]> git.sesse.net Git - vlc/blob - modules/audio_output/pulse.c
a064ff3aec0ef5307a143a16a3bd1d2a74255e7c
[vlc] / modules / audio_output / pulse.c
1 /*****************************************************************************
2  * pulse.c : Pulseaudio output plugin for vlc
3  *****************************************************************************
4  * Copyright (C) 2008 the VideoLAN team
5  *
6  * Authors: Martin Hamrle <hamrle @ post . cz>
7  *
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.
12  *
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.
17  *
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  *****************************************************************************/
22
23 /*****************************************************************************
24  * Preamble
25  *****************************************************************************/
26 #ifdef HAVE_CONFIG_H
27 # include "config.h"
28 #endif
29
30 #include <vlc_common.h>
31 #include <vlc_plugin.h>
32
33 #include <vlc_aout.h>
34 #include <vlc_cpu.h>
35
36 #include <pulse/pulseaudio.h>
37 #ifdef HAVE_X11_XLIB_H
38 # include <X11/Xlib.h>
39 #endif
40
41 #include <assert.h>
42
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  *****************************************************************************/
49 struct aout_sys_t
50 {
51     /** PulseAudio playback stream object */
52     struct pa_stream *stream;
53
54     /** PulseAudio connection context */
55     struct pa_context *context;
56
57     /** Main event loop object */
58     struct pa_threaded_mainloop *mainloop;
59
60     int started;
61     size_t buffer_size;
62     mtime_t start_date;
63 };
64
65 #define    PULSE_CLIENT_NAME N_("VLC media player")
66
67 #if 0
68 #define PULSE_DEBUG( ...) \
69     msg_Dbg( p_aout, __VA_ARGS__ )
70 #else
71 #define PULSE_DEBUG( ...) \
72     (void) 0
73 #endif
74
75
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"); \
80         goto label; \
81     }  \
82 } while(0);
83
84 /*****************************************************************************
85  * Local prototypes
86  *****************************************************************************/
87 static int  Open        ( vlc_object_t * );
88 static void Close       ( vlc_object_t * );
89 static void Play        ( aout_instance_t * );
90
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);
97
98 /*****************************************************************************
99  * Module descriptor
100  *****************************************************************************/
101 vlc_module_begin ()
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" )
108     add_shortcut( "pa" )
109     set_callbacks( Open, Close )
110 vlc_module_end ()
111
112 /*****************************************************************************
113  * Open: open the audio device
114  *****************************************************************************/
115 static int Open ( vlc_object_t *p_this )
116 {
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;
123
124 #ifdef X_DISPLAY_MISSING
125 # error Xlib required due to PulseAudio bug 799!
126 #else
127     if( !var_InheritBool( p_this, "xlib" ) || !XInitThreads() )
128         return VLC_EGENERIC;
129 #endif
130     /* Allocate structures */
131     p_aout->output.p_sys = p_sys = calloc( 1, sizeof( aout_sys_t ) );
132     if( p_sys == NULL )
133         return VLC_ENOMEM;
134
135     PULSE_DEBUG( "Pulse start initialization");
136
137     ss.channels = aout_FormatNbChannels( &p_aout->output.output ); /* Get the input stream channel count */
138
139     /* Setup the pulse audio stream based on the input stream count */
140     switch(ss.channels)
141     {
142         case 8:
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
147                 | AOUT_CHAN_LFE;
148             break;
149         case 6:
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
153                 | AOUT_CHAN_LFE;
154             break;
155
156         case 4:
157             p_aout->output.output.i_physical_channels
158                 = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT
159                 | AOUT_CHAN_REARLEFT | AOUT_CHAN_REARRIGHT;
160             break;
161
162         case 2:
163             p_aout->output.output.i_physical_channels
164                 = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT;
165             break;
166
167         case 1:
168             p_aout->output.output.i_physical_channels = AOUT_CHAN_CENTER;
169             break;
170
171         default:
172             msg_Err(p_aout,"Invalid number of channels");
173         goto fail;
174     }
175
176     /* Add a quick command line info message */
177     msg_Dbg(p_aout, "%d audio channels", ss.channels);
178
179     ss.rate = p_aout->output.output.i_rate;
180     if (HAVE_FPU)
181     {
182         ss.format = PA_SAMPLE_FLOAT32NE;
183         p_aout->output.output.i_format = VLC_CODEC_FL32;
184     }
185     else
186     {
187         ss.format = PA_SAMPLE_S16NE;
188         p_aout->output.output.i_format = VLC_CODEC_S16N;
189     }
190
191     if (!pa_sample_spec_valid(&ss)) {
192         msg_Err(p_aout,"Invalid sample spec");
193         goto fail;
194     }
195
196     /* Reduce overall latency to 200mS to reduce audible clicks
197      * Also pulse minreq and internal buffers are now 20mS which reduces resampling
198      */
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;
203
204     /* Buffer size is 20mS */
205     p_sys->buffer_size = a.minreq;
206
207     /* Initialise the speaker map setup above */
208     pa_channel_map_init_auto(&map, ss.channels, PA_CHANNEL_MAP_ALSA);
209
210     if (!(p_sys->mainloop = pa_threaded_mainloop_new())) {
211         msg_Err(p_aout, "Failed to allocate main loop");
212         goto fail;
213     }
214
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");
217         goto fail;
218     }
219
220     pa_context_set_state_callback(p_sys->context, context_state_cb, p_aout);
221
222     PULSE_DEBUG( "Pulse before context connect");
223
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)));
226         goto fail;
227     }
228
229     PULSE_DEBUG( "Pulse after context connect");
230
231     pa_threaded_mainloop_lock(p_sys->mainloop);
232
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;
236     }
237
238     msg_Dbg(p_aout, "Pulse mainloop started");
239
240     /* Wait until the context is ready */
241     pa_threaded_mainloop_wait(p_sys->mainloop);
242
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;
246     }
247
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;
251     }
252
253     PULSE_DEBUG( "Pulse after new stream");
254
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);
258
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;
262     }
263
264      PULSE_DEBUG("Pulse stream connect");
265
266     /* Wait until the stream is ready */
267     pa_threaded_mainloop_wait(p_sys->mainloop);
268
269     msg_Dbg(p_aout,"Pulse stream connected");
270
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;
274     }
275
276
277     PULSE_DEBUG("Pulse after stream get status");
278
279     pa_threaded_mainloop_unlock(p_sys->mainloop);
280
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");
286     {
287         char cmt[PA_CHANNEL_MAP_SNPRINT_MAX], sst[PA_SAMPLE_SPEC_SNPRINT_MAX];
288
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)));
293
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 ");
298     }
299
300     return VLC_SUCCESS;
301
302 unlock_and_fail:
303     msg_Dbg(p_aout, "Pulse initialization unlock and fail");
304
305     if (p_sys->mainloop)
306         pa_threaded_mainloop_unlock(p_sys->mainloop);
307 fail:
308     msg_Dbg(p_aout, "Pulse initialization failed");
309     uninit(p_aout);
310     return VLC_EGENERIC;
311 }
312
313 /*****************************************************************************
314  * Play: play a sound samples buffer
315  *****************************************************************************/
316 static void Play( aout_instance_t * p_aout )
317 {
318     struct aout_sys_t * p_sys = (struct aout_sys_t *) p_aout->output.p_sys;
319
320     pa_operation *o;
321
322     if(!p_sys->started){
323         msg_Dbg(p_aout, "Pulse stream started");
324         p_sys->start_date =
325             aout_FifoFirstDate( p_aout, &p_aout->output.fifo );
326         p_sys->started = 1;
327
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);
331         }
332         pa_threaded_mainloop_unlock(p_sys->mainloop);
333
334         pa_threaded_mainloop_signal(p_sys->mainloop, 0);
335     }
336 }
337
338 /*****************************************************************************
339  * Close: close the audio device
340  *****************************************************************************/
341 static void Close ( vlc_object_t *p_this )
342 {
343     aout_instance_t *p_aout = (aout_instance_t *)p_this;
344     struct aout_sys_t * p_sys = p_aout->output.p_sys;
345
346     msg_Dbg(p_aout, "Pulse Close");
347
348     if(p_sys->stream){
349         pa_threaded_mainloop_lock(p_sys->mainloop);
350         pa_stream_set_write_callback(p_sys->stream, NULL, NULL);
351
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).
355  */
356 #if 0
357         pa_operation *o = pa_stream_drain(p_sys->stream, success_cb, p_aout);
358         if(o){
359             while (pa_operation_get_state(o) != PA_OPERATION_DONE) {
360                 CHECK_DEAD_GOTO(fail);
361                 pa_threaded_mainloop_wait(p_sys->mainloop);
362             }
363
364         fail:
365
366             pa_operation_unref(o);
367         }
368 #endif
369         pa_threaded_mainloop_unlock(p_sys->mainloop);
370     }
371     uninit(p_aout);
372 }
373
374 static void uninit(aout_instance_t *p_aout){
375     struct aout_sys_t * p_sys = p_aout->output.p_sys;
376
377     if (p_sys->mainloop)
378         pa_threaded_mainloop_stop(p_sys->mainloop);
379
380     if (p_sys->stream) {
381         pa_stream_disconnect(p_sys->stream);
382         pa_stream_unref(p_sys->stream);
383         p_sys->stream = NULL;
384     }
385
386     if (p_sys->context) {
387         pa_context_disconnect(p_sys->context);
388         pa_context_unref(p_sys->context);
389         p_sys->context = NULL;
390     }
391
392     if (p_sys->mainloop) {
393         pa_threaded_mainloop_free(p_sys->mainloop);
394         p_sys->mainloop = NULL;
395     }
396
397     free(p_sys);
398     p_aout->output.p_sys = NULL;
399 }
400
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;
404
405     assert(c);
406
407     PULSE_DEBUG( "Pulse context state changed");
408
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);
415             break;
416
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");
422             break;
423     }
424 }
425
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;
429
430     assert(s);
431
432     PULSE_DEBUG( "Pulse stream state changed");
433
434     switch (pa_stream_get_state(s)) {
435
436         case PA_STREAM_READY:
437         case PA_STREAM_FAILED:
438         case PA_STREAM_TERMINATED:
439             pa_threaded_mainloop_signal(p_sys->mainloop, 0);
440             break;
441
442         case PA_STREAM_UNCONNECTED:
443         case PA_STREAM_CREATING:
444             break;
445     }
446 }
447
448 static void stream_request_cb(pa_stream *s, size_t length, void *userdata) {
449     VLC_UNUSED( s );
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;
452     mtime_t next_date;
453
454     assert(s);
455     assert(p_sys);
456
457     size_t buffer_size = p_sys->buffer_size;
458
459     PULSE_DEBUG( "Pulse stream request %d", length);
460
461     do{
462         aout_buffer_t *   p_buffer = NULL;
463         if(p_sys->started){
464             pa_usec_t latency;
465             int negative;
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)));
469                 }
470                 latency = 0;
471
472             }
473
474             PULSE_DEBUG( "Pulse stream request latency=%"PRId64"", latency);
475             next_date = mdate() + latency;
476
477             if(p_sys->start_date < next_date + AOUT_PTS_TOLERANCE ){
478                 p_buffer = aout_OutputNextBuffer( p_aout, next_date, 0);
479             }
480         }
481
482         if ( p_buffer != NULL )
483         {
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 );
488         }
489         else
490         {
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;
496         }
497     }while(length > buffer_size);
498
499     pa_threaded_mainloop_signal(p_sys->mainloop, 0);
500 }
501
502 static void stream_latency_update_cb(pa_stream *s, void *userdata) {
503     VLC_UNUSED( s );
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;
506
507     assert(s);
508
509     PULSE_DEBUG( "Pulse stream latency update");
510
511     pa_threaded_mainloop_signal(p_sys->mainloop, 0);
512 }
513
514 static void success_cb(pa_stream *s, int sucess, void *userdata)
515 {
516     VLC_UNUSED( s );
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;
519
520     VLC_UNUSED(sucess);
521
522     assert(s);
523
524     pa_threaded_mainloop_signal(p_sys->mainloop, 0);
525 }
526
527 #undef PULSE_DEBUG