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