Cast: Stop logging kVideoFrameSentToEncoder and rename a couple events.
[chromium-blink-merge.git] / media / audio / pulse / audio_manager_pulse.cc
blob238530a2038a6d8b904c62af0dd0ef2097bdccf6
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"
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"
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)
30 namespace media {
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 static const base::FilePath::CharType kPulseLib[] =
43 FILE_PATH_LITERAL("libpulse.so.0");
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();
51 DVLOG(1) << "PulseAudio is not available on the OS";
52 return NULL;
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);
64 AudioManagerPulse::~AudioManagerPulse() {
65 Shutdown();
67 // The Pulse objects are the last things to be destroyed since Shutdown()
68 // needs them.
69 DestroyPulse();
72 // Implementation of AudioManager.
73 bool AudioManagerPulse::HasAudioOutputDevices() {
74 AudioDeviceNames devices;
75 GetAudioOutputDeviceNames(&devices);
76 return !devices.empty();
79 bool AudioManagerPulse::HasAudioInputDevices() {
80 AudioDeviceNames devices;
81 GetAudioInputDeviceNames(&devices);
82 return !devices.empty();
85 void AudioManagerPulse::ShowAudioInputSettings() {
86 #if defined(USE_ALSA)
87 AudioManagerAlsa::ShowLinuxAudioInputSettings();
88 #endif
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);
106 WaitForOperationCompletion(input_mainloop_, operation);
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));
116 void AudioManagerPulse::GetAudioInputDeviceNames(
117 AudioDeviceNames* device_names) {
118 GetAudioDeviceNames(true, device_names);
121 void AudioManagerPulse::GetAudioOutputDeviceNames(
122 AudioDeviceNames* device_names) {
123 GetAudioDeviceNames(false, device_names);
126 AudioParameters AudioManagerPulse::GetInputStreamParameters(
127 const std::string& device_id) {
128 static const int kDefaultInputBufferSize = 1024;
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);
136 AudioOutputStream* AudioManagerPulse::MakeLinearOutputStream(
137 const AudioParameters& params) {
138 DCHECK_EQ(AudioParameters::AUDIO_PCM_LINEAR, params.format());
139 return MakeOutputStream(params, AudioManagerBase::kDefaultDeviceId);
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);
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);
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);
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!";
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();
186 int user_buffer_size = GetUserBufferSize();
187 if (user_buffer_size)
188 buffer_size = user_buffer_size;
190 return AudioParameters(
191 AudioParameters::AUDIO_PCM_LOW_LATENCY, channel_layout, input_channels,
192 sample_rate, bits_per_sample, buffer_size, AudioParameters::NO_EFFECTS);
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);
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_);
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);
216 return native_input_sample_rate_;
219 bool AudioManagerPulse::Init() {
220 DCHECK(!input_mainloop_);
222 #if defined(DLOPEN_PULSEAUDIO)
223 StubPathMap paths;
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;
231 #endif // defined(DLOPEN_PULSEAUDIO)
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;
239 // Start the threaded mainloop.
240 if (pa_threaded_mainloop_start(input_mainloop_))
241 return false;
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_);
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;
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;
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_);
273 return true;
276 void AudioManagerPulse::DestroyPulse() {
277 if (!input_mainloop_) {
278 DCHECK(!input_context_);
279 return;
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;
293 pa_threaded_mainloop_stop(input_mainloop_);
294 pa_threaded_mainloop_free(input_mainloop_);
295 input_mainloop_ = NULL;
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);
303 if (error) {
304 // Signal the pulse object that it is done.
305 pa_threaded_mainloop_signal(manager->input_mainloop_, 0);
306 return;
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));
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);
321 if (error) {
322 // Signal the pulse object that it is done.
323 pa_threaded_mainloop_signal(manager->input_mainloop_, 0);
324 return;
327 manager->devices_->push_back(AudioDeviceName(info->description,
328 info->name));
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);
336 manager->native_input_sample_rate_ = info->sample_spec.rate;
337 pa_threaded_mainloop_signal(manager->input_mainloop_, 0);
340 } // namespace media