diff options
author | crogers@google.com <crogers@google.com@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-03-13 20:36:51 +0000 |
---|---|---|
committer | crogers@google.com <crogers@google.com@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-03-13 20:36:51 +0000 |
commit | 06ea4f7c2ee733bdf2e717af72cb56fb571eafac (patch) | |
tree | c1e387d65490a2bc7cf9bfc72e32d33b646e1df8 | |
parent | a5d3767bf2ddae040dd9bdb894bbe6276e7f5a2f (diff) | |
download | chromium_src-06ea4f7c2ee733bdf2e717af72cb56fb571eafac.zip chromium_src-06ea4f7c2ee733bdf2e717af72cb56fb571eafac.tar.gz chromium_src-06ea4f7c2ee733bdf2e717af72cb56fb571eafac.tar.bz2 |
Pass more detailed audio hardware configuration information to the renderer
AudioHardwareConfig currently contains an ad-hoc mix of pieces of information about
the audio input and output hardware. This CL adds more complete and symmetric information
about the audio hardware as tracked in AudioHardwareConfig.
The ChannelMixer is also upgraded to allow for "discrete" up and down mixing.
BUG=none
TEST=manual - several tests updated
Review URL: https://codereview.chromium.org/12387006
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@187936 0039d316-1c4b-4281-b951-d872f2087c98
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) { |