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"
14 #include "media/audio/alsa/audio_manager_alsa.h"
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"
22 #if defined(DLOPEN_PULSEAUDIO)
23 #include "media/audio/pulse/pulse_stubs.h"
25 using media_audio_pulse::kModulePulse
;
26 using media_audio_pulse::InitializeStubs
;
27 using media_audio_pulse::StubPathMap
;
28 #endif // defined(DLOPEN_PULSEAUDIO)
32 using pulse::AutoPulseLock
;
33 using pulse::WaitForOperationCompletion
;
35 // Maximum number of output streams that can be open simultaneously.
36 static const int kMaxOutputStreams
= 50;
38 // Define bounds for the output buffer size.
39 static const int kMinimumOutputBufferSize
= 512;
40 static const int kMaximumOutputBufferSize
= 8192;
42 // Default input buffer size.
43 static const int kDefaultInputBufferSize
= 1024;
45 static const base::FilePath::CharType kPulseLib
[] =
46 FILE_PATH_LITERAL("libpulse.so.0");
49 AudioManager
* AudioManagerPulse::Create(AudioLogFactory
* audio_log_factory
) {
50 scoped_ptr
<AudioManagerPulse
> ret(new AudioManagerPulse(audio_log_factory
));
54 DVLOG(1) << "PulseAudio is not available on the OS";
58 AudioManagerPulse::AudioManagerPulse(AudioLogFactory
* audio_log_factory
)
59 : AudioManagerBase(audio_log_factory
),
60 input_mainloop_(NULL
),
63 native_input_sample_rate_(0) {
64 SetMaxOutputStreamsAllowed(kMaxOutputStreams
);
67 AudioManagerPulse::~AudioManagerPulse() {
70 // The Pulse objects are the last things to be destroyed since Shutdown()
75 // Implementation of AudioManager.
76 bool AudioManagerPulse::HasAudioOutputDevices() {
77 AudioDeviceNames devices
;
78 GetAudioOutputDeviceNames(&devices
);
79 return !devices
.empty();
82 bool AudioManagerPulse::HasAudioInputDevices() {
83 AudioDeviceNames devices
;
84 GetAudioInputDeviceNames(&devices
);
85 return !devices
.empty();
88 void AudioManagerPulse::ShowAudioInputSettings() {
90 AudioManagerAlsa::ShowLinuxAudioInputSettings();
94 void AudioManagerPulse::GetAudioDeviceNames(
95 bool input
, media::AudioDeviceNames
* device_names
) {
96 DCHECK(device_names
->empty());
97 DCHECK(input_mainloop_
);
98 DCHECK(input_context_
);
99 AutoPulseLock
auto_lock(input_mainloop_
);
100 devices_
= device_names
;
101 pa_operation
* operation
= NULL
;
103 operation
= pa_context_get_source_info_list(
104 input_context_
, InputDevicesInfoCallback
, this);
106 operation
= pa_context_get_sink_info_list(
107 input_context_
, OutputDevicesInfoCallback
, this);
109 WaitForOperationCompletion(input_mainloop_
, operation
);
111 // Prepend the default device if the list is not empty.
112 if (!device_names
->empty()) {
113 device_names
->push_front(
114 AudioDeviceName(AudioManagerBase::kDefaultDeviceName
,
115 AudioManagerBase::kDefaultDeviceId
));
119 void AudioManagerPulse::GetAudioInputDeviceNames(
120 AudioDeviceNames
* device_names
) {
121 GetAudioDeviceNames(true, device_names
);
124 void AudioManagerPulse::GetAudioOutputDeviceNames(
125 AudioDeviceNames
* device_names
) {
126 GetAudioDeviceNames(false, device_names
);
129 AudioParameters
AudioManagerPulse::GetInputStreamParameters(
130 const std::string
& device_id
) {
131 int user_buffer_size
= GetUserBufferSize();
132 int buffer_size
= user_buffer_size
?
133 user_buffer_size
: kDefaultInputBufferSize
;
135 // TODO(xians): add support for querying native channel layout for pulse.
136 return AudioParameters(
137 AudioParameters::AUDIO_PCM_LOW_LATENCY
, CHANNEL_LAYOUT_STEREO
,
138 GetNativeSampleRate(), 16, buffer_size
);
141 AudioOutputStream
* AudioManagerPulse::MakeLinearOutputStream(
142 const AudioParameters
& params
) {
143 DCHECK_EQ(AudioParameters::AUDIO_PCM_LINEAR
, params
.format());
144 return MakeOutputStream(params
, AudioManagerBase::kDefaultDeviceId
);
147 AudioOutputStream
* AudioManagerPulse::MakeLowLatencyOutputStream(
148 const AudioParameters
& params
,
149 const std::string
& device_id
) {
150 DCHECK_EQ(AudioParameters::AUDIO_PCM_LOW_LATENCY
, params
.format());
151 return MakeOutputStream(
153 device_id
.empty() ? AudioManagerBase::kDefaultDeviceId
: device_id
);
156 AudioInputStream
* AudioManagerPulse::MakeLinearInputStream(
157 const AudioParameters
& params
, const std::string
& device_id
) {
158 DCHECK_EQ(AudioParameters::AUDIO_PCM_LINEAR
, params
.format());
159 return MakeInputStream(params
, device_id
);
162 AudioInputStream
* AudioManagerPulse::MakeLowLatencyInputStream(
163 const AudioParameters
& params
, const std::string
& device_id
) {
164 DCHECK_EQ(AudioParameters::AUDIO_PCM_LOW_LATENCY
, params
.format());
165 return MakeInputStream(params
, device_id
);
168 AudioParameters
AudioManagerPulse::GetPreferredOutputStreamParameters(
169 const std::string
& output_device_id
,
170 const AudioParameters
& input_params
) {
171 // TODO(tommi): Support |output_device_id|.
172 VLOG_IF(0, !output_device_id
.empty()) << "Not implemented!";
174 ChannelLayout channel_layout
= CHANNEL_LAYOUT_STEREO
;
175 int buffer_size
= kMinimumOutputBufferSize
;
176 int bits_per_sample
= 16;
177 int input_channels
= 0;
178 int sample_rate
= GetNativeSampleRate();
179 if (input_params
.IsValid()) {
180 bits_per_sample
= input_params
.bits_per_sample();
181 channel_layout
= input_params
.channel_layout();
182 input_channels
= input_params
.input_channels();
184 std::min(kMaximumOutputBufferSize
,
185 std::max(buffer_size
, input_params
.frames_per_buffer()));
188 int user_buffer_size
= GetUserBufferSize();
189 if (user_buffer_size
)
190 buffer_size
= user_buffer_size
;
192 return AudioParameters(
193 AudioParameters::AUDIO_PCM_LOW_LATENCY
, channel_layout
, input_channels
,
194 sample_rate
, bits_per_sample
, buffer_size
, AudioParameters::NO_EFFECTS
);
197 AudioOutputStream
* AudioManagerPulse::MakeOutputStream(
198 const AudioParameters
& params
,
199 const std::string
& device_id
) {
200 DCHECK(!device_id
.empty());
201 return new PulseAudioOutputStream(params
, device_id
, this);
204 AudioInputStream
* AudioManagerPulse::MakeInputStream(
205 const AudioParameters
& params
, const std::string
& device_id
) {
206 return new PulseAudioInputStream(this, device_id
, params
,
207 input_mainloop_
, input_context_
);
210 int AudioManagerPulse::GetNativeSampleRate() {
211 DCHECK(input_mainloop_
);
212 DCHECK(input_context_
);
213 AutoPulseLock
auto_lock(input_mainloop_
);
214 pa_operation
* operation
= pa_context_get_server_info(
215 input_context_
, SampleRateInfoCallback
, this);
216 WaitForOperationCompletion(input_mainloop_
, operation
);
218 return native_input_sample_rate_
;
221 bool AudioManagerPulse::Init() {
222 DCHECK(!input_mainloop_
);
224 #if defined(DLOPEN_PULSEAUDIO)
227 // Check if the pulse library is avialbale.
228 paths
[kModulePulse
].push_back(kPulseLib
);
229 if (!InitializeStubs(paths
)) {
230 VLOG(1) << "Failed on loading the Pulse library and symbols";
233 #endif // defined(DLOPEN_PULSEAUDIO)
235 // Create a mainloop API and connect to the default server.
236 // The mainloop is the internal asynchronous API event loop.
237 input_mainloop_
= pa_threaded_mainloop_new();
238 if (!input_mainloop_
)
241 // Start the threaded mainloop.
242 if (pa_threaded_mainloop_start(input_mainloop_
))
245 // Lock the event loop object, effectively blocking the event loop thread
246 // from processing events. This is necessary.
247 AutoPulseLock
auto_lock(input_mainloop_
);
249 pa_mainloop_api
* pa_mainloop_api
=
250 pa_threaded_mainloop_get_api(input_mainloop_
);
251 input_context_
= pa_context_new(pa_mainloop_api
, "Chrome input");
255 pa_context_set_state_callback(input_context_
, &pulse::ContextStateCallback
,
257 if (pa_context_connect(input_context_
, NULL
, PA_CONTEXT_NOAUTOSPAWN
, NULL
)) {
258 VLOG(0) << "Failed to connect to the context. Error: "
259 << pa_strerror(pa_context_errno(input_context_
));
263 // Wait until |input_context_| is ready. pa_threaded_mainloop_wait() must be
264 // called after pa_context_get_state() in case the context is already ready,
265 // otherwise pa_threaded_mainloop_wait() will hang indefinitely.
267 pa_context_state_t context_state
= pa_context_get_state(input_context_
);
268 if (!PA_CONTEXT_IS_GOOD(context_state
))
270 if (context_state
== PA_CONTEXT_READY
)
272 pa_threaded_mainloop_wait(input_mainloop_
);
278 void AudioManagerPulse::DestroyPulse() {
279 if (!input_mainloop_
) {
280 DCHECK(!input_context_
);
285 AutoPulseLock
auto_lock(input_mainloop_
);
286 if (input_context_
) {
287 // Clear our state callback.
288 pa_context_set_state_callback(input_context_
, NULL
, NULL
);
289 pa_context_disconnect(input_context_
);
290 pa_context_unref(input_context_
);
291 input_context_
= NULL
;
295 pa_threaded_mainloop_stop(input_mainloop_
);
296 pa_threaded_mainloop_free(input_mainloop_
);
297 input_mainloop_
= NULL
;
300 void AudioManagerPulse::InputDevicesInfoCallback(pa_context
* context
,
301 const pa_source_info
* info
,
302 int error
, void *user_data
) {
303 AudioManagerPulse
* manager
= reinterpret_cast<AudioManagerPulse
*>(user_data
);
306 // Signal the pulse object that it is done.
307 pa_threaded_mainloop_signal(manager
->input_mainloop_
, 0);
311 // Exclude the output devices.
312 if (info
->monitor_of_sink
== PA_INVALID_INDEX
) {
313 manager
->devices_
->push_back(AudioDeviceName(info
->description
,
318 void AudioManagerPulse::OutputDevicesInfoCallback(pa_context
* context
,
319 const pa_sink_info
* info
,
320 int error
, void *user_data
) {
321 AudioManagerPulse
* manager
= reinterpret_cast<AudioManagerPulse
*>(user_data
);
324 // Signal the pulse object that it is done.
325 pa_threaded_mainloop_signal(manager
->input_mainloop_
, 0);
329 manager
->devices_
->push_back(AudioDeviceName(info
->description
,
333 void AudioManagerPulse::SampleRateInfoCallback(pa_context
* context
,
334 const pa_server_info
* info
,
336 AudioManagerPulse
* manager
= reinterpret_cast<AudioManagerPulse
*>(user_data
);
338 manager
->native_input_sample_rate_
= info
->sample_spec
.rate
;
339 pa_threaded_mainloop_signal(manager
->input_mainloop_
, 0);