diff options
author | henrika@chromium.org <henrika@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-09-14 18:53:56 +0000 |
---|---|---|
committer | henrika@chromium.org <henrika@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-09-14 18:53:56 +0000 |
commit | f1d491ef6f199a80f1e3396060196cac5496fd8f (patch) | |
tree | f17bd443be814eadf926931840e099bea49ac318 /media | |
parent | f8c37dfad2a6c55c6c4c48af20e5b41e7280906c (diff) | |
download | chromium_src-f1d491ef6f199a80f1e3396060196cac5496fd8f.zip chromium_src-f1d491ef6f199a80f1e3396060196cac5496fd8f.tar.gz chromium_src-f1d491ef6f199a80f1e3396060196cac5496fd8f.tar.bz2 |
Adds support for 2->1 channel down mixing for WASAPI on Windows.
BUG=none
TBR=scherkus
TEST=--v=1 --gtest_also_run_disabled_tests --gtest_filter=WASAPIAudioOutputStreamTest*ReadFromStereo* using an audio-device setting with 1 output channel
Review URL: https://chromiumcodereview.appspot.com/10911309
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@156851 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'media')
-rw-r--r-- | media/audio/win/audio_low_latency_output_win.cc | 111 | ||||
-rw-r--r-- | media/audio/win/audio_low_latency_output_win.h | 8 |
2 files changed, 89 insertions, 30 deletions
diff --git a/media/audio/win/audio_low_latency_output_win.cc b/media/audio/win/audio_low_latency_output_win.cc index 4bf743b..75cf93a 100644 --- a/media/audio/win/audio_low_latency_output_win.cc +++ b/media/audio/win/audio_low_latency_output_win.cc @@ -213,6 +213,18 @@ static ChannelLayout ChannelConfigToChannelLayout(ChannelConfig config) { } } +// Record UMA statistics when a low latency Open() call fails. +// TODO(dalecurtis): This should be done by AudioOutputResampler() once it +// supports channel remixing. http://crbug.com/138762 +static void RecordFallbackStats() { + UMA_HISTOGRAM_ENUMERATION( + "Media.FallbackHardwareAudioChannelLayout", + WASAPIAudioOutputStream::HardwareChannelLayout(), CHANNEL_LAYOUT_MAX); + UMA_HISTOGRAM_ENUMERATION( + "Media.FallbackHardwareAudioChannelCount", + WASAPIAudioOutputStream::HardwareChannelCount(), limits::kMaxChannels); +} + // mono/stereo -> N.1 up-mixing where N=out_channels-1. // See http://www.w3.org/TR/webaudio/#UpMix-sub for details. // TODO(henrika): try to reduce the size of this function. @@ -317,16 +329,50 @@ static int ChannelUpMix(void* input, return 0; } -// Record UMA statistics when a low latency Open() call fails. -// TODO(dalecurtis): This should be done by AudioOutputResampler() once it -// supports channel remixing. http://crbug.com/138762 -static void RecordFallbackStats() { - UMA_HISTOGRAM_ENUMERATION( - "Media.FallbackHardwareAudioChannelLayout", - WASAPIAudioOutputStream::HardwareChannelLayout(), CHANNEL_LAYOUT_MAX); - UMA_HISTOGRAM_ENUMERATION( - "Media.FallbackHardwareAudioChannelCount", - WASAPIAudioOutputStream::HardwareChannelCount(), limits::kMaxChannels); +// 2->1 downmixing. +static int ChannelDownMix(const void* input, + void* output, + int in_channels, + int out_channels, + size_t number_of_input_bytes, + int bytes_per_sample) { + DCHECK(input); + DCHECK(output); + DCHECK_GT(in_channels, out_channels); + DCHECK_EQ(bytes_per_sample, 2); + + if (bytes_per_sample != 2) { + LOG(ERROR) << "Only 16-bit samples are supported."; + return 0; + } + + // 2 -> 1 + if (in_channels == 2 && out_channels == 1) { + const LayoutStereo_16bit* in = + reinterpret_cast<const LayoutStereo_16bit*>(input); + LayoutMono_16bit* out = reinterpret_cast<LayoutMono_16bit*>(output); + size_t number_of_input_stereo_samples = (number_of_input_bytes / 4); + + DCHECK_EQ(0u, number_of_input_stereo_samples % 4); + for (size_t i = 0; i < number_of_input_stereo_samples; ++i) { + int32 sum = + (static_cast<int32>(in->left) + static_cast<int32>(in->right)) / 2; + if (sum > 32767) + sum = 32767; + else if (sum < -32768) + sum = -32768; + out->center = static_cast<int16>(sum); + in++; + out++; + } + + return ((out_channels / static_cast<double> (in_channels)) * + number_of_input_bytes); + } + + LOG(ERROR) << "Down-mixing " << out_channels << "->" + << in_channels << " is not supported."; + return 0; } // static @@ -407,20 +453,24 @@ WASAPIAudioOutputStream::WASAPIAudioOutputStream(AudioManagerWin* manager, // the audio stream is opened up in 7.1 surround mode but the source only // provides a stereo signal as input, i.e., a stereo up-mix (2 -> 7.1) will // take place before sending the stream to the audio driver. + // We also support down mixing for the 2->1 case. + // TODO(henrika): extend down-mixing support. DVLOG(1) << "Channel mixing " << client_channel_count_ << "->" << endpoint_channel_count() << " is requested."; - LOG_IF(ERROR, channel_factor() < 1) + LOG_IF(ERROR, channel_factor() < 1 && channel_factor() != 0.5f) << "Channel mixing " << client_channel_count_ << "->" << endpoint_channel_count() << " is not supported."; // Store size (in different units) of audio packets which we expect to // get from the audio endpoint device in each render event. - packet_size_frames_ = - (channel_factor() * params.GetBytesPerBuffer()) / format->nBlockAlign; - packet_size_bytes_ = channel_factor() * params.GetBytesPerBuffer(); + packet_size_frames_ =(channel_factor() * params.GetBytesPerBuffer() + 0.5) / + format->nBlockAlign; + packet_size_bytes_ = channel_factor() * params.GetBytesPerBuffer() + 0.5; packet_size_ms_ = (1000.0 * packet_size_frames_) / params.sample_rate(); + DVLOG(1) << "channel ratio (in/out) : " << channel_factor(); DVLOG(1) << "Number of bytes per audio frame : " << frame_size_; DVLOG(1) << "Number of audio frames per packet: " << packet_size_frames_; + DVLOG(1) << "Number of bytes per packet : " << packet_size_bytes_; DVLOG(1) << "Number of milliseconds per packet: " << packet_size_ms_; // All events are auto-reset events and non-signaled initially. @@ -450,7 +500,7 @@ bool WASAPIAudioOutputStream::Open() { // by the audio source must be less than or equal to the number of native // channels (given by endpoint_channel_count()) which is the channel count // used when opening the default endpoint device. - if (channel_factor() < 1) { + if (channel_factor() < 1 && channel_factor() != 0.5f) { LOG(ERROR) << "Channel down-mixing is not supported"; RecordFallbackStats(); return false; @@ -851,7 +901,7 @@ void WASAPIAudioOutputStream::Run() { uint32 num_filled_bytes = 0; const int bytes_per_sample = format_.Format.wBitsPerSample >> 3; - if (channel_factor() == 1) { + if (channel_factor() == 1.0f) { // Case I: no up-mixing. int frames_filled = source_->OnMoreData( audio_bus_.get(), AudioBuffersState(0, audio_delay_bytes)); @@ -863,9 +913,9 @@ void WASAPIAudioOutputStream::Run() { audio_bus_->ToInterleaved( frames_filled, bytes_per_sample, audio_data); } else { - // Case II: up-mixing. + // Case II: up-mixing or down-mix 2->1 const int audio_source_size_bytes = - packet_size_bytes_ / channel_factor(); + (packet_size_bytes_ / channel_factor()) + 0.5; scoped_array<uint8> buffer; buffer.reset(new uint8[audio_source_size_bytes]); @@ -881,13 +931,24 @@ void WASAPIAudioOutputStream::Run() { audio_bus_->ToInterleaved( frames_filled, bytes_per_sample, buffer.get()); - // Do channel up-mixing on 16-bit PCM samples. - num_filled_bytes = ChannelUpMix(buffer.get(), - &audio_data[0], - client_channel_count_, - endpoint_channel_count(), - num_filled_bytes, - bytes_per_sample); + if (channel_factor() > 1.0f) { + // Do channel up-mixing on 16-bit PCM samples. + num_filled_bytes = ChannelUpMix(buffer.get(), + &audio_data[0], + client_channel_count_, + endpoint_channel_count(), + num_filled_bytes, + bytes_per_sample); + } else if (channel_factor() == 0.5f) { + // TODO(henrika): this can be done in the float domain before + // AudioBus::ToInterleaved() to avoid saturation logic. + num_filled_bytes = ChannelDownMix(buffer.get(), + &audio_data[0], + client_channel_count_, + endpoint_channel_count(), + num_filled_bytes, + bytes_per_sample); + } } // Perform in-place, software-volume adjustments. diff --git a/media/audio/win/audio_low_latency_output_win.h b/media/audio/win/audio_low_latency_output_win.h index 053be13..19a5c19 100644 --- a/media/audio/win/audio_low_latency_output_win.h +++ b/media/audio/win/audio_low_latency_output_win.h @@ -290,11 +290,9 @@ class MEDIA_EXPORT WASAPIAudioOutputStream // The ratio between the the number of native audio channels used by the // audio device and the number of audio channels from the client. - // TODO(henrika): using int as indicator of the required type of channel - // mixing is not a perfect solution. E.g. 2->2.1 will result in a ratio of - // 2/3 which is truncated to 1 and 1 means "no mixing is required". - int channel_factor() const { - return (format_.Format.nChannels / client_channel_count_); + double channel_factor() const { + return (format_.Format.nChannels / static_cast<double> ( + client_channel_count_)); } // Initializes the COM library for use by the calling thread and sets the |