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