audio_manager_pulse.cc revision 868fa2fe829687343ffae624259930155e16dbd8
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.
4
5#include "media/audio/pulse/audio_manager_pulse.h"
6
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/process_util.h"
13#include "base/stl_util.h"
14#include "media/audio/audio_parameters.h"
15#include "media/audio/audio_util.h"
16#include "media/audio/linux/audio_manager_linux.h"
17#include "media/audio/pulse/pulse_input.h"
18#include "media/audio/pulse/pulse_output.h"
19#include "media/audio/pulse/pulse_unified.h"
20#include "media/audio/pulse/pulse_util.h"
21#include "media/base/channel_layout.h"
22
23#if defined(DLOPEN_PULSEAUDIO)
24#include "media/audio/pulse/pulse_stubs.h"
25
26using media_audio_pulse::kModulePulse;
27using media_audio_pulse::InitializeStubs;
28using media_audio_pulse::StubPathMap;
29#endif  // defined(DLOPEN_PULSEAUDIO)
30
31namespace media {
32
33using pulse::AutoPulseLock;
34using pulse::WaitForOperationCompletion;
35
36// Maximum number of output streams that can be open simultaneously.
37static const int kMaxOutputStreams = 50;
38
39static const base::FilePath::CharType kPulseLib[] =
40    FILE_PATH_LITERAL("libpulse.so.0");
41
42// static
43AudioManager* AudioManagerPulse::Create() {
44  scoped_ptr<AudioManagerPulse> ret(new AudioManagerPulse());
45  if (ret->Init())
46    return ret.release();
47
48  DVLOG(1) << "PulseAudio is not available on the OS";
49  return NULL;
50}
51
52AudioManagerPulse::AudioManagerPulse()
53    : input_mainloop_(NULL),
54      input_context_(NULL),
55      devices_(NULL),
56      native_input_sample_rate_(0) {
57  SetMaxOutputStreamsAllowed(kMaxOutputStreams);
58}
59
60AudioManagerPulse::~AudioManagerPulse() {
61  Shutdown();
62
63  // The Pulse objects are the last things to be destroyed since Shutdown()
64  // needs them.
65  DestroyPulse();
66}
67
68// Implementation of AudioManager.
69bool AudioManagerPulse::HasAudioOutputDevices() {
70  // TODO(xians): implement this function.
71  return true;
72}
73
74bool AudioManagerPulse::HasAudioInputDevices() {
75  // TODO(xians): implement this function.
76  return true;
77}
78
79void AudioManagerPulse::ShowAudioInputSettings() {
80  AudioManagerLinux::ShowLinuxAudioInputSettings();
81}
82
83void AudioManagerPulse::GetAudioInputDeviceNames(
84    media::AudioDeviceNames* device_names) {
85  DCHECK(device_names->empty());
86  DCHECK(input_mainloop_);
87  DCHECK(input_context_);
88  devices_ = device_names;
89  AutoPulseLock auto_lock(input_mainloop_);
90  pa_operation* operation = pa_context_get_source_info_list(
91      input_context_, DevicesInfoCallback, this);
92  WaitForOperationCompletion(input_mainloop_, operation);
93
94  // Append the default device on the top of the list if the list is not empty.
95  if (!device_names->empty()) {
96    device_names->push_front(
97        AudioDeviceName(AudioManagerBase::kDefaultDeviceName,
98                        AudioManagerBase::kDefaultDeviceId));
99  }
100}
101
102AudioParameters AudioManagerPulse::GetInputStreamParameters(
103    const std::string& device_id) {
104  static const int kDefaultInputBufferSize = 1024;
105
106  // TODO(xians): add support for querying native channel layout for pulse.
107  return AudioParameters(
108      AudioParameters::AUDIO_PCM_LOW_LATENCY, CHANNEL_LAYOUT_STEREO,
109      GetNativeSampleRate(), 16, kDefaultInputBufferSize);
110}
111
112AudioOutputStream* AudioManagerPulse::MakeLinearOutputStream(
113    const AudioParameters& params) {
114  DCHECK_EQ(AudioParameters::AUDIO_PCM_LINEAR, params.format());
115  return MakeOutputStream(params, std::string());
116}
117
118AudioOutputStream* AudioManagerPulse::MakeLowLatencyOutputStream(
119    const AudioParameters& params, const std::string& input_device_id) {
120  DCHECK_EQ(AudioParameters::AUDIO_PCM_LOW_LATENCY, params.format());
121  return MakeOutputStream(params, input_device_id);
122}
123
124AudioInputStream* AudioManagerPulse::MakeLinearInputStream(
125    const AudioParameters& params, const std::string& device_id) {
126  DCHECK_EQ(AudioParameters::AUDIO_PCM_LINEAR, params.format());
127  return MakeInputStream(params, device_id);
128}
129
130AudioInputStream* AudioManagerPulse::MakeLowLatencyInputStream(
131    const AudioParameters& params, const std::string& device_id) {
132  DCHECK_EQ(AudioParameters::AUDIO_PCM_LOW_LATENCY, params.format());
133  return MakeInputStream(params, device_id);
134}
135
136AudioParameters AudioManagerPulse::GetPreferredOutputStreamParameters(
137    const AudioParameters& input_params) {
138  static const int kDefaultOutputBufferSize = 512;
139
140  ChannelLayout channel_layout = CHANNEL_LAYOUT_STEREO;
141  int buffer_size = kDefaultOutputBufferSize;
142  int bits_per_sample = 16;
143  int input_channels = 0;
144  int sample_rate;
145  if (input_params.IsValid()) {
146    bits_per_sample = input_params.bits_per_sample();
147    channel_layout = input_params.channel_layout();
148    input_channels = input_params.input_channels();
149    buffer_size = std::min(buffer_size, input_params.frames_per_buffer());
150    sample_rate = input_params.sample_rate();
151  } else {
152    sample_rate = GetNativeSampleRate();
153  }
154
155  int user_buffer_size = GetUserBufferSize();
156  if (user_buffer_size)
157    buffer_size = user_buffer_size;
158
159  return AudioParameters(
160      AudioParameters::AUDIO_PCM_LOW_LATENCY, channel_layout, input_channels,
161      sample_rate, bits_per_sample, buffer_size);
162}
163
164AudioOutputStream* AudioManagerPulse::MakeOutputStream(
165    const AudioParameters& params, const std::string& input_device_id) {
166  if (params.input_channels()) {
167    return new PulseAudioUnifiedStream(params, input_device_id, this);
168  }
169
170  return new PulseAudioOutputStream(params, this);
171}
172
173AudioInputStream* AudioManagerPulse::MakeInputStream(
174    const AudioParameters& params, const std::string& device_id) {
175  return new PulseAudioInputStream(this, device_id, params,
176                                   input_mainloop_, input_context_);
177}
178
179int AudioManagerPulse::GetNativeSampleRate() {
180  DCHECK(input_mainloop_);
181  DCHECK(input_context_);
182  AutoPulseLock auto_lock(input_mainloop_);
183  pa_operation* operation = pa_context_get_server_info(
184      input_context_, SampleRateInfoCallback, this);
185  WaitForOperationCompletion(input_mainloop_, operation);
186
187  return native_input_sample_rate_;
188}
189
190bool AudioManagerPulse::Init() {
191  DCHECK(!input_mainloop_);
192
193#if defined(DLOPEN_PULSEAUDIO)
194  StubPathMap paths;
195
196  // Check if the pulse library is avialbale.
197  paths[kModulePulse].push_back(kPulseLib);
198  if (!InitializeStubs(paths)) {
199    DLOG(WARNING) << "Failed on loading the Pulse library and symbols";
200    return false;
201  }
202#endif  // defined(DLOPEN_PULSEAUDIO)
203
204  // Create a mainloop API and connect to the default server.
205  // The mainloop is the internal asynchronous API event loop.
206  input_mainloop_ = pa_threaded_mainloop_new();
207  if (!input_mainloop_)
208    return false;
209
210  // Start the threaded mainloop.
211  if (pa_threaded_mainloop_start(input_mainloop_))
212    return false;
213
214  // Lock the event loop object, effectively blocking the event loop thread
215  // from processing events. This is necessary.
216  AutoPulseLock auto_lock(input_mainloop_);
217
218  pa_mainloop_api* pa_mainloop_api =
219      pa_threaded_mainloop_get_api(input_mainloop_);
220  input_context_ = pa_context_new(pa_mainloop_api, "Chrome input");
221  if (!input_context_)
222    return false;
223
224  pa_context_set_state_callback(input_context_, &pulse::ContextStateCallback,
225                                input_mainloop_);
226  if (pa_context_connect(input_context_, NULL, PA_CONTEXT_NOAUTOSPAWN, NULL)) {
227    DLOG(ERROR) << "Failed to connect to the context.  Error: "
228                << pa_strerror(pa_context_errno(input_context_));
229    return false;
230  }
231
232  // Wait until |input_context_| is ready.  pa_threaded_mainloop_wait() must be
233  // called after pa_context_get_state() in case the context is already ready,
234  // otherwise pa_threaded_mainloop_wait() will hang indefinitely.
235  while (true) {
236    pa_context_state_t context_state = pa_context_get_state(input_context_);
237    if (!PA_CONTEXT_IS_GOOD(context_state))
238      return false;
239    if (context_state == PA_CONTEXT_READY)
240      break;
241    pa_threaded_mainloop_wait(input_mainloop_);
242  }
243
244  return true;
245}
246
247void AudioManagerPulse::DestroyPulse() {
248  if (!input_mainloop_) {
249    DCHECK(!input_context_);
250    return;
251  }
252
253  {
254    AutoPulseLock auto_lock(input_mainloop_);
255    if (input_context_) {
256      // Clear our state callback.
257      pa_context_set_state_callback(input_context_, NULL, NULL);
258      pa_context_disconnect(input_context_);
259      pa_context_unref(input_context_);
260      input_context_ = NULL;
261    }
262  }
263
264  pa_threaded_mainloop_stop(input_mainloop_);
265  pa_threaded_mainloop_free(input_mainloop_);
266  input_mainloop_ = NULL;
267}
268
269void AudioManagerPulse::DevicesInfoCallback(pa_context* context,
270                                            const pa_source_info* info,
271                                            int error, void *user_data) {
272  AudioManagerPulse* manager = reinterpret_cast<AudioManagerPulse*>(user_data);
273
274  if (error) {
275    // Signal the pulse object that it is done.
276    pa_threaded_mainloop_signal(manager->input_mainloop_, 0);
277    return;
278  }
279
280  // Exclude the output devices.
281  if (info->monitor_of_sink == PA_INVALID_INDEX) {
282    manager->devices_->push_back(media::AudioDeviceName(info->description,
283                                                        info->name));
284  }
285}
286
287void AudioManagerPulse::SampleRateInfoCallback(pa_context* context,
288                                               const pa_server_info* info,
289                                               void* user_data) {
290  AudioManagerPulse* manager = reinterpret_cast<AudioManagerPulse*>(user_data);
291
292  manager->native_input_sample_rate_ = info->sample_spec.rate;
293  pa_threaded_mainloop_signal(manager->input_mainloop_, 0);
294}
295
296}  // namespace media
297