diff options
author | slock@chromium.org <slock@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-08-22 19:56:51 +0000 |
---|---|---|
committer | slock@chromium.org <slock@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-08-22 19:56:51 +0000 |
commit | 9115cf37eb2442721d4f02d5631857082093b8fa (patch) | |
tree | 8ebb7af3cf383800b88fe34a9b79a25e5870fc01 | |
parent | 3a9bcbf8625df86ec726b64036b39595625978c9 (diff) | |
download | chromium_src-9115cf37eb2442721d4f02d5631857082093b8fa.zip chromium_src-9115cf37eb2442721d4f02d5631857082093b8fa.tar.gz chromium_src-9115cf37eb2442721d4f02d5631857082093b8fa.tar.bz2 |
Adds Surround Sound support using PulseAudio.
Depends on codereview.chromium.org/7473021: Preliminary PulseAudio Sound Playback on Linux.
PulseAudio has built in swizzling, downmixing, and upmixing. The client (Chrome) just has to give PulseAudio the channel layout of the audio it wants to play in the form of a pa_channel_map.
BUG=55489, 55490
TEST=
Review URL: http://codereview.chromium.org/7650002
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@97717 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r-- | media/audio/linux/pulse_output.cc | 83 |
1 files changed, 78 insertions, 5 deletions
diff --git a/media/audio/linux/pulse_output.cc b/media/audio/linux/pulse_output.cc index a405538..fe5e694 100644 --- a/media/audio/linux/pulse_output.cc +++ b/media/audio/linux/pulse_output.cc @@ -11,7 +11,7 @@ #include "media/base/data_buffer.h" #include "media/base/seekable_buffer.h" -static pa_sample_format_t BitsToFormat(int bits_per_sample) { +static pa_sample_format_t BitsToPASampleFormat(int bits_per_sample) { switch (bits_per_sample) { // Unsupported sample formats shown for reference. I am assuming we want // signed and little endian because that is what we gave to ALSA. @@ -36,6 +36,70 @@ static pa_sample_format_t BitsToFormat(int bits_per_sample) { } } +static pa_channel_position ChromiumToPAChannelPosition(Channels channel) { + switch (channel) { + // PulseAudio does not differentiate between left/right and + // stereo-left/stereo-right, both translate to front-left/front-right. + case LEFT: + case STEREO_LEFT: + return PA_CHANNEL_POSITION_FRONT_LEFT; + case RIGHT: + case STEREO_RIGHT: + return PA_CHANNEL_POSITION_FRONT_RIGHT; + case CENTER: + return PA_CHANNEL_POSITION_FRONT_CENTER; + case LFE: + return PA_CHANNEL_POSITION_LFE; + case BACK_LEFT: + return PA_CHANNEL_POSITION_REAR_LEFT; + case BACK_RIGHT: + return PA_CHANNEL_POSITION_REAR_RIGHT; + case LEFT_OF_CENTER: + return PA_CHANNEL_POSITION_FRONT_LEFT_OF_CENTER; + case RIGHT_OF_CENTER: + return PA_CHANNEL_POSITION_FRONT_RIGHT_OF_CENTER; + case BACK_CENTER: + return PA_CHANNEL_POSITION_REAR_CENTER; + case SIDE_LEFT: + return PA_CHANNEL_POSITION_SIDE_LEFT; + case SIDE_RIGHT: + return PA_CHANNEL_POSITION_SIDE_RIGHT; + case CHANNELS_MAX: + return PA_CHANNEL_POSITION_INVALID; + } + NOTREACHED(); +} + +static pa_channel_map ChannelLayoutToPAChannelMap( + ChannelLayout channel_layout) { + // Initialize channel map. + pa_channel_map channel_map; + pa_channel_map_init(&channel_map); + + channel_map.channels = ChannelLayoutToChannelCount(channel_layout); + + // All channel maps have the same size array of channel positions. + for (unsigned int channel = 0; channel != CHANNELS_MAX; ++channel) { + int channel_position = kChannelOrderings[channel_layout][channel]; + if (channel_position > -1) { + channel_map.map[channel_position] = ChromiumToPAChannelPosition( + static_cast<Channels>(channel)); + } else { + // PulseAudio expects unused channels in channel maps to be filled with + // PA_CHANNEL_POSITION_MONO. + channel_map.map[channel_position] = PA_CHANNEL_POSITION_MONO; + } + } + + // Fill in the rest of the unused channels. + for (unsigned int channel = CHANNELS_MAX; channel != PA_CHANNELS_MAX; + ++channel) { + channel_map.map[channel] = PA_CHANNEL_POSITION_MONO; + } + + return channel_map; +} + static size_t MicrosecondsToBytes( uint32 microseconds, uint32 sample_rate, size_t bytes_per_frame) { return microseconds * sample_rate * bytes_per_frame / @@ -66,7 +130,7 @@ PulseAudioOutputStream::PulseAudioOutputStream(const AudioParameters& params, MessageLoop* message_loop) : channel_layout_(params.channel_layout), channel_count_(ChannelLayoutToChannelCount(channel_layout_)), - sample_format_(BitsToFormat(params.bits_per_sample)), + sample_format_(BitsToPASampleFormat(params.bits_per_sample)), sample_rate_(params.sample_rate), bytes_per_frame_(params.channels * params.bits_per_sample / 8), manager_(manager), @@ -121,13 +185,23 @@ bool PulseAudioOutputStream::Open() { } } - // Set sample specifications and open playback stream. + // Set sample specifications. pa_sample_spec pa_sample_specifications; pa_sample_specifications.format = sample_format_; pa_sample_specifications.rate = sample_rate_; pa_sample_specifications.channels = channel_count_; + + // Get channel mapping and open playback stream. + pa_channel_map* map = NULL; + pa_channel_map source_channel_map = ChannelLayoutToPAChannelMap( + channel_layout_); + if (source_channel_map.channels != 0) { + // The source data uses a supported channel map so we will use it rather + // than the default channel map (NULL). + map = &source_channel_map; + } playback_handle_ = pa_stream_new(pa_context_, "Playback", - &pa_sample_specifications, NULL); + &pa_sample_specifications, map); // Initialize client buffer. uint32 output_packet_size = frames_per_packet_ * bytes_per_frame_; @@ -237,7 +311,6 @@ bool PulseAudioOutputStream::BufferPacketFromSource() { if (packet_size == 0) return false; - // TODO(slock): Swizzling and downmixing. media::AdjustVolume(packet->GetWritableData(), packet_size, channel_count_, |