1 /*****************************************************************************
2 * pulse.c : Pulseaudio output plugin for vlc
3 *****************************************************************************
4 * Copyright (C) 2008 the VideoLAN team
6 * Authors: Martin Hamrle <hamrle @ post . cz>
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
21 *****************************************************************************/
23 /*****************************************************************************
25 *****************************************************************************/
30 #include <vlc_common.h>
31 #include <vlc_plugin.h>
36 #include <pulse/pulseaudio.h>
37 #ifdef HAVE_X11_XLIB_H
38 # include <X11/Xlib.h>
43 /*****************************************************************************
44 * aout_sys_t: Pulseaudio output method descriptor
45 *****************************************************************************
46 * This structure is part of the audio output thread descriptor.
47 * It describes the specific properties of an audio device.
48 *****************************************************************************/
51 /** PulseAudio playback stream object */
52 struct pa_stream *stream;
54 /** PulseAudio connection context */
55 struct pa_context *context;
57 /** Main event loop object */
58 struct pa_threaded_mainloop *mainloop;
65 #define PULSE_CLIENT_NAME N_("VLC media player")
68 #define PULSE_DEBUG( ...) \
69 msg_Dbg( p_aout, __VA_ARGS__ )
71 #define PULSE_DEBUG( ...) \
76 #define CHECK_DEAD_GOTO(label) do { \
77 if (!p_sys->context || pa_context_get_state(p_sys->context) != PA_CONTEXT_READY || \
78 !p_sys->stream || pa_stream_get_state(p_sys->stream) != PA_STREAM_READY) { \
79 msg_Err(p_aout, "Connection died: %s", p_sys->context ? pa_strerror(pa_context_errno(p_sys->context)) : "NULL"); \
84 /*****************************************************************************
86 *****************************************************************************/
87 static int Open ( vlc_object_t * );
88 static void Close ( vlc_object_t * );
89 static void Play ( aout_instance_t * );
91 static void context_state_cb(pa_context *c, void *userdata);
92 static void stream_state_cb(pa_stream *s, void * userdata);
93 static void stream_request_cb(pa_stream *s, size_t length, void *userdata);
94 static void stream_latency_update_cb(pa_stream *s, void *userdata);
95 static void success_cb(pa_stream *s, int sucess, void *userdata);
96 static void uninit(aout_instance_t *p_aout);
98 /*****************************************************************************
100 *****************************************************************************/
102 set_shortname( "PulseAudio" )
103 set_description( N_("Pulseaudio audio output") )
104 set_capability( "audio output", 160 )
105 set_category( CAT_AUDIO )
106 set_subcategory( SUBCAT_AUDIO_AOUT )
107 add_shortcut( "pulseaudio" )
109 set_callbacks( Open, Close )
112 /*****************************************************************************
113 * Open: open the audio device
114 *****************************************************************************/
115 static int Open ( vlc_object_t *p_this )
117 aout_instance_t *p_aout = (aout_instance_t *)p_this;
118 struct aout_sys_t * p_sys;
119 struct pa_sample_spec ss;
120 const struct pa_buffer_attr *buffer_attr;
121 struct pa_buffer_attr a;
122 struct pa_channel_map map;
124 #ifdef X_DISPLAY_MISSING
125 # error Xlib required due to PulseAudio bug 799!
127 if( !XInitThreads() )
130 /* Allocate structures */
131 p_aout->output.p_sys = p_sys = calloc( 1, sizeof( aout_sys_t ) );
135 PULSE_DEBUG( "Pulse start initialization");
137 ss.channels = aout_FormatNbChannels( &p_aout->output.output ); /* Get the input stream channel count */
139 /* Setup the pulse audio stream based on the input stream count */
143 p_aout->output.output.i_physical_channels
144 = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT | AOUT_CHAN_CENTER
145 | AOUT_CHAN_MIDDLELEFT | AOUT_CHAN_MIDDLERIGHT
146 | AOUT_CHAN_REARLEFT | AOUT_CHAN_REARRIGHT
150 p_aout->output.output.i_physical_channels
151 = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT | AOUT_CHAN_CENTER
152 | AOUT_CHAN_REARLEFT | AOUT_CHAN_REARRIGHT
157 p_aout->output.output.i_physical_channels
158 = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT
159 | AOUT_CHAN_REARLEFT | AOUT_CHAN_REARRIGHT;
163 p_aout->output.output.i_physical_channels
164 = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT;
168 p_aout->output.output.i_physical_channels = AOUT_CHAN_CENTER;
172 msg_Err(p_aout,"Invalid number of channels");
176 /* Add a quick command line info message */
177 msg_Dbg(p_aout, "%d audio channels", ss.channels);
179 ss.rate = p_aout->output.output.i_rate;
182 ss.format = PA_SAMPLE_FLOAT32NE;
183 p_aout->output.output.i_format = VLC_CODEC_FL32;
187 ss.format = PA_SAMPLE_S16NE;
188 p_aout->output.output.i_format = VLC_CODEC_S16N;
191 if (!pa_sample_spec_valid(&ss)) {
192 msg_Err(p_aout,"Invalid sample spec");
196 /* Reduce overall latency to 200mS to reduce audible clicks
197 * Also pulse minreq and internal buffers are now 20mS which reduces resampling
199 a.tlength = pa_bytes_per_second(&ss)/5;
200 a.maxlength = a.tlength * 2;
201 a.prebuf = a.tlength / 2;
202 a.minreq = a.tlength / 10;
204 /* Buffer size is 20mS */
205 p_sys->buffer_size = a.minreq;
207 /* Initialise the speaker map setup above */
208 pa_channel_map_init_auto(&map, ss.channels, PA_CHANNEL_MAP_ALSA);
210 if (!(p_sys->mainloop = pa_threaded_mainloop_new())) {
211 msg_Err(p_aout, "Failed to allocate main loop");
215 if (!(p_sys->context = pa_context_new(pa_threaded_mainloop_get_api(p_sys->mainloop), _( PULSE_CLIENT_NAME )))) {
216 msg_Err(p_aout, "Failed to allocate context");
220 pa_context_set_state_callback(p_sys->context, context_state_cb, p_aout);
222 PULSE_DEBUG( "Pulse before context connect");
224 if (pa_context_connect(p_sys->context, NULL, 0, NULL) < 0) {
225 msg_Err(p_aout, "Failed to connect to server: %s", pa_strerror(pa_context_errno(p_sys->context)));
229 PULSE_DEBUG( "Pulse after context connect");
231 pa_threaded_mainloop_lock(p_sys->mainloop);
233 if (pa_threaded_mainloop_start(p_sys->mainloop) < 0) {
234 msg_Err(p_aout, "Failed to start main loop");
235 goto unlock_and_fail;
238 msg_Dbg(p_aout, "Pulse mainloop started");
240 /* Wait until the context is ready */
241 pa_threaded_mainloop_wait(p_sys->mainloop);
243 if (pa_context_get_state(p_sys->context) != PA_CONTEXT_READY) {
244 msg_Dbg(p_aout, "Failed to connect to server: %s", pa_strerror(pa_context_errno(p_sys->context)));
245 goto unlock_and_fail;
248 if (!(p_sys->stream = pa_stream_new(p_sys->context, "audio stream", &ss, &map))) {
249 msg_Err(p_aout, "Failed to create stream: %s", pa_strerror(pa_context_errno(p_sys->context)));
250 goto unlock_and_fail;
253 PULSE_DEBUG( "Pulse after new stream");
255 pa_stream_set_state_callback(p_sys->stream, stream_state_cb, p_aout);
256 pa_stream_set_write_callback(p_sys->stream, stream_request_cb, p_aout);
257 pa_stream_set_latency_update_callback(p_sys->stream, stream_latency_update_cb, p_aout);
259 if (pa_stream_connect_playback(p_sys->stream, NULL, &a, PA_STREAM_INTERPOLATE_TIMING|PA_STREAM_AUTO_TIMING_UPDATE|PA_STREAM_ADJUST_LATENCY, NULL, NULL) < 0) {
260 msg_Err(p_aout, "Failed to connect stream: %s", pa_strerror(pa_context_errno(p_sys->context)));
261 goto unlock_and_fail;
264 PULSE_DEBUG("Pulse stream connect");
266 /* Wait until the stream is ready */
267 pa_threaded_mainloop_wait(p_sys->mainloop);
269 msg_Dbg(p_aout,"Pulse stream connected");
271 if (pa_stream_get_state(p_sys->stream) != PA_STREAM_READY) {
272 msg_Err(p_aout, "Failed to connect to server: %s", pa_strerror(pa_context_errno(p_sys->context)));
273 goto unlock_and_fail;
277 PULSE_DEBUG("Pulse after stream get status");
279 pa_threaded_mainloop_unlock(p_sys->mainloop);
281 buffer_attr = pa_stream_get_buffer_attr(p_sys->stream);
282 p_aout->output.i_nb_samples = buffer_attr->minreq / pa_frame_size(&ss);
283 p_aout->output.pf_play = Play;
284 aout_VolumeSoftInit(p_aout);
285 msg_Dbg(p_aout, "Pulse initialized successfully");
287 char cmt[PA_CHANNEL_MAP_SNPRINT_MAX], sst[PA_SAMPLE_SPEC_SNPRINT_MAX];
289 msg_Dbg(p_aout, "Buffer metrics: maxlength=%u, tlength=%u, prebuf=%u, minreq=%u", buffer_attr->maxlength, buffer_attr->tlength, buffer_attr->prebuf, buffer_attr->minreq);
290 msg_Dbg(p_aout, "Using sample spec '%s', channel map '%s'.",
291 pa_sample_spec_snprint(sst, sizeof(sst), pa_stream_get_sample_spec(p_sys->stream)),
292 pa_channel_map_snprint(cmt, sizeof(cmt), pa_stream_get_channel_map(p_sys->stream)));
294 msg_Dbg(p_aout, "Connected to device %s (%u, %ssuspended).",
295 pa_stream_get_device_name(p_sys->stream),
296 pa_stream_get_device_index(p_sys->stream),
297 pa_stream_is_suspended(p_sys->stream) ? "" : "not ");
303 msg_Dbg(p_aout, "Pulse initialization unlock and fail");
306 pa_threaded_mainloop_unlock(p_sys->mainloop);
308 msg_Dbg(p_aout, "Pulse initialization failed");
313 /*****************************************************************************
314 * Play: play a sound samples buffer
315 *****************************************************************************/
316 static void Play( aout_instance_t * p_aout )
318 struct aout_sys_t * p_sys = (struct aout_sys_t *) p_aout->output.p_sys;
323 msg_Dbg(p_aout, "Pulse stream started");
325 aout_FifoFirstDate( p_aout, &p_aout->output.fifo );
328 pa_threaded_mainloop_lock(p_sys->mainloop);
329 if((o = pa_stream_flush(p_sys->stream, success_cb, p_aout))){
330 pa_operation_unref(o);
332 pa_threaded_mainloop_unlock(p_sys->mainloop);
334 pa_threaded_mainloop_signal(p_sys->mainloop, 0);
338 /*****************************************************************************
339 * Close: close the audio device
340 *****************************************************************************/
341 static void Close ( vlc_object_t *p_this )
343 aout_instance_t *p_aout = (aout_instance_t *)p_this;
344 struct aout_sys_t * p_sys = p_aout->output.p_sys;
346 msg_Dbg(p_aout, "Pulse Close");
349 pa_threaded_mainloop_lock(p_sys->mainloop);
350 pa_stream_set_write_callback(p_sys->stream, NULL, NULL);
352 /* I didn't find any explanation why we need to do pa_stream_drain on close
353 * as we don't really care if we lose 20ms buffer in this point anyway?
354 * And disabling this speeds up closing pulseaudio quite a lot (atleast for me).
357 pa_operation *o = pa_stream_drain(p_sys->stream, success_cb, p_aout);
359 while (pa_operation_get_state(o) != PA_OPERATION_DONE) {
360 CHECK_DEAD_GOTO(fail);
361 pa_threaded_mainloop_wait(p_sys->mainloop);
366 pa_operation_unref(o);
369 pa_threaded_mainloop_unlock(p_sys->mainloop);
374 static void uninit(aout_instance_t *p_aout){
375 struct aout_sys_t * p_sys = p_aout->output.p_sys;
378 pa_threaded_mainloop_stop(p_sys->mainloop);
381 pa_stream_disconnect(p_sys->stream);
382 pa_stream_unref(p_sys->stream);
383 p_sys->stream = NULL;
386 if (p_sys->context) {
387 pa_context_disconnect(p_sys->context);
388 pa_context_unref(p_sys->context);
389 p_sys->context = NULL;
392 if (p_sys->mainloop) {
393 pa_threaded_mainloop_free(p_sys->mainloop);
394 p_sys->mainloop = NULL;
398 p_aout->output.p_sys = NULL;
401 static void context_state_cb(pa_context *c, void *userdata) {
402 aout_instance_t *p_aout = (aout_instance_t *)userdata;
403 struct aout_sys_t * p_sys = (struct aout_sys_t *) p_aout->output.p_sys;
407 PULSE_DEBUG( "Pulse context state changed");
409 switch (pa_context_get_state(c)) {
410 case PA_CONTEXT_READY:
411 case PA_CONTEXT_TERMINATED:
412 case PA_CONTEXT_FAILED:
413 PULSE_DEBUG( "Pulse context state changed signal");
414 pa_threaded_mainloop_signal(p_sys->mainloop, 0);
417 case PA_CONTEXT_UNCONNECTED:
418 case PA_CONTEXT_CONNECTING:
419 case PA_CONTEXT_AUTHORIZING:
420 case PA_CONTEXT_SETTING_NAME:
421 PULSE_DEBUG( "Pulse context state changed no signal");
426 static void stream_state_cb(pa_stream *s, void * userdata) {
427 aout_instance_t *p_aout = (aout_instance_t *)userdata;
428 struct aout_sys_t * p_sys = (struct aout_sys_t *) p_aout->output.p_sys;
432 PULSE_DEBUG( "Pulse stream state changed");
434 switch (pa_stream_get_state(s)) {
436 case PA_STREAM_READY:
437 case PA_STREAM_FAILED:
438 case PA_STREAM_TERMINATED:
439 pa_threaded_mainloop_signal(p_sys->mainloop, 0);
442 case PA_STREAM_UNCONNECTED:
443 case PA_STREAM_CREATING:
448 static void stream_request_cb(pa_stream *s, size_t length, void *userdata) {
450 aout_instance_t *p_aout = (aout_instance_t *)userdata;
451 struct aout_sys_t * p_sys = (struct aout_sys_t *) p_aout->output.p_sys;
457 size_t buffer_size = p_sys->buffer_size;
459 PULSE_DEBUG( "Pulse stream request %d", length);
462 aout_buffer_t * p_buffer = NULL;
466 if(pa_stream_get_latency(p_sys->stream, &latency, &negative)<0){
467 if (pa_context_errno(p_sys->context) != PA_ERR_NODATA) {
468 msg_Err(p_aout, "pa_stream_get_latency() failed: %s", pa_strerror(pa_context_errno(p_sys->context)));
474 PULSE_DEBUG( "Pulse stream request latency=%"PRId64"", latency);
475 next_date = mdate() + latency;
477 if(p_sys->start_date < next_date + AOUT_PTS_TOLERANCE ){
478 p_buffer = aout_OutputNextBuffer( p_aout, next_date, 0);
482 if ( p_buffer != NULL )
484 PULSE_DEBUG( "Pulse stream request write buffer %d", p_buffer->i_buffer);
485 pa_stream_write(p_sys->stream, p_buffer->p_buffer, p_buffer->i_buffer, NULL, 0, PA_SEEK_RELATIVE);
486 length -= p_buffer->i_buffer;
487 aout_BufferFree( p_buffer );
491 PULSE_DEBUG( "Pulse stream request write zeroes");
492 void *data = pa_xmalloc(buffer_size);
493 bzero(data, buffer_size);
494 pa_stream_write(p_sys->stream, data, buffer_size, pa_xfree, 0, PA_SEEK_RELATIVE);
495 length -= buffer_size;
497 }while(length > buffer_size);
499 pa_threaded_mainloop_signal(p_sys->mainloop, 0);
502 static void stream_latency_update_cb(pa_stream *s, void *userdata) {
504 aout_instance_t *p_aout = (aout_instance_t *)userdata;
505 struct aout_sys_t * p_sys = (struct aout_sys_t *) p_aout->output.p_sys;
509 PULSE_DEBUG( "Pulse stream latency update");
511 pa_threaded_mainloop_signal(p_sys->mainloop, 0);
514 static void success_cb(pa_stream *s, int sucess, void *userdata)
517 aout_instance_t *p_aout = (aout_instance_t *)userdata;
518 struct aout_sys_t * p_sys = (struct aout_sys_t *) p_aout->output.p_sys;
524 pa_threaded_mainloop_signal(p_sys->mainloop, 0);