summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--content/browser/renderer_host/media/audio_input_renderer_host.cc3
-rw-r--r--content/browser/renderer_host/render_message_filter.cc17
-rw-r--r--content/browser/renderer_host/render_message_filter.h6
-rw-r--r--content/common/DEPS1
-rw-r--r--content/common/media/media_param_traits.cc4
-rw-r--r--content/common/media/media_param_traits.h5
-rw-r--r--content/common/view_messages.h11
-rw-r--r--content/renderer/media/audio_message_filter.cc17
-rw-r--r--content/renderer/media/audio_renderer_mixer_manager_unittest.cc13
-rw-r--r--content/renderer/media/webrtc_audio_capturer.cc6
-rw-r--r--content/renderer/media/webrtc_audio_device_unittest.cc25
-rw-r--r--content/renderer/media/webrtc_audio_renderer.cc6
-rw-r--r--content/renderer/pepper/pepper_platform_audio_input_impl.cc2
-rw-r--r--content/renderer/render_thread_impl.cc13
-rw-r--r--content/renderer/renderer_webkitplatformsupport_impl.cc5
-rw-r--r--content/renderer/renderer_webkitplatformsupport_impl.h1
-rw-r--r--content/test/DEPS1
-rw-r--r--content/test/webrtc_audio_device_test.cc16
-rw-r--r--content/test/webrtc_audio_device_test.h5
-rw-r--r--media/audio/audio_output_device_unittest.cc2
-rw-r--r--media/audio/audio_output_resampler.cc2
-rw-r--r--media/audio/audio_parameters.cc13
-rw-r--r--media/audio/audio_parameters.h5
-rw-r--r--media/audio/mac/audio_manager_mac.cc124
-rw-r--r--media/audio/mac/audio_manager_mac.h10
-rw-r--r--media/base/audio_converter.cc3
-rw-r--r--media/base/audio_hardware_config.cc79
-rw-r--r--media/base/audio_hardware_config.h33
-rw-r--r--media/base/audio_hardware_config_unittest.cc56
-rw-r--r--media/base/channel_layout.cc29
-rw-r--r--media/base/channel_layout.h7
-rw-r--r--media/base/channel_mixer.cc70
-rw-r--r--media/base/channel_mixer.h7
-rw-r--r--media/base/channel_mixer_unittest.cc5
-rw-r--r--media/ffmpeg/ffmpeg_common.cc26
35 files changed, 462 insertions, 166 deletions
diff --git a/content/browser/renderer_host/media/audio_input_renderer_host.cc b/content/browser/renderer_host/media/audio_input_renderer_host.cc
index 18b7e70..ea05dc5 100644
--- a/content/browser/renderer_host/media/audio_input_renderer_host.cc
+++ b/content/browser/renderer_host/media/audio_input_renderer_host.cc
@@ -232,7 +232,8 @@ void AudioInputRendererHost::OnCreateStream(
if (media_stream_manager_->audio_input_device_manager()->
ShouldUseFakeDevice()) {
audio_params.Reset(media::AudioParameters::AUDIO_FAKE,
- params.channel_layout(), 0, params.sample_rate(),
+ params.channel_layout(), params.channels(), 0,
+ params.sample_rate(),
params.bits_per_sample(), params.frames_per_buffer());
}
diff --git a/content/browser/renderer_host/render_message_filter.cc b/content/browser/renderer_host/render_message_filter.cc
index 608c7ed..fc216a1 100644
--- a/content/browser/renderer_host/render_message_filter.cc
+++ b/content/browser/renderer_host/render_message_filter.cc
@@ -33,6 +33,7 @@
#include "content/common/child_process_host_impl.h"
#include "content/common/child_process_messages.h"
#include "content/common/desktop_notification_messages.h"
+#include "content/common/media/media_param_traits.h"
#include "content/common/view_messages.h"
#include "content/public/browser/browser_context.h"
#include "content/public/browser/browser_thread.h"
@@ -778,22 +779,18 @@ void RenderMessageFilter::OnGetCPUUsage(int* cpu_usage) {
*cpu_usage = cpu_usage_;
}
-// TODO(xians): refactor the API to return input and output AudioParameters.
void RenderMessageFilter::OnGetAudioHardwareConfig(
- int* output_buffer_size, int* output_sample_rate, int* input_sample_rate,
- media::ChannelLayout* input_channel_layout) {
+ media::AudioParameters* input_params,
+ media::AudioParameters* output_params) {
+ DCHECK(input_params);
+ DCHECK(output_params);
media::AudioManager* audio_manager = BrowserMainLoop::GetAudioManager();
- const media::AudioParameters output_parameters =
- audio_manager->GetDefaultOutputStreamParameters();
- *output_buffer_size = output_parameters.frames_per_buffer();
- *output_sample_rate = output_parameters.sample_rate();
+ *output_params = audio_manager->GetDefaultOutputStreamParameters();
// TODO(henrika): add support for all available input devices.
- const media::AudioParameters input_parameters =
+ *input_params =
audio_manager->GetInputStreamParameters(
media::AudioManagerBase::kDefaultDeviceId);
- *input_sample_rate = input_parameters.sample_rate();
- *input_channel_layout = input_parameters.channel_layout();
}
void RenderMessageFilter::OnGetMonitorColorProfile(std::vector<char>* profile) {
diff --git a/content/browser/renderer_host/render_message_filter.h b/content/browser/renderer_host/render_message_filter.h
index 6f19c33..689b3f6 100644
--- a/content/browser/renderer_host/render_message_filter.h
+++ b/content/browser/renderer_host/render_message_filter.h
@@ -22,6 +22,7 @@
#include "content/common/pepper_renderer_instance_data.h"
#include "content/public/browser/browser_message_filter.h"
#include "content/public/common/three_d_api_types.h"
+#include "media/audio/audio_parameters.h"
#include "media/base/channel_layout.h"
#include "net/cookies/canonical_cookie.h"
#include "third_party/WebKit/Source/WebKit/chromium/public/WebPopupType.h"
@@ -190,9 +191,8 @@ class RenderMessageFilter : public BrowserMessageFilter {
void OnGetCPUUsage(int* cpu_usage);
- void OnGetAudioHardwareConfig(int* output_buffer_size,
- int* output_sample_rate, int* input_sample_rate,
- media::ChannelLayout* input_channel_layout);
+ void OnGetAudioHardwareConfig(media::AudioParameters* input_params,
+ media::AudioParameters* output_params);
// Used to look up the monitor color profile.
void OnGetMonitorColorProfile(std::vector<char>* profile);
diff --git a/content/common/DEPS b/content/common/DEPS
index bd4bed3..e09f27a 100644
--- a/content/common/DEPS
+++ b/content/common/DEPS
@@ -1,6 +1,7 @@
include_rules = [
"+cc",
"+components/tracing",
+ "+media/audio",
"+media/base",
"+sandbox/linux/seccomp-legacy",
]
diff --git a/content/common/media/media_param_traits.cc b/content/common/media/media_param_traits.cc
index 31ba948..f833ea0 100644
--- a/content/common/media/media_param_traits.cc
+++ b/content/common/media/media_param_traits.cc
@@ -42,8 +42,8 @@ bool ParamTraits<AudioParameters>::Read(const Message* m,
!m->ReadInt(iter, &input_channels))
return false;
r->Reset(static_cast<AudioParameters::Format>(format),
- static_cast<ChannelLayout>(channel_layout), input_channels,
- sample_rate, bits_per_sample, frames_per_buffer);
+ static_cast<ChannelLayout>(channel_layout), channels,
+ input_channels, sample_rate, bits_per_sample, frames_per_buffer);
if (!r->IsValid())
return false;
return true;
diff --git a/content/common/media/media_param_traits.h b/content/common/media/media_param_traits.h
index 94ce9ca..90d7258 100644
--- a/content/common/media/media_param_traits.h
+++ b/content/common/media/media_param_traits.h
@@ -5,6 +5,7 @@
#ifndef CONTENT_COMMON_MEDIA_MEDIA_PARAM_TRAITS_H_
#define CONTENT_COMMON_MEDIA_MEDIA_PARAM_TRAITS_H_
+#include "content/common/content_export.h"
#include "ipc/ipc_message.h"
#include "ipc/ipc_param_traits.h"
@@ -16,7 +17,7 @@ struct VideoCaptureParams;
namespace IPC {
template <>
-struct ParamTraits<media::AudioParameters> {
+struct CONTENT_EXPORT ParamTraits<media::AudioParameters> {
typedef media::AudioParameters param_type;
static void Write(Message* m, const param_type& p);
static bool Read(const Message* m, PickleIterator* iter, param_type* r);
@@ -24,7 +25,7 @@ struct ParamTraits<media::AudioParameters> {
};
template <>
-struct ParamTraits<media::VideoCaptureParams> {
+struct CONTENT_EXPORT ParamTraits<media::VideoCaptureParams> {
typedef media::VideoCaptureParams param_type;
static void Write(Message* m, const param_type& p);
static bool Read(const Message* m, PickleIterator* iter, param_type* r);
diff --git a/content/common/view_messages.h b/content/common/view_messages.h
index c10f4aa..c186f21 100644
--- a/content/common/view_messages.h
+++ b/content/common/view_messages.h
@@ -31,6 +31,7 @@
#include "ipc/ipc_channel_handle.h"
#include "ipc/ipc_message_macros.h"
#include "ipc/ipc_platform_file.h"
+#include "media/audio/audio_parameters.h"
#include "media/base/channel_layout.h"
#include "media/base/media_log_event.h"
#include "third_party/skia/include/core/SkBitmap.h"
@@ -1417,12 +1418,10 @@ IPC_SYNC_MESSAGE_CONTROL1_2(ViewHostMsg_CreateFullscreenWidget,
IPC_SYNC_MESSAGE_CONTROL0_1(ViewHostMsg_GenerateRoutingID,
int /* routing_id */)
-// Asks the browser for the default audio hardware buffer-size.
-IPC_SYNC_MESSAGE_CONTROL0_4(ViewHostMsg_GetAudioHardwareConfig,
- int /* output_buffer_size */,
- int /* output_sample_rate */,
- int /* input_sample_rate */,
- media::ChannelLayout /* input_channel_layout */)
+// Asks the browser for the default audio hardware configuration.
+IPC_SYNC_MESSAGE_CONTROL0_2(ViewHostMsg_GetAudioHardwareConfig,
+ media::AudioParameters /* input parameters */,
+ media::AudioParameters /* output parameters */)
// Asks the browser for CPU usage of the renderer process in percents.
IPC_SYNC_MESSAGE_CONTROL0_1(ViewHostMsg_GetCPUUsage,
diff --git a/content/renderer/media/audio_message_filter.cc b/content/renderer/media/audio_message_filter.cc
index 377c770..11de086 100644
--- a/content/renderer/media/audio_message_filter.cc
+++ b/content/renderer/media/audio_message_filter.cc
@@ -172,7 +172,22 @@ void AudioMessageFilter::OnOutputDeviceChanged(int stream_id,
if (!audio_hardware_config_)
return;
- audio_hardware_config_->UpdateOutputConfig(new_buffer_size, new_sample_rate);
+ // TODO(crogers): fix OnOutputDeviceChanged() to pass AudioParameters.
+ media::ChannelLayout channel_layout =
+ audio_hardware_config_->GetOutputChannelLayout();
+ int channels = audio_hardware_config_->GetOutputChannels();
+
+ media::AudioParameters output_params;
+ output_params.Reset(
+ media::AudioParameters::AUDIO_PCM_LOW_LATENCY,
+ channel_layout,
+ channels,
+ 0,
+ new_sample_rate,
+ 16,
+ new_buffer_size);
+
+ audio_hardware_config_->UpdateOutputConfig(output_params);
}
void AudioMessageFilter::SetAudioHardwareConfig(
diff --git a/content/renderer/media/audio_renderer_mixer_manager_unittest.cc b/content/renderer/media/audio_renderer_mixer_manager_unittest.cc
index 0d00942..900162f 100644
--- a/content/renderer/media/audio_renderer_mixer_manager_unittest.cc
+++ b/content/renderer/media/audio_renderer_mixer_manager_unittest.cc
@@ -6,6 +6,7 @@
#include "base/memory/ref_counted.h"
#include "base/memory/scoped_ptr.h"
#include "content/renderer/media/audio_renderer_mixer_manager.h"
+#include "media/audio/audio_parameters.h"
#include "media/base/audio_hardware_config.h"
#include "media/base/audio_renderer_mixer.h"
#include "media/base/audio_renderer_mixer_input.h"
@@ -24,10 +25,20 @@ static const media::ChannelLayout kChannelLayout = media::CHANNEL_LAYOUT_STEREO;
static const int kRenderViewId = 123;
static const int kAnotherRenderViewId = 456;
+using media::AudioParameters;
+
class AudioRendererMixerManagerTest : public testing::Test {
public:
AudioRendererMixerManagerTest()
- : fake_config_(kBufferSize, kSampleRate, 0, media::CHANNEL_LAYOUT_NONE) {
+ : fake_config_(AudioParameters(), AudioParameters()) {
+ AudioParameters output_params(
+ media::AudioParameters::AUDIO_PCM_LOW_LATENCY,
+ media::CHANNEL_LAYOUT_STEREO,
+ kSampleRate,
+ 16,
+ kBufferSize);
+ fake_config_.UpdateOutputConfig(output_params);
+
manager_.reset(new AudioRendererMixerManager(&fake_config_));
// We don't want to deal with instantiating a real AudioOutputDevice since
diff --git a/content/renderer/media/webrtc_audio_capturer.cc b/content/renderer/media/webrtc_audio_capturer.cc
index 1217458..b1eebba 100644
--- a/content/renderer/media/webrtc_audio_capturer.cc
+++ b/content/renderer/media/webrtc_audio_capturer.cc
@@ -85,9 +85,9 @@ class WebRtcAudioCapturer::ConfiguredBuffer :
// bits_per_sample is always 16 for now.
int bits_per_sample = 16;
-
- params_.Reset(format, channel_layout, 0, sample_rate, bits_per_sample,
- buffer_size);
+ int channels = ChannelLayoutToChannelCount(channel_layout);
+ params_.Reset(format, channel_layout, channels, 0,
+ sample_rate, bits_per_sample, buffer_size);
buffer_.reset(new int16[params_.frames_per_buffer() * params_.channels()]);
return true;
diff --git a/content/renderer/media/webrtc_audio_device_unittest.cc b/content/renderer/media/webrtc_audio_device_unittest.cc
index e04eafc..e039ae4 100644
--- a/content/renderer/media/webrtc_audio_device_unittest.cc
+++ b/content/renderer/media/webrtc_audio_device_unittest.cc
@@ -18,6 +18,7 @@
#include "third_party/webrtc/voice_engine/include/voe_file.h"
#include "third_party/webrtc/voice_engine/include/voe_network.h"
+using media::AudioParameters;
using testing::_;
using testing::AnyNumber;
using testing::InvokeWithoutArgs;
@@ -32,14 +33,13 @@ const int kRenderViewId = 1;
scoped_ptr<media::AudioHardwareConfig> CreateRealHardwareConfig(
media::AudioManager* manager) {
- const media::AudioParameters output_parameters =
+ const AudioParameters output_parameters =
manager->GetDefaultOutputStreamParameters();
- const media::AudioParameters input_parameters =
+ const AudioParameters input_parameters =
manager->GetInputStreamParameters(
media::AudioManagerBase::kDefaultDeviceId);
return make_scoped_ptr(new media::AudioHardwareConfig(
- output_parameters.frames_per_buffer(), output_parameters.sample_rate(),
- input_parameters.sample_rate(), input_parameters.channel_layout()));
+ input_parameters, output_parameters));
}
// Return true if at least one element in the array matches |value|.
@@ -218,8 +218,21 @@ TEST_F(WebRTCAudioDeviceTest, TestValidOutputRates) {
// Basic test that instantiates and initializes an instance of
// WebRtcAudioDeviceImpl.
TEST_F(WebRTCAudioDeviceTest, Construct) {
- media::AudioHardwareConfig audio_config(
- 480, 48000, 48000, media::CHANNEL_LAYOUT_MONO);
+ AudioParameters input_params(
+ AudioParameters::AUDIO_PCM_LOW_LATENCY,
+ media::CHANNEL_LAYOUT_MONO,
+ 48000,
+ 16,
+ 480);
+
+ AudioParameters output_params(
+ AudioParameters::AUDIO_PCM_LOW_LATENCY,
+ media::CHANNEL_LAYOUT_STEREO,
+ 48000,
+ 16,
+ 480);
+
+ media::AudioHardwareConfig audio_config(input_params, output_params);
SetAudioHardwareConfig(&audio_config);
scoped_refptr<WebRtcAudioDeviceImpl> webrtc_audio_device(
diff --git a/content/renderer/media/webrtc_audio_renderer.cc b/content/renderer/media/webrtc_audio_renderer.cc
index b668f80..c30f265 100644
--- a/content/renderer/media/webrtc_audio_renderer.cc
+++ b/content/renderer/media/webrtc_audio_renderer.cc
@@ -158,8 +158,10 @@ bool WebRtcAudioRenderer::Initialize(WebRtcAudioRendererSource* source) {
return false;
}
+ int channels = ChannelLayoutToChannelCount(channel_layout);
source_params.Reset(media::AudioParameters::AUDIO_PCM_LOW_LATENCY,
- channel_layout, 0, sample_rate, 16, buffer_size);
+ channel_layout, channels, 0,
+ sample_rate, 16, buffer_size);
// Set up audio parameters for the sink, i.e., the native audio output stream.
// We strive to open up using native parameters to achieve best possible
@@ -171,7 +173,7 @@ bool WebRtcAudioRenderer::Initialize(WebRtcAudioRendererSource* source) {
buffer_size = hardware_config->GetOutputBufferSize();
sink_params.Reset(media::AudioParameters::AUDIO_PCM_LOW_LATENCY,
- channel_layout, 0, sample_rate, 16, buffer_size);
+ channel_layout, channels, 0, sample_rate, 16, buffer_size);
// Create a FIFO if re-buffering is required to match the source input with
// the sink request. The source acts as provider here and the sink as
diff --git a/content/renderer/pepper/pepper_platform_audio_input_impl.cc b/content/renderer/pepper/pepper_platform_audio_input_impl.cc
index 6351768..4534f33 100644
--- a/content/renderer/pepper/pepper_platform_audio_input_impl.cc
+++ b/content/renderer/pepper/pepper_platform_audio_input_impl.cc
@@ -165,7 +165,7 @@ bool PepperPlatformAudioInputImpl::Initialize(
client_ = client;
params_.Reset(media::AudioParameters::AUDIO_PCM_LINEAR,
- media::CHANNEL_LAYOUT_MONO, 0,
+ media::CHANNEL_LAYOUT_MONO, 1, 0,
sample_rate, 16, frames_per_buffer);
if (device_id.empty()) {
diff --git a/content/renderer/render_thread_impl.cc b/content/renderer/render_thread_impl.cc
index 58cd3f7..8879aa0 100644
--- a/content/renderer/render_thread_impl.cc
+++ b/content/renderer/render_thread_impl.cc
@@ -980,18 +980,13 @@ AudioRendererMixerManager* RenderThreadImpl::GetAudioRendererMixerManager() {
media::AudioHardwareConfig* RenderThreadImpl::GetAudioHardwareConfig() {
if (!audio_hardware_config_) {
- int output_buffer_size;
- int output_sample_rate;
- int input_sample_rate;
- media::ChannelLayout input_channel_layout;
-
+ media::AudioParameters input_params;
+ media::AudioParameters output_params;
Send(new ViewHostMsg_GetAudioHardwareConfig(
- &output_buffer_size, &output_sample_rate,
- &input_sample_rate, &input_channel_layout));
+ &input_params, &output_params));
audio_hardware_config_.reset(new media::AudioHardwareConfig(
- output_buffer_size, output_sample_rate, input_sample_rate,
- input_channel_layout));
+ input_params, output_params));
audio_message_filter_->SetAudioHardwareConfig(audio_hardware_config_.get());
}
diff --git a/content/renderer/renderer_webkitplatformsupport_impl.cc b/content/renderer/renderer_webkitplatformsupport_impl.cc
index 1368005..addb397 100644
--- a/content/renderer/renderer_webkitplatformsupport_impl.cc
+++ b/content/renderer/renderer_webkitplatformsupport_impl.cc
@@ -633,6 +633,11 @@ size_t RendererWebKitPlatformSupportImpl::audioHardwareBufferSize() {
return thread->GetAudioHardwareConfig()->GetOutputBufferSize();
}
+unsigned RendererWebKitPlatformSupportImpl::audioHardwareOutputChannels() {
+ RenderThreadImpl* thread = RenderThreadImpl::current();
+ return thread->GetAudioHardwareConfig()->GetOutputChannels();
+}
+
// TODO(crogers): remove deprecated API as soon as WebKit calls new API.
WebAudioDevice*
RendererWebKitPlatformSupportImpl::createAudioDevice(
diff --git a/content/renderer/renderer_webkitplatformsupport_impl.h b/content/renderer/renderer_webkitplatformsupport_impl.h
index 10210e9..03d2df7 100644
--- a/content/renderer/renderer_webkitplatformsupport_impl.h
+++ b/content/renderer/renderer_webkitplatformsupport_impl.h
@@ -79,6 +79,7 @@ class CONTENT_EXPORT RendererWebKitPlatformSupportImpl
virtual bool isThreadedCompositingEnabled();
virtual double audioHardwareSampleRate();
virtual size_t audioHardwareBufferSize();
+ virtual unsigned audioHardwareOutputChannels();
// TODO(crogers): remove deprecated API as soon as WebKit calls new API.
virtual WebKit::WebAudioDevice* createAudioDevice(
diff --git a/content/test/DEPS b/content/test/DEPS
index ebd2714..95f1d48 100644
--- a/content/test/DEPS
+++ b/content/test/DEPS
@@ -1,6 +1,7 @@
include_rules = [
# Testing utilities can access anything in content/
"+content",
+ "+media/audio", # For AudioParameters in WebRTC tests.
"+media/base", # For ChannelLayout in WebRTC tests.
"+ui/aura/test/test_aura_initializer.h",
"+ui/base/resource/data_pack.h",
diff --git a/content/test/webrtc_audio_device_test.cc b/content/test/webrtc_audio_device_test.cc
index e9a3c48..562c308 100644
--- a/content/test/webrtc_audio_device_test.cc
+++ b/content/test/webrtc_audio_device_test.cc
@@ -16,6 +16,7 @@
#include "content/browser/renderer_host/media/audio_renderer_host.h"
#include "content/browser/renderer_host/media/media_stream_manager.h"
#include "content/browser/renderer_host/media/mock_media_observer.h"
+#include "content/common/media/media_param_traits.h"
#include "content/common/view_messages.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/common/content_paths.h"
@@ -27,6 +28,7 @@
#include "content/renderer/render_process.h"
#include "content/renderer/render_thread_impl.h"
#include "content/renderer/renderer_webkitplatformsupport_impl.h"
+#include "media/audio/audio_parameters.h"
#include "media/base/audio_hardware_config.h"
#include "net/url_request/url_request_test_util.h"
#include "testing/gmock/include/gmock/gmock.h"
@@ -40,6 +42,8 @@
#include "base/win/scoped_com_initializer.h"
#endif
+using media::AudioParameters;
+using media::ChannelLayout;
using testing::_;
using testing::InvokeWithoutArgs;
using testing::Return;
@@ -262,16 +266,10 @@ void WebRTCAudioDeviceTest::DestroyChannel() {
}
void WebRTCAudioDeviceTest::OnGetAudioHardwareConfig(
- int* output_buffer_size, int* output_sample_rate, int* input_sample_rate,
- media::ChannelLayout* input_channel_layout) {
+ AudioParameters* input_params, AudioParameters* output_params) {
ASSERT_TRUE(audio_hardware_config_);
-
- *output_buffer_size = audio_hardware_config_->GetOutputBufferSize();
- *output_sample_rate = audio_hardware_config_->GetOutputSampleRate();
-
- // TODO(henrika): add support for all available input devices.
- *input_sample_rate = audio_hardware_config_->GetInputSampleRate();
- *input_channel_layout = audio_hardware_config_->GetInputChannelLayout();
+ *input_params = audio_hardware_config_->GetInputConfig();
+ *output_params = audio_hardware_config_->GetOutputConfig();
}
// IPC::Listener implementation.
diff --git a/content/test/webrtc_audio_device_test.h b/content/test/webrtc_audio_device_test.h
index 71327b6..ed9760d 100644
--- a/content/test/webrtc_audio_device_test.h
+++ b/content/test/webrtc_audio_device_test.h
@@ -132,9 +132,8 @@ class WebRTCAudioDeviceTest : public ::testing::Test, public IPC::Listener {
void CreateChannel(const char* name);
void DestroyChannel();
- void OnGetAudioHardwareConfig(int* output_buffer_size,
- int* output_sample_rate, int* input_sample_rate,
- media::ChannelLayout* input_channel_layout);
+ void OnGetAudioHardwareConfig(media::AudioParameters* input_params,
+ media::AudioParameters* output_params);
// IPC::Listener implementation.
virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE;
diff --git a/media/audio/audio_output_device_unittest.cc b/media/audio/audio_output_device_unittest.cc
index 5628f66..5668687 100644
--- a/media/audio/audio_output_device_unittest.cc
+++ b/media/audio/audio_output_device_unittest.cc
@@ -152,7 +152,7 @@ AudioOutputDeviceTest::AudioOutputDeviceTest()
input_channels_(synchronized_io_ ? 2 : 0) {
default_audio_parameters_.Reset(
AudioParameters::AUDIO_PCM_LINEAR,
- CHANNEL_LAYOUT_STEREO, input_channels_,
+ CHANNEL_LAYOUT_STEREO, 2, input_channels_,
48000, 16, 1024);
audio_device_ = new AudioOutputDevice(
diff --git a/media/audio/audio_output_resampler.cc b/media/audio/audio_output_resampler.cc
index 9993096..089c083 100644
--- a/media/audio/audio_output_resampler.cc
+++ b/media/audio/audio_output_resampler.cc
@@ -221,7 +221,7 @@ bool AudioOutputResampler::OpenStream() {
// Finally fall back to a fake audio output device.
output_params_.Reset(
AudioParameters::AUDIO_FAKE, params_.channel_layout(),
- params_.input_channels(), params_.sample_rate(),
+ params_.channels(), params_.input_channels(), params_.sample_rate(),
params_.bits_per_sample(), params_.frames_per_buffer());
Initialize();
if (dispatcher_->OpenStream()) {
diff --git a/media/audio/audio_parameters.cc b/media/audio/audio_parameters.cc
index 721dea0a..5e77c60 100644
--- a/media/audio/audio_parameters.cc
+++ b/media/audio/audio_parameters.cc
@@ -4,6 +4,7 @@
#include "media/audio/audio_parameters.h"
+#include "base/logging.h"
#include "media/base/limits.h"
namespace media {
@@ -44,16 +45,19 @@ AudioParameters::AudioParameters(Format format, ChannelLayout channel_layout,
}
void AudioParameters::Reset(Format format, ChannelLayout channel_layout,
- int input_channels,
+ int channels, int input_channels,
int sample_rate, int bits_per_sample,
int frames_per_buffer) {
+ if (channel_layout != CHANNEL_LAYOUT_DISCRETE)
+ DCHECK_EQ(channels, ChannelLayoutToChannelCount(channel_layout));
+
format_ = format;
channel_layout_ = channel_layout;
+ channels_ = channels;
input_channels_ = input_channels;
sample_rate_ = sample_rate;
bits_per_sample_ = bits_per_sample;
frames_per_buffer_ = frames_per_buffer;
- channels_ = ChannelLayoutToChannelCount(channel_layout);
}
bool AudioParameters::IsValid() const {
@@ -85,4 +89,9 @@ int AudioParameters::GetBytesPerFrame() const {
return channels_ * bits_per_sample_ / 8;
}
+void AudioParameters::SetDiscreteChannels(int channels) {
+ channel_layout_ = CHANNEL_LAYOUT_DISCRETE;
+ channels_ = channels;
+}
+
} // namespace media
diff --git a/media/audio/audio_parameters.h b/media/audio/audio_parameters.h
index 498fe2e..dcc9eae 100644
--- a/media/audio/audio_parameters.h
+++ b/media/audio/audio_parameters.h
@@ -51,7 +51,7 @@ class MEDIA_EXPORT AudioParameters {
int sample_rate, int bits_per_sample,
int frames_per_buffer);
void Reset(Format format, ChannelLayout channel_layout,
- int input_channels,
+ int channels, int input_channels,
int sample_rate, int bits_per_sample,
int frames_per_buffer);
@@ -76,6 +76,9 @@ class MEDIA_EXPORT AudioParameters {
int channels() const { return channels_; }
int input_channels() const { return input_channels_; }
+ // Set to CHANNEL_LAYOUT_DISCRETE with given number of channels.
+ void SetDiscreteChannels(int channels);
+
private:
Format format_; // Format of the stream.
ChannelLayout channel_layout_; // Order of surround sound channels.
diff --git a/media/audio/mac/audio_manager_mac.cc b/media/audio/mac/audio_manager_mac.cc
index 2184e12..ec6a79a 100644
--- a/media/audio/mac/audio_manager_mac.cc
+++ b/media/audio/mac/audio_manager_mac.cc
@@ -264,6 +264,97 @@ bool AudioManagerMac::HasAudioInputDevices() {
return HasAudioHardware(kAudioHardwarePropertyDefaultInputDevice);
}
+// TODO(crogers): There are several places on the OSX specific code which
+// could benefit from this helper function.
+bool AudioManagerMac::GetDefaultOutputDevice(
+ AudioDeviceID* device) {
+ CHECK(device);
+
+ // Obtain the current output device selected by the user.
+ static const AudioObjectPropertyAddress kAddress = {
+ kAudioHardwarePropertyDefaultOutputDevice,
+ kAudioObjectPropertyScopeGlobal,
+ kAudioObjectPropertyElementMaster
+ };
+
+ UInt32 size = sizeof(*device);
+
+ OSStatus result = AudioObjectGetPropertyData(
+ kAudioObjectSystemObject,
+ &kAddress,
+ 0,
+ 0,
+ &size,
+ device);
+
+ if ((result != kAudioHardwareNoError) || (*device == kAudioDeviceUnknown)) {
+ DLOG(ERROR) << "Error getting default output AudioDevice.";
+ return false;
+ }
+
+ return true;
+}
+
+bool AudioManagerMac::GetDefaultOutputChannels(
+ int* channels, int* channels_per_frame) {
+ AudioDeviceID device;
+ if (!GetDefaultOutputDevice(&device))
+ return false;
+
+ return GetDeviceChannels(device,
+ kAudioDevicePropertyScopeOutput,
+ channels,
+ channels_per_frame);
+}
+
+bool AudioManagerMac::GetDeviceChannels(
+ AudioDeviceID device,
+ AudioObjectPropertyScope scope,
+ int* channels,
+ int* channels_per_frame) {
+ CHECK(channels);
+ CHECK(channels_per_frame);
+
+ // Get stream configuration.
+ AudioObjectPropertyAddress pa;
+ pa.mSelector = kAudioDevicePropertyStreamConfiguration;
+ pa.mScope = scope;
+ pa.mElement = kAudioObjectPropertyElementMaster;
+
+ UInt32 size;
+ OSStatus result = AudioObjectGetPropertyDataSize(device, &pa, 0, 0, &size);
+ if (result != noErr || !size)
+ return false;
+
+ // Allocate storage.
+ scoped_array<uint8> list_storage(new uint8[size]);
+ AudioBufferList& buffer_list =
+ *reinterpret_cast<AudioBufferList*>(list_storage.get());
+
+ result = AudioObjectGetPropertyData(
+ device,
+ &pa,
+ 0,
+ 0,
+ &size,
+ &buffer_list);
+ if (result != noErr)
+ return false;
+
+ // Determine number of input channels.
+ *channels_per_frame = buffer_list.mNumberBuffers > 0 ?
+ buffer_list.mBuffers[0].mNumberChannels : 0;
+ if (*channels_per_frame == 1 && buffer_list.mNumberBuffers > 1) {
+ // Non-interleaved.
+ *channels = buffer_list.mNumberBuffers;
+ } else {
+ // Interleaved.
+ *channels = *channels_per_frame;
+ }
+
+ return true;
+}
+
void AudioManagerMac::GetAudioInputDeviceNames(
media::AudioDeviceNames* device_names) {
GetAudioDeviceInfo(true, device_names);
@@ -333,11 +424,23 @@ AudioInputStream* AudioManagerMac::MakeLowLatencyInputStream(
AudioParameters AudioManagerMac::GetPreferredOutputStreamParameters(
const AudioParameters& input_params) {
- ChannelLayout channel_layout = CHANNEL_LAYOUT_STEREO;
+ int hardware_channels = 2;
+ int hardware_channels_per_frame = 1;
+ if (!GetDefaultOutputChannels(&hardware_channels,
+ &hardware_channels_per_frame)) {
+ // Fallback to stereo.
+ hardware_channels = 2;
+ }
+
+ ChannelLayout channel_layout = GuessChannelLayout(hardware_channels);
+
int buffer_size = kDefaultLowLatencyBufferSize;
+ int user_buffer_size = GetUserBufferSize();
+ if (user_buffer_size)
+ buffer_size = user_buffer_size;
+
int input_channels = 0;
if (input_params.IsValid()) {
- channel_layout = input_params.channel_layout();
input_channels = input_params.input_channels();
if (input_channels > 0) {
@@ -349,13 +452,18 @@ AudioParameters AudioManagerMac::GetPreferredOutputStreamParameters(
}
}
- int user_buffer_size = GetUserBufferSize();
- if (user_buffer_size)
- buffer_size = user_buffer_size;
+ AudioParameters params(
+ AudioParameters::AUDIO_PCM_LOW_LATENCY,
+ channel_layout,
+ input_channels,
+ AUAudioOutputStream::HardwareSampleRate(),
+ 16,
+ buffer_size);
- return AudioParameters(
- AudioParameters::AUDIO_PCM_LOW_LATENCY, channel_layout, input_channels,
- AUAudioOutputStream::HardwareSampleRate(), 16, buffer_size);
+ if (channel_layout == CHANNEL_LAYOUT_UNSUPPORTED)
+ params.SetDiscreteChannels(hardware_channels);
+
+ return params;
}
void AudioManagerMac::CreateDeviceListener() {
diff --git a/media/audio/mac/audio_manager_mac.h b/media/audio/mac/audio_manager_mac.h
index 5eba595..6ebac06 100644
--- a/media/audio/mac/audio_manager_mac.h
+++ b/media/audio/mac/audio_manager_mac.h
@@ -38,6 +38,16 @@ class MEDIA_EXPORT AudioManagerMac : public AudioManagerBase {
virtual AudioInputStream* MakeLowLatencyInputStream(
const AudioParameters& params, const std::string& device_id) OVERRIDE;
+ static bool GetDefaultOutputDevice(AudioDeviceID* device);
+
+ static bool GetDefaultOutputChannels(int* channels,
+ int* channels_per_frame);
+
+ static bool GetDeviceChannels(AudioDeviceID device,
+ AudioObjectPropertyScope scope,
+ int* channels,
+ int* channels_per_frame);
+
protected:
virtual ~AudioManagerMac();
diff --git a/media/base/audio_converter.cc b/media/base/audio_converter.cc
index 1b66b03..5fda460 100644
--- a/media/base/audio_converter.cc
+++ b/media/base/audio_converter.cc
@@ -30,8 +30,7 @@ AudioConverter::AudioConverter(const AudioParameters& input_params,
<< " to " << output_params.channel_layout() << "; from "
<< input_params.channels() << " channels to "
<< output_params.channels() << " channels.";
- channel_mixer_.reset(new ChannelMixer(
- input_params.channel_layout(), output_params.channel_layout()));
+ channel_mixer_.reset(new ChannelMixer(input_params, output_params));
// Pare off data as early as we can for efficiency.
downmix_early_ = input_params.channels() > output_params.channels();
diff --git a/media/base/audio_hardware_config.cc b/media/base/audio_hardware_config.cc
index eaacc69..d72fce7 100644
--- a/media/base/audio_hardware_config.cc
+++ b/media/base/audio_hardware_config.cc
@@ -4,50 +4,77 @@
#include "media/base/audio_hardware_config.h"
+using base::AutoLock;
+using media::AudioParameters;
+
namespace media {
AudioHardwareConfig::AudioHardwareConfig(
- int output_buffer_size, int output_sample_rate,
- int input_sample_rate, ChannelLayout input_channel_layout)
- : output_buffer_size_(output_buffer_size),
- output_sample_rate_(output_sample_rate),
- input_sample_rate_(input_sample_rate),
- input_channel_layout_(input_channel_layout) {
+ const AudioParameters& input_params,
+ const AudioParameters& output_params)
+ : input_params_(input_params),
+ output_params_(output_params) {
}
AudioHardwareConfig::~AudioHardwareConfig() {}
-int AudioHardwareConfig::GetOutputBufferSize() {
- base::AutoLock auto_lock(config_lock_);
- return output_buffer_size_;
+int AudioHardwareConfig::GetOutputBufferSize() const {
+ AutoLock auto_lock(config_lock_);
+ return output_params_.frames_per_buffer();
+}
+
+int AudioHardwareConfig::GetOutputSampleRate() const {
+ AutoLock auto_lock(config_lock_);
+ return output_params_.sample_rate();
+}
+
+ChannelLayout AudioHardwareConfig::GetOutputChannelLayout() const {
+ AutoLock auto_lock(config_lock_);
+ return output_params_.channel_layout();
+}
+
+int AudioHardwareConfig::GetOutputChannels() const {
+ AutoLock auto_lock(config_lock_);
+ return output_params_.channels();
+}
+
+int AudioHardwareConfig::GetInputSampleRate() const {
+ AutoLock auto_lock(config_lock_);
+ return input_params_.sample_rate();
+}
+
+ChannelLayout AudioHardwareConfig::GetInputChannelLayout() const {
+ AutoLock auto_lock(config_lock_);
+ return input_params_.channel_layout();
}
-int AudioHardwareConfig::GetOutputSampleRate() {
- base::AutoLock auto_lock(config_lock_);
- return output_sample_rate_;
+int AudioHardwareConfig::GetInputChannels() const {
+ AutoLock auto_lock(config_lock_);
+ return input_params_.channels();
}
-int AudioHardwareConfig::GetInputSampleRate() {
- base::AutoLock auto_lock(config_lock_);
- return input_sample_rate_;
+media::AudioParameters
+AudioHardwareConfig::GetInputConfig() const {
+ AutoLock auto_lock(config_lock_);
+ return input_params_;
}
-ChannelLayout AudioHardwareConfig::GetInputChannelLayout() {
- base::AutoLock auto_lock(config_lock_);
- return input_channel_layout_;
+media::AudioParameters
+AudioHardwareConfig::GetOutputConfig() const {
+ AutoLock auto_lock(config_lock_);
+ return output_params_;
}
void AudioHardwareConfig::UpdateInputConfig(
- int sample_rate, media::ChannelLayout channel_layout) {
- base::AutoLock auto_lock(config_lock_);
- input_sample_rate_ = sample_rate;
- input_channel_layout_ = channel_layout;
+ const AudioParameters& input_params) {
+ AutoLock auto_lock(config_lock_);
+ input_params_ = input_params;
}
-void AudioHardwareConfig::UpdateOutputConfig(int buffer_size, int sample_rate) {
- base::AutoLock auto_lock(config_lock_);
- output_buffer_size_ = buffer_size;
- output_sample_rate_ = sample_rate;
+void AudioHardwareConfig::UpdateOutputConfig(
+ const AudioParameters& output_params) {
+ AutoLock auto_lock(config_lock_);
+ output_params_ = output_params;
}
} // namespace media
diff --git a/media/base/audio_hardware_config.h b/media/base/audio_hardware_config.h
index e61d9ba..d1621b98 100644
--- a/media/base/audio_hardware_config.h
+++ b/media/base/audio_hardware_config.h
@@ -7,6 +7,7 @@
#include "base/compiler_specific.h"
#include "base/synchronization/lock.h"
+#include "media/audio/audio_parameters.h"
#include "media/base/channel_layout.h"
#include "media/base/media_export.h"
@@ -15,32 +16,36 @@ namespace media {
// Provides thread safe access to the audio hardware configuration.
class MEDIA_EXPORT AudioHardwareConfig {
public:
- AudioHardwareConfig(int output_buffer_size, int output_sample_rate,
- int input_sample_rate,
- ChannelLayout input_channel_layout);
+ AudioHardwareConfig(const media::AudioParameters& input_params,
+ const media::AudioParameters& output_params);
virtual ~AudioHardwareConfig();
// Accessors for the currently cached hardware configuration. Safe to call
// from any thread.
- int GetOutputBufferSize();
- int GetOutputSampleRate();
- int GetInputSampleRate();
- ChannelLayout GetInputChannelLayout();
+ int GetOutputBufferSize() const;
+ int GetOutputSampleRate() const;
+ ChannelLayout GetOutputChannelLayout() const;
+ int GetOutputChannels() const;
+
+ int GetInputSampleRate() const;
+ ChannelLayout GetInputChannelLayout() const;
+ int GetInputChannels() const;
+
+ media::AudioParameters GetInputConfig() const;
+ media::AudioParameters GetOutputConfig() const;
// Allows callers to update the cached values for either input or output. The
// values are paired under the assumption that these values will only be set
// after an input or output device change respectively. Safe to call from
// any thread.
- void UpdateInputConfig(int sample_rate, media::ChannelLayout channel_layout);
- void UpdateOutputConfig(int buffer_size, int sample_rate);
+ void UpdateInputConfig(const media::AudioParameters& input_params);
+ void UpdateOutputConfig(const media::AudioParameters& output_params);
private:
// Cached values; access is protected by |config_lock_|.
- base::Lock config_lock_;
- int output_buffer_size_;
- int output_sample_rate_;
- int input_sample_rate_;
- ChannelLayout input_channel_layout_;
+ mutable base::Lock config_lock_;
+ media::AudioParameters input_params_;
+ media::AudioParameters output_params_;
DISALLOW_COPY_AND_ASSIGN(AudioHardwareConfig);
};
diff --git a/media/base/audio_hardware_config_unittest.cc b/media/base/audio_hardware_config_unittest.cc
index afa2e0d..4a742bf 100644
--- a/media/base/audio_hardware_config_unittest.cc
+++ b/media/base/audio_hardware_config_unittest.cc
@@ -3,19 +3,33 @@
// found in the LICENSE file.
#include "media/base/audio_hardware_config.h"
+#include "media/audio/audio_parameters.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace media {
static const int kOutputBufferSize = 2048;
static const int kOutputSampleRate = 48000;
+static const ChannelLayout kOutputChannelLayout = CHANNEL_LAYOUT_STEREO;
static const int kInputSampleRate = 44100;
static const ChannelLayout kInputChannelLayout = CHANNEL_LAYOUT_STEREO;
TEST(AudioHardwareConfig, Getters) {
- AudioHardwareConfig fake_config(
- kOutputBufferSize, kOutputSampleRate, kInputSampleRate,
- kInputChannelLayout);
+ AudioParameters input_params(
+ AudioParameters::AUDIO_PCM_LOW_LATENCY,
+ kInputChannelLayout,
+ kInputSampleRate,
+ 16,
+ kOutputBufferSize);
+
+ AudioParameters output_params(
+ AudioParameters::AUDIO_PCM_LOW_LATENCY,
+ kOutputChannelLayout,
+ kOutputSampleRate,
+ 16,
+ kOutputBufferSize);
+
+ AudioHardwareConfig fake_config(input_params, output_params);
EXPECT_EQ(kOutputBufferSize, fake_config.GetOutputBufferSize());
EXPECT_EQ(kOutputSampleRate, fake_config.GetOutputSampleRate());
@@ -24,16 +38,35 @@ TEST(AudioHardwareConfig, Getters) {
}
TEST(AudioHardwareConfig, Setters) {
- AudioHardwareConfig fake_config(
- kOutputBufferSize, kOutputSampleRate, kInputSampleRate,
- kInputChannelLayout);
+ AudioParameters input_params(
+ AudioParameters::AUDIO_PCM_LOW_LATENCY,
+ kInputChannelLayout,
+ kInputSampleRate,
+ 16,
+ kOutputBufferSize);
+
+ AudioParameters output_params(
+ AudioParameters::AUDIO_PCM_LOW_LATENCY,
+ kOutputChannelLayout,
+ kOutputSampleRate,
+ 16,
+ kOutputBufferSize);
+
+ AudioHardwareConfig fake_config(input_params, output_params);
// Verify output parameters.
const int kNewOutputBufferSize = kOutputBufferSize * 2;
const int kNewOutputSampleRate = kOutputSampleRate * 2;
EXPECT_NE(kNewOutputBufferSize, fake_config.GetOutputBufferSize());
EXPECT_NE(kNewOutputSampleRate, fake_config.GetOutputSampleRate());
- fake_config.UpdateOutputConfig(kNewOutputBufferSize, kNewOutputSampleRate);
+
+ AudioParameters new_output_params(
+ AudioParameters::AUDIO_PCM_LOW_LATENCY,
+ kOutputChannelLayout,
+ kNewOutputSampleRate,
+ 16,
+ kNewOutputBufferSize);
+ fake_config.UpdateOutputConfig(new_output_params);
EXPECT_EQ(kNewOutputBufferSize, fake_config.GetOutputBufferSize());
EXPECT_EQ(kNewOutputSampleRate, fake_config.GetOutputSampleRate());
@@ -42,7 +75,14 @@ TEST(AudioHardwareConfig, Setters) {
const ChannelLayout kNewInputChannelLayout = CHANNEL_LAYOUT_MONO;
EXPECT_NE(kNewInputSampleRate, fake_config.GetInputSampleRate());
EXPECT_NE(kNewInputChannelLayout, fake_config.GetInputChannelLayout());
- fake_config.UpdateInputConfig(kNewInputSampleRate, kNewInputChannelLayout);
+
+ AudioParameters new_input_params(
+ AudioParameters::AUDIO_PCM_LOW_LATENCY,
+ kNewInputChannelLayout,
+ kNewInputSampleRate,
+ 16,
+ kOutputBufferSize);
+ fake_config.UpdateInputConfig(new_input_params);
EXPECT_EQ(kNewInputSampleRate, fake_config.GetInputSampleRate());
EXPECT_EQ(kNewInputChannelLayout, fake_config.GetInputChannelLayout());
}
diff --git a/media/base/channel_layout.cc b/media/base/channel_layout.cc
index e622f91..927cd77 100644
--- a/media/base/channel_layout.cc
+++ b/media/base/channel_layout.cc
@@ -39,6 +39,7 @@ static const int kLayoutToChannels[] = {
7, // CHANNEL_LAYOUT_7_0_FRONT
8, // CHANNEL_LAYOUT_7_1_WIDE_BACK
8, // CHANNEL_LAYOUT_OCTAGONAL
+ 0, // CHANNEL_LAYOUT_DISCRETE
};
// The channel orderings for each layout as specified by FFmpeg. Each value
@@ -141,6 +142,9 @@ static const int kChannelOrderings[CHANNEL_LAYOUT_MAX][CHANNELS_MAX] = {
// CHANNEL_LAYOUT_OCTAGONAL
{ 0 , 1 , 2 , -1 , 5 , 6 , -1 , -1 , 7 , 3 , 4 },
+ // CHANNEL_LAYOUT_DISCRETE
+ { -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 },
+
// FL | FR | FC | LFE | BL | BR | FLofC | FRofC | BC | SL | SR
};
@@ -149,6 +153,31 @@ int ChannelLayoutToChannelCount(ChannelLayout layout) {
return kLayoutToChannels[layout];
}
+// Converts a channel count into a channel layout.
+ChannelLayout GuessChannelLayout(int channels) {
+ switch (channels) {
+ case 1:
+ return CHANNEL_LAYOUT_MONO;
+ case 2:
+ return CHANNEL_LAYOUT_STEREO;
+ case 3:
+ return CHANNEL_LAYOUT_SURROUND;
+ case 4:
+ return CHANNEL_LAYOUT_QUAD;
+ case 5:
+ return CHANNEL_LAYOUT_5_0;
+ case 6:
+ return CHANNEL_LAYOUT_5_1;
+ case 7:
+ return CHANNEL_LAYOUT_6_1;
+ case 8:
+ return CHANNEL_LAYOUT_7_1;
+ default:
+ DVLOG(1) << "Unsupported channel count: " << channels;
+ }
+ return CHANNEL_LAYOUT_UNSUPPORTED;
+}
+
int ChannelOrder(ChannelLayout layout, Channels channel) {
DCHECK_LT(static_cast<size_t>(layout), arraysize(kChannelOrderings));
DCHECK_LT(static_cast<size_t>(channel), arraysize(kChannelOrderings[0]));
diff --git a/media/base/channel_layout.h b/media/base/channel_layout.h
index 8153ca6..4c96ca5 100644
--- a/media/base/channel_layout.h
+++ b/media/base/channel_layout.h
@@ -96,6 +96,9 @@ enum ChannelLayout {
// Front L, Front R, Front C, Side L, Side R, Rear C, Back L, Back R.
CHANNEL_LAYOUT_OCTAGONAL = 28,
+ // Channels are not explicitly mapped to speakers.
+ CHANNEL_LAYOUT_DISCRETE = 29,
+
// Total number of layouts.
CHANNEL_LAYOUT_MAX // Must always be last!
};
@@ -123,6 +126,10 @@ MEDIA_EXPORT int ChannelOrder(ChannelLayout layout, Channels channel);
// Returns the number of channels in a given ChannelLayout.
MEDIA_EXPORT int ChannelLayoutToChannelCount(ChannelLayout layout);
+// Given the number of channels, return the best layout,
+// or return CHANNEL_LAYOUT_UNSUPPORTED if there is no good match.
+MEDIA_EXPORT ChannelLayout GuessChannelLayout(int channels);
+
} // namespace media
#endif // MEDIA_BASE_CHANNEL_LAYOUT_H_
diff --git a/media/base/channel_mixer.cc b/media/base/channel_mixer.cc
index fa4cbb6..420ecda 100644
--- a/media/base/channel_mixer.cc
+++ b/media/base/channel_mixer.cc
@@ -11,6 +11,7 @@
#include <cmath>
#include "base/logging.h"
+#include "media/audio/audio_parameters.h"
#include "media/base/audio_bus.h"
#include "media/base/vector_math.h"
@@ -20,14 +21,11 @@ namespace media {
// value for stereo -> mono and mono -> stereo mixes.
static const float kEqualPowerScale = static_cast<float>(M_SQRT1_2);
-static int ValidateLayout(ChannelLayout layout) {
+static void ValidateLayout(ChannelLayout layout) {
CHECK_NE(layout, CHANNEL_LAYOUT_NONE);
CHECK_NE(layout, CHANNEL_LAYOUT_MAX);
-
- // TODO(dalecurtis, crogers): We will eventually handle unsupported layouts by
- // simply copying the input channels to the output channels, similar to if the
- // user requests identical input and output layouts today.
CHECK_NE(layout, CHANNEL_LAYOUT_UNSUPPORTED);
+ CHECK_NE(layout, CHANNEL_LAYOUT_DISCRETE);
// Verify there's at least one channel. Should always be true here by virtue
// of not being one of the invalid layouts, but lets double check to be sure.
@@ -52,24 +50,60 @@ static int ValidateLayout(ChannelLayout layout) {
DCHECK_EQ(layout, CHANNEL_LAYOUT_MONO);
}
- return channel_count;
+ return;
+}
+
+ChannelMixer::ChannelMixer(ChannelLayout input_layout,
+ ChannelLayout output_layout) {
+ Initialize(input_layout,
+ ChannelLayoutToChannelCount(input_layout),
+ output_layout,
+ ChannelLayoutToChannelCount(output_layout));
}
-ChannelMixer::ChannelMixer(ChannelLayout input, ChannelLayout output)
- : input_layout_(input),
- output_layout_(output),
- remapping_(false) {
+ChannelMixer::ChannelMixer(
+ const AudioParameters& input, const AudioParameters& output) {
+ Initialize(input.channel_layout(),
+ input.channels(),
+ output.channel_layout(),
+ output.channels());
+}
+
+void ChannelMixer::Initialize(
+ ChannelLayout input_layout, int input_channels,
+ ChannelLayout output_layout, int output_channels) {
+ input_layout_ = input_layout;
+ output_layout_ = output_layout;
+ remapping_ = false;
+
// Stereo down mix should never be the output layout.
CHECK_NE(output_layout_, CHANNEL_LAYOUT_STEREO_DOWNMIX);
- int input_channels = ValidateLayout(input_layout_);
- int output_channels = ValidateLayout(output_layout_);
+ if (input_layout_ != CHANNEL_LAYOUT_DISCRETE)
+ ValidateLayout(input_layout_);
+ if (output_layout_ != CHANNEL_LAYOUT_DISCRETE)
+ ValidateLayout(output_layout_);
// Size out the initial matrix.
matrix_.reserve(output_channels);
for (int output_ch = 0; output_ch < output_channels; ++output_ch)
matrix_.push_back(std::vector<float>(input_channels, 0));
+ // First check for discrete case.
+ if (input_layout_ == CHANNEL_LAYOUT_DISCRETE ||
+ output_layout_ == CHANNEL_LAYOUT_DISCRETE) {
+ // If the number of input channels is more than output channels, then
+ // copy as many as we can then drop the remaining input channels.
+ // If the number of input channels is less than output channels, then
+ // copy them all, then zero out the remaining output channels.
+ int passthrough_channels = std::min(input_channels, output_channels);
+ for (int i = 0; i < passthrough_channels; ++i)
+ matrix_[i][i] = 1;
+
+ remapping_ = true;
+ return;
+ }
+
// Route matching channels and figure out which ones aren't accounted for.
for (Channels ch = LEFT; ch < CHANNELS_MAX;
ch = static_cast<Channels>(ch + 1)) {
@@ -102,7 +136,8 @@ ChannelMixer::ChannelMixer(ChannelLayout input, ChannelLayout output)
// When down mixing to mono from stereo, we need to be careful of full scale
// stereo mixes. Scaling by 1 / sqrt(2) here will likely lead to clipping
// so we use 1 / 2 instead.
- float scale = (output == CHANNEL_LAYOUT_MONO && input_channels == 2) ?
+ float scale =
+ (output_layout_ == CHANNEL_LAYOUT_MONO && input_channels == 2) ?
0.5 : kEqualPowerScale;
Mix(LEFT, CENTER, scale);
Mix(RIGHT, CENTER, scale);
@@ -111,7 +146,8 @@ ChannelMixer::ChannelMixer(ChannelLayout input, ChannelLayout output)
// Mix center into front LR.
if (IsUnaccounted(CENTER)) {
// When up mixing from mono, just do a copy to front LR.
- float scale = (input == CHANNEL_LAYOUT_MONO) ? 1 : kEqualPowerScale;
+ float scale =
+ (input_layout_ == CHANNEL_LAYOUT_MONO) ? 1 : kEqualPowerScale;
MixWithoutAccounting(CENTER, LEFT, scale);
Mix(CENTER, RIGHT, scale);
}
@@ -128,7 +164,7 @@ ChannelMixer::ChannelMixer(ChannelLayout input, ChannelLayout output)
// Mix back LR into back center.
Mix(BACK_LEFT, BACK_CENTER, kEqualPowerScale);
Mix(BACK_RIGHT, BACK_CENTER, kEqualPowerScale);
- } else if (output > CHANNEL_LAYOUT_MONO) {
+ } else if (output_layout_ > CHANNEL_LAYOUT_MONO) {
// Mix back LR into front LR.
Mix(BACK_LEFT, LEFT, kEqualPowerScale);
Mix(BACK_RIGHT, RIGHT, kEqualPowerScale);
@@ -151,7 +187,7 @@ ChannelMixer::ChannelMixer(ChannelLayout input, ChannelLayout output)
// Mix side LR into back center.
Mix(SIDE_LEFT, BACK_CENTER, kEqualPowerScale);
Mix(SIDE_RIGHT, BACK_CENTER, kEqualPowerScale);
- } else if (output > CHANNEL_LAYOUT_MONO) {
+ } else if (output_layout_ > CHANNEL_LAYOUT_MONO) {
// Mix side LR into front LR.
Mix(SIDE_LEFT, LEFT, kEqualPowerScale);
Mix(SIDE_RIGHT, RIGHT, kEqualPowerScale);
@@ -172,7 +208,7 @@ ChannelMixer::ChannelMixer(ChannelLayout input, ChannelLayout output)
// Mix back center into side LR.
MixWithoutAccounting(BACK_CENTER, SIDE_LEFT, kEqualPowerScale);
Mix(BACK_CENTER, SIDE_RIGHT, kEqualPowerScale);
- } else if (output > CHANNEL_LAYOUT_MONO) {
+ } else if (output_layout_ > CHANNEL_LAYOUT_MONO) {
// Mix back center into front LR.
// TODO(dalecurtis): Not sure about these values?
MixWithoutAccounting(BACK_CENTER, LEFT, kEqualPowerScale);
diff --git a/media/base/channel_mixer.h b/media/base/channel_mixer.h
index 0fdcc18..c88669d 100644
--- a/media/base/channel_mixer.h
+++ b/media/base/channel_mixer.h
@@ -14,6 +14,7 @@
namespace media {
class AudioBus;
+class AudioParameters;
// ChannelMixer is for converting audio between channel layouts. The conversion
// matrix is built upon construction and used during each Transform() call. The
@@ -23,9 +24,13 @@ class AudioBus;
// input channels as defined in the matrix.
class MEDIA_EXPORT ChannelMixer {
public:
- ChannelMixer(ChannelLayout input, ChannelLayout output);
+ ChannelMixer(ChannelLayout input_layout, ChannelLayout output_layout);
+ ChannelMixer(const AudioParameters& input, const AudioParameters& output);
~ChannelMixer();
+ void Initialize(ChannelLayout input_layout, int input_channels,
+ ChannelLayout output_layout, int output_channels);
+
// Transforms all channels from |input| into |output| channels.
void Transform(const AudioBus* input, AudioBus* output);
diff --git a/media/base/channel_mixer_unittest.cc b/media/base/channel_mixer_unittest.cc
index a71f86b..3e44409 100644
--- a/media/base/channel_mixer_unittest.cc
+++ b/media/base/channel_mixer_unittest.cc
@@ -25,6 +25,11 @@ TEST(ChannelMixerTest, ConstructAllPossibleLayouts) {
for (ChannelLayout output_layout = CHANNEL_LAYOUT_MONO;
output_layout < CHANNEL_LAYOUT_STEREO_DOWNMIX;
output_layout = static_cast<ChannelLayout>(output_layout + 1)) {
+ // DISCRETE can't be tested here based on the current approach.
+ if (input_layout == CHANNEL_LAYOUT_DISCRETE ||
+ output_layout == CHANNEL_LAYOUT_DISCRETE)
+ continue;
+
SCOPED_TRACE(base::StringPrintf(
"Input Layout: %d, Output Layout: %d", input_layout, output_layout));
ChannelMixer mixer(input_layout, output_layout);
diff --git a/media/ffmpeg/ffmpeg_common.cc b/media/ffmpeg/ffmpeg_common.cc
index bf23430..a2c4efd 100644
--- a/media/ffmpeg/ffmpeg_common.cc
+++ b/media/ffmpeg/ffmpeg_common.cc
@@ -269,32 +269,6 @@ static AVSampleFormat SampleFormatToAVSampleFormat(SampleFormat sample_format) {
return AV_SAMPLE_FMT_NONE;
}
-// Converts a channel count into a channel layout. Layouts chosen based on the
-// Vorbis / Opus channel layout.
-static ChannelLayout GuessChannelLayout(int channels) {
- switch (channels) {
- case 1:
- return CHANNEL_LAYOUT_MONO;
- case 2:
- return CHANNEL_LAYOUT_STEREO;
- case 3:
- return CHANNEL_LAYOUT_SURROUND;
- case 4:
- return CHANNEL_LAYOUT_QUAD;
- case 5:
- return CHANNEL_LAYOUT_5_0;
- case 6:
- return CHANNEL_LAYOUT_5_1;
- case 7:
- return CHANNEL_LAYOUT_6_1;
- case 8:
- return CHANNEL_LAYOUT_7_1;
- default:
- DVLOG(1) << "Unsupported channel count: " << channels;
- }
- return CHANNEL_LAYOUT_UNSUPPORTED;
-}
-
void AVCodecContextToAudioDecoderConfig(
const AVCodecContext* codec_context,
AudioDecoderConfig* config) {