Removed unused VideoCaptureCapability parameters.
[chromium-blink-merge.git] / media / audio / pulse / audio_manager_pulse.cc
blob4aac9c5e0800a0281f083b4a856dfc061c720bf7
1 // Copyright 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "media/audio/pulse/audio_manager_pulse.h"
7 #include "base/command_line.h"
8 #include "base/environment.h"
9 #include "base/files/file_path.h"
10 #include "base/logging.h"
11 #include "base/nix/xdg_util.h"
12 #include "base/stl_util.h"
13 #include "media/audio/audio_parameters.h"
14 #include "media/audio/linux/audio_manager_linux.h"
15 #include "media/audio/pulse/pulse_input.h"
16 #include "media/audio/pulse/pulse_output.h"
17 #include "media/audio/pulse/pulse_unified.h"
18 #include "media/audio/pulse/pulse_util.h"
19 #include "media/base/channel_layout.h"
21 #if defined(DLOPEN_PULSEAUDIO)
22 #include "media/audio/pulse/pulse_stubs.h"
24 using media_audio_pulse::kModulePulse;
25 using media_audio_pulse::InitializeStubs;
26 using media_audio_pulse::StubPathMap;
27 #endif // defined(DLOPEN_PULSEAUDIO)
29 namespace media {
31 using pulse::AutoPulseLock;
32 using pulse::WaitForOperationCompletion;
34 // Maximum number of output streams that can be open simultaneously.
35 static const int kMaxOutputStreams = 50;
37 static const base::FilePath::CharType kPulseLib[] =
38 FILE_PATH_LITERAL("libpulse.so.0");
40 // static
41 AudioManager* AudioManagerPulse::Create() {
42 scoped_ptr<AudioManagerPulse> ret(new AudioManagerPulse());
43 if (ret->Init())
44 return ret.release();
46 DVLOG(1) << "PulseAudio is not available on the OS";
47 return NULL;
50 AudioManagerPulse::AudioManagerPulse()
51 : input_mainloop_(NULL),
52 input_context_(NULL),
53 devices_(NULL),
54 native_input_sample_rate_(0) {
55 SetMaxOutputStreamsAllowed(kMaxOutputStreams);
58 AudioManagerPulse::~AudioManagerPulse() {
59 Shutdown();
61 // The Pulse objects are the last things to be destroyed since Shutdown()
62 // needs them.
63 DestroyPulse();
66 // Implementation of AudioManager.
67 bool AudioManagerPulse::HasAudioOutputDevices() {
68 AudioDeviceNames devices;
69 GetAudioOutputDeviceNames(&devices);
70 return !devices.empty();
73 bool AudioManagerPulse::HasAudioInputDevices() {
74 AudioDeviceNames devices;
75 GetAudioInputDeviceNames(&devices);
76 return !devices.empty();
79 void AudioManagerPulse::ShowAudioInputSettings() {
80 AudioManagerLinux::ShowLinuxAudioInputSettings();
83 void AudioManagerPulse::GetAudioDeviceNames(
84 bool input, media::AudioDeviceNames* device_names) {
85 DCHECK(device_names->empty());
86 DCHECK(input_mainloop_);
87 DCHECK(input_context_);
88 AutoPulseLock auto_lock(input_mainloop_);
89 devices_ = device_names;
90 pa_operation* operation = NULL;
91 if (input) {
92 operation = pa_context_get_source_info_list(
93 input_context_, InputDevicesInfoCallback, this);
94 } else {
95 operation = pa_context_get_sink_info_list(
96 input_context_, OutputDevicesInfoCallback, this);
98 WaitForOperationCompletion(input_mainloop_, operation);
100 // Prepend the default device if the list is not empty.
101 if (!device_names->empty()) {
102 device_names->push_front(
103 AudioDeviceName(AudioManagerBase::kDefaultDeviceName,
104 AudioManagerBase::kDefaultDeviceId));
108 void AudioManagerPulse::GetAudioInputDeviceNames(
109 AudioDeviceNames* device_names) {
110 GetAudioDeviceNames(true, device_names);
113 void AudioManagerPulse::GetAudioOutputDeviceNames(
114 AudioDeviceNames* device_names) {
115 GetAudioDeviceNames(false, device_names);
118 AudioParameters AudioManagerPulse::GetInputStreamParameters(
119 const std::string& device_id) {
120 static const int kDefaultInputBufferSize = 1024;
122 // TODO(xians): add support for querying native channel layout for pulse.
123 return AudioParameters(
124 AudioParameters::AUDIO_PCM_LOW_LATENCY, CHANNEL_LAYOUT_STEREO,
125 GetNativeSampleRate(), 16, kDefaultInputBufferSize);
128 AudioOutputStream* AudioManagerPulse::MakeLinearOutputStream(
129 const AudioParameters& params) {
130 DCHECK_EQ(AudioParameters::AUDIO_PCM_LINEAR, params.format());
131 return MakeOutputStream(params, std::string());
134 AudioOutputStream* AudioManagerPulse::MakeLowLatencyOutputStream(
135 const AudioParameters& params,
136 const std::string& device_id,
137 const std::string& input_device_id) {
138 DLOG_IF(ERROR, !device_id.empty()) << "Not implemented!";
139 DCHECK_EQ(AudioParameters::AUDIO_PCM_LOW_LATENCY, params.format());
140 return MakeOutputStream(params, input_device_id);
143 AudioInputStream* AudioManagerPulse::MakeLinearInputStream(
144 const AudioParameters& params, const std::string& device_id) {
145 DCHECK_EQ(AudioParameters::AUDIO_PCM_LINEAR, params.format());
146 return MakeInputStream(params, device_id);
149 AudioInputStream* AudioManagerPulse::MakeLowLatencyInputStream(
150 const AudioParameters& params, const std::string& device_id) {
151 DCHECK_EQ(AudioParameters::AUDIO_PCM_LOW_LATENCY, params.format());
152 return MakeInputStream(params, device_id);
155 AudioParameters AudioManagerPulse::GetPreferredOutputStreamParameters(
156 const std::string& output_device_id,
157 const AudioParameters& input_params) {
158 // TODO(tommi): Support |output_device_id|.
159 DLOG_IF(ERROR, !output_device_id.empty()) << "Not implemented!";
160 static const int kDefaultOutputBufferSize = 512;
162 ChannelLayout channel_layout = CHANNEL_LAYOUT_STEREO;
163 int buffer_size = kDefaultOutputBufferSize;
164 int bits_per_sample = 16;
165 int input_channels = 0;
166 int sample_rate;
167 if (input_params.IsValid()) {
168 bits_per_sample = input_params.bits_per_sample();
169 channel_layout = input_params.channel_layout();
170 input_channels = input_params.input_channels();
171 buffer_size = std::min(buffer_size, input_params.frames_per_buffer());
172 sample_rate = input_params.sample_rate();
173 } else {
174 sample_rate = GetNativeSampleRate();
177 int user_buffer_size = GetUserBufferSize();
178 if (user_buffer_size)
179 buffer_size = user_buffer_size;
181 return AudioParameters(
182 AudioParameters::AUDIO_PCM_LOW_LATENCY, channel_layout, input_channels,
183 sample_rate, bits_per_sample, buffer_size);
186 AudioOutputStream* AudioManagerPulse::MakeOutputStream(
187 const AudioParameters& params, const std::string& input_device_id) {
188 if (params.input_channels()) {
189 return new PulseAudioUnifiedStream(params, input_device_id, this);
192 return new PulseAudioOutputStream(params, this);
195 AudioInputStream* AudioManagerPulse::MakeInputStream(
196 const AudioParameters& params, const std::string& device_id) {
197 return new PulseAudioInputStream(this, device_id, params,
198 input_mainloop_, input_context_);
201 int AudioManagerPulse::GetNativeSampleRate() {
202 DCHECK(input_mainloop_);
203 DCHECK(input_context_);
204 AutoPulseLock auto_lock(input_mainloop_);
205 pa_operation* operation = pa_context_get_server_info(
206 input_context_, SampleRateInfoCallback, this);
207 WaitForOperationCompletion(input_mainloop_, operation);
209 return native_input_sample_rate_;
212 bool AudioManagerPulse::Init() {
213 DCHECK(!input_mainloop_);
215 #if defined(DLOPEN_PULSEAUDIO)
216 StubPathMap paths;
218 // Check if the pulse library is avialbale.
219 paths[kModulePulse].push_back(kPulseLib);
220 if (!InitializeStubs(paths)) {
221 DLOG(WARNING) << "Failed on loading the Pulse library and symbols";
222 return false;
224 #endif // defined(DLOPEN_PULSEAUDIO)
226 // Create a mainloop API and connect to the default server.
227 // The mainloop is the internal asynchronous API event loop.
228 input_mainloop_ = pa_threaded_mainloop_new();
229 if (!input_mainloop_)
230 return false;
232 // Start the threaded mainloop.
233 if (pa_threaded_mainloop_start(input_mainloop_))
234 return false;
236 // Lock the event loop object, effectively blocking the event loop thread
237 // from processing events. This is necessary.
238 AutoPulseLock auto_lock(input_mainloop_);
240 pa_mainloop_api* pa_mainloop_api =
241 pa_threaded_mainloop_get_api(input_mainloop_);
242 input_context_ = pa_context_new(pa_mainloop_api, "Chrome input");
243 if (!input_context_)
244 return false;
246 pa_context_set_state_callback(input_context_, &pulse::ContextStateCallback,
247 input_mainloop_);
248 if (pa_context_connect(input_context_, NULL, PA_CONTEXT_NOAUTOSPAWN, NULL)) {
249 DLOG(ERROR) << "Failed to connect to the context. Error: "
250 << pa_strerror(pa_context_errno(input_context_));
251 return false;
254 // Wait until |input_context_| is ready. pa_threaded_mainloop_wait() must be
255 // called after pa_context_get_state() in case the context is already ready,
256 // otherwise pa_threaded_mainloop_wait() will hang indefinitely.
257 while (true) {
258 pa_context_state_t context_state = pa_context_get_state(input_context_);
259 if (!PA_CONTEXT_IS_GOOD(context_state))
260 return false;
261 if (context_state == PA_CONTEXT_READY)
262 break;
263 pa_threaded_mainloop_wait(input_mainloop_);
266 return true;
269 void AudioManagerPulse::DestroyPulse() {
270 if (!input_mainloop_) {
271 DCHECK(!input_context_);
272 return;
276 AutoPulseLock auto_lock(input_mainloop_);
277 if (input_context_) {
278 // Clear our state callback.
279 pa_context_set_state_callback(input_context_, NULL, NULL);
280 pa_context_disconnect(input_context_);
281 pa_context_unref(input_context_);
282 input_context_ = NULL;
286 pa_threaded_mainloop_stop(input_mainloop_);
287 pa_threaded_mainloop_free(input_mainloop_);
288 input_mainloop_ = NULL;
291 void AudioManagerPulse::InputDevicesInfoCallback(pa_context* context,
292 const pa_source_info* info,
293 int error, void *user_data) {
294 AudioManagerPulse* manager = reinterpret_cast<AudioManagerPulse*>(user_data);
296 if (error) {
297 // Signal the pulse object that it is done.
298 pa_threaded_mainloop_signal(manager->input_mainloop_, 0);
299 return;
302 // Exclude the output devices.
303 if (info->monitor_of_sink == PA_INVALID_INDEX) {
304 manager->devices_->push_back(AudioDeviceName(info->description,
305 info->name));
309 void AudioManagerPulse::OutputDevicesInfoCallback(pa_context* context,
310 const pa_sink_info* info,
311 int error, void *user_data) {
312 AudioManagerPulse* manager = reinterpret_cast<AudioManagerPulse*>(user_data);
314 if (error) {
315 // Signal the pulse object that it is done.
316 pa_threaded_mainloop_signal(manager->input_mainloop_, 0);
317 return;
320 manager->devices_->push_back(AudioDeviceName(info->description,
321 info->name));
324 void AudioManagerPulse::SampleRateInfoCallback(pa_context* context,
325 const pa_server_info* info,
326 void* user_data) {
327 AudioManagerPulse* manager = reinterpret_cast<AudioManagerPulse*>(user_data);
329 manager->native_input_sample_rate_ = info->sample_spec.rate;
330 pa_threaded_mainloop_signal(manager->input_mainloop_, 0);
333 } // namespace media