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