| // Copyright 2013 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "media/audio/cras/audio_manager_cras.h" |
| |
| #include <algorithm> |
| |
| #include "base/command_line.h" |
| #include "base/environment.h" |
| #include "base/logging.h" |
| #include "base/nix/xdg_util.h" |
| #include "base/stl_util.h" |
| #include "media/audio/cras/cras_input.h" |
| #include "media/audio/cras/cras_unified.h" |
| #include "media/base/channel_layout.h" |
| |
| // cras_util.h headers pull in min/max macros... |
| // TODO(dgreid): Fix headers such that these aren't imported. |
| #undef min |
| #undef max |
| |
| namespace media { |
| |
| static void AddDefaultDevice(AudioDeviceNames* device_names) { |
| DCHECK(device_names->empty()); |
| |
| // Cras will route audio from a proper physical device automatically. |
| device_names->push_back( |
| AudioDeviceName(AudioManagerBase::kDefaultDeviceName, |
| AudioManagerBase::kDefaultDeviceId)); |
| } |
| |
| // Maximum number of output streams that can be open simultaneously. |
| static const int kMaxOutputStreams = 50; |
| |
| // Default sample rate for input and output streams. |
| static const int kDefaultSampleRate = 48000; |
| |
| // Define bounds for the output buffer size. |
| static const int kMinimumOutputBufferSize = 512; |
| static const int kMaximumOutputBufferSize = 8192; |
| |
| // Default input buffer size. |
| static const int kDefaultInputBufferSize = 1024; |
| |
| bool AudioManagerCras::HasAudioOutputDevices() { |
| return true; |
| } |
| |
| bool AudioManagerCras::HasAudioInputDevices() { |
| return true; |
| } |
| |
| AudioManagerCras::AudioManagerCras(AudioLogFactory* audio_log_factory) |
| : AudioManagerBase(audio_log_factory) { |
| SetMaxOutputStreamsAllowed(kMaxOutputStreams); |
| } |
| |
| AudioManagerCras::~AudioManagerCras() { |
| Shutdown(); |
| } |
| |
| void AudioManagerCras::ShowAudioInputSettings() { |
| NOTIMPLEMENTED(); |
| } |
| |
| void AudioManagerCras::GetAudioInputDeviceNames( |
| AudioDeviceNames* device_names) { |
| AddDefaultDevice(device_names); |
| } |
| |
| void AudioManagerCras::GetAudioOutputDeviceNames( |
| AudioDeviceNames* device_names) { |
| AddDefaultDevice(device_names); |
| } |
| |
| AudioParameters AudioManagerCras::GetInputStreamParameters( |
| const std::string& device_id) { |
| int user_buffer_size = GetUserBufferSize(); |
| int buffer_size = user_buffer_size ? |
| user_buffer_size : kDefaultInputBufferSize; |
| |
| // TODO(hshi): Fine-tune audio parameters based on |device_id|. The optimal |
| // parameters for the loopback stream may differ from the default. |
| return AudioParameters( |
| AudioParameters::AUDIO_PCM_LOW_LATENCY, CHANNEL_LAYOUT_STEREO, |
| kDefaultSampleRate, 16, buffer_size); |
| } |
| |
| AudioOutputStream* AudioManagerCras::MakeLinearOutputStream( |
| const AudioParameters& params) { |
| DCHECK_EQ(AudioParameters::AUDIO_PCM_LINEAR, params.format()); |
| return MakeOutputStream(params); |
| } |
| |
| AudioOutputStream* AudioManagerCras::MakeLowLatencyOutputStream( |
| const AudioParameters& params, |
| const std::string& device_id) { |
| DLOG_IF(ERROR, !device_id.empty()) << "Not implemented!"; |
| DCHECK_EQ(AudioParameters::AUDIO_PCM_LOW_LATENCY, params.format()); |
| // TODO(dgreid): Open the correct input device for unified IO. |
| return MakeOutputStream(params); |
| } |
| |
| AudioInputStream* AudioManagerCras::MakeLinearInputStream( |
| const AudioParameters& params, const std::string& device_id) { |
| DCHECK_EQ(AudioParameters::AUDIO_PCM_LINEAR, params.format()); |
| return MakeInputStream(params, device_id); |
| } |
| |
| AudioInputStream* AudioManagerCras::MakeLowLatencyInputStream( |
| const AudioParameters& params, const std::string& device_id) { |
| DCHECK_EQ(AudioParameters::AUDIO_PCM_LOW_LATENCY, params.format()); |
| return MakeInputStream(params, device_id); |
| } |
| |
| AudioParameters AudioManagerCras::GetPreferredOutputStreamParameters( |
| const std::string& output_device_id, |
| const AudioParameters& input_params) { |
| // TODO(tommi): Support |output_device_id|. |
| DLOG_IF(ERROR, !output_device_id.empty()) << "Not implemented!"; |
| ChannelLayout channel_layout = CHANNEL_LAYOUT_STEREO; |
| int sample_rate = kDefaultSampleRate; |
| int buffer_size = kMinimumOutputBufferSize; |
| int bits_per_sample = 16; |
| int input_channels = 0; |
| if (input_params.IsValid()) { |
| sample_rate = input_params.sample_rate(); |
| bits_per_sample = input_params.bits_per_sample(); |
| channel_layout = input_params.channel_layout(); |
| input_channels = input_params.input_channels(); |
| buffer_size = |
| std::min(kMaximumOutputBufferSize, |
| std::max(buffer_size, input_params.frames_per_buffer())); |
| } |
| |
| int user_buffer_size = GetUserBufferSize(); |
| if (user_buffer_size) |
| buffer_size = user_buffer_size; |
| |
| return AudioParameters( |
| AudioParameters::AUDIO_PCM_LOW_LATENCY, channel_layout, input_channels, |
| sample_rate, bits_per_sample, buffer_size, AudioParameters::NO_EFFECTS); |
| } |
| |
| AudioOutputStream* AudioManagerCras::MakeOutputStream( |
| const AudioParameters& params) { |
| return new CrasUnifiedStream(params, this); |
| } |
| |
| AudioInputStream* AudioManagerCras::MakeInputStream( |
| const AudioParameters& params, const std::string& device_id) { |
| return new CrasInputStream(params, this, device_id); |
| } |
| |
| snd_pcm_format_t AudioManagerCras::BitsToFormat(int bits_per_sample) { |
| switch (bits_per_sample) { |
| case 8: |
| return SND_PCM_FORMAT_U8; |
| case 16: |
| return SND_PCM_FORMAT_S16; |
| case 24: |
| return SND_PCM_FORMAT_S24; |
| case 32: |
| return SND_PCM_FORMAT_S32; |
| default: |
| return SND_PCM_FORMAT_UNKNOWN; |
| } |
| } |
| |
| } // namespace media |