summaryrefslogtreecommitdiffstats
path: root/media
diff options
context:
space:
mode:
authorhenrika@chromium.org <henrika@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2012-09-14 18:53:56 +0000
committerhenrika@chromium.org <henrika@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2012-09-14 18:53:56 +0000
commitf1d491ef6f199a80f1e3396060196cac5496fd8f (patch)
treef17bd443be814eadf926931840e099bea49ac318 /media
parentf8c37dfad2a6c55c6c4c48af20e5b41e7280906c (diff)
downloadchromium_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.cc111
-rw-r--r--media/audio/win/audio_low_latency_output_win.h8
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