]> git.sesse.net Git - vlc/blob - modules/audio_output/pulse.c
pulse: Use the 'user-agent' variable for the client name.
[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 X_DISPLAY_MISSING
38 # error Xlib required due to PulseAudio bug 799!
39 #endif
40 #include <vlc_xlib.h>
41
42 #include <assert.h>
43
44 /*****************************************************************************
45  * aout_sys_t: Pulseaudio output method descriptor
46  *****************************************************************************
47  * This structure is part of the audio output thread descriptor.
48  * It describes the specific properties of an audio device.
49  *****************************************************************************/
50 struct aout_sys_t
51 {
52     /** PulseAudio playback stream object */
53     struct pa_stream *stream;
54
55     /** PulseAudio connection context */
56     struct pa_context *context;
57
58     /** Main event loop object */
59     struct pa_threaded_mainloop *mainloop;
60
61     int started;
62     size_t buffer_size;
63     mtime_t start_date;
64 };
65
66 #if 0
67 #define PULSE_DEBUG( ...) \
68     msg_Dbg( p_aout, __VA_ARGS__ )
69 #else
70 #define PULSE_DEBUG( ...) \
71     (void) 0
72 #endif
73
74
75 #define CHECK_DEAD_GOTO(label) do { \
76 if (!p_sys->context || pa_context_get_state(p_sys->context) != PA_CONTEXT_READY || \
77     !p_sys->stream || pa_stream_get_state(p_sys->stream) != PA_STREAM_READY) { \
78         msg_Err(p_aout, "Connection died: %s", p_sys->context ? pa_strerror(pa_context_errno(p_sys->context)) : "NULL"); \
79         goto label; \
80     }  \
81 } while(0);
82
83 /*****************************************************************************
84  * Local prototypes
85  *****************************************************************************/
86 static int  Open        ( vlc_object_t * );
87 static void Close       ( vlc_object_t * );
88 static void Play        ( aout_instance_t * );
89
90 static void context_state_cb(pa_context *c, void *userdata);
91 static void stream_state_cb(pa_stream *s, void * userdata);
92 static void stream_request_cb(pa_stream *s, size_t length, void *userdata);
93 static void stream_latency_update_cb(pa_stream *s, void *userdata);
94 static void success_cb(pa_stream *s, int sucess, void *userdata);
95 static void uninit(aout_instance_t *p_aout);
96
97 /*****************************************************************************
98  * Module descriptor
99  *****************************************************************************/
100 vlc_module_begin ()
101     set_shortname( "PulseAudio" )
102     set_description( N_("Pulseaudio audio output") )
103     set_capability( "audio output", 160 )
104     set_category( CAT_AUDIO )
105     set_subcategory( SUBCAT_AUDIO_AOUT )
106     add_shortcut( "pulseaudio" )
107     add_shortcut( "pa" )
108     set_callbacks( Open, Close )
109 vlc_module_end ()
110
111 /*****************************************************************************
112  * Open: open the audio device
113  *****************************************************************************/
114 static int Open ( vlc_object_t *p_this )
115 {
116     aout_instance_t *p_aout = (aout_instance_t *)p_this;
117     struct aout_sys_t * p_sys;
118     struct pa_sample_spec ss;
119     const struct pa_buffer_attr *buffer_attr;
120     struct pa_buffer_attr a;
121     struct pa_channel_map map;
122     char * p_client_name = NULL;
123
124     if( !vlc_xlib_init( p_this ) )
125         return VLC_EGENERIC;
126
127     /* Allocate structures */
128     p_aout->output.p_sys = p_sys = calloc( 1, sizeof( aout_sys_t ) );
129     if( p_sys == NULL )
130         return VLC_ENOMEM;
131
132     PULSE_DEBUG( "Pulse start initialization");
133
134     ss.channels = aout_FormatNbChannels( &p_aout->output.output ); /* Get the input stream channel count */
135
136     /* Setup the pulse audio stream based on the input stream count */
137     switch(ss.channels)
138     {
139         case 8:
140             p_aout->output.output.i_physical_channels
141                 = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT | AOUT_CHAN_CENTER
142                 | AOUT_CHAN_MIDDLELEFT | AOUT_CHAN_MIDDLERIGHT
143                 | AOUT_CHAN_REARLEFT | AOUT_CHAN_REARRIGHT
144                 | AOUT_CHAN_LFE;
145             break;
146         case 6:
147             p_aout->output.output.i_physical_channels
148                 = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT | AOUT_CHAN_CENTER
149                 | AOUT_CHAN_REARLEFT | AOUT_CHAN_REARRIGHT
150                 | AOUT_CHAN_LFE;
151             break;
152
153         case 4:
154             p_aout->output.output.i_physical_channels
155                 = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT
156                 | AOUT_CHAN_REARLEFT | AOUT_CHAN_REARRIGHT;
157             break;
158
159         case 2:
160             p_aout->output.output.i_physical_channels
161                 = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT;
162             break;
163
164         case 1:
165             p_aout->output.output.i_physical_channels = AOUT_CHAN_CENTER;
166             break;
167
168         default:
169             msg_Err(p_aout,"Invalid number of channels");
170         goto fail;
171     }
172
173     /* Add a quick command line info message */
174     msg_Dbg(p_aout, "%d audio channels", ss.channels);
175
176     ss.rate = p_aout->output.output.i_rate;
177     if (HAVE_FPU)
178     {
179         ss.format = PA_SAMPLE_FLOAT32NE;
180         p_aout->output.output.i_format = VLC_CODEC_FL32;
181     }
182     else
183     {
184         ss.format = PA_SAMPLE_S16NE;
185         p_aout->output.output.i_format = VLC_CODEC_S16N;
186     }
187
188     if (!pa_sample_spec_valid(&ss)) {
189         msg_Err(p_aout,"Invalid sample spec");
190         goto fail;
191     }
192
193     /* Reduce overall latency to 200mS to reduce audible clicks
194      * Also pulse minreq and internal buffers are now 20mS which reduces resampling
195      */
196     a.tlength = pa_bytes_per_second(&ss)/5;
197     a.maxlength = a.tlength * 2;
198     a.prebuf = a.tlength / 2;
199     a.minreq = a.tlength / 10;
200
201     /* Buffer size is 20mS */
202     p_sys->buffer_size = a.minreq;
203
204     /* Initialise the speaker map setup above */
205     pa_channel_map_init_auto(&map, ss.channels, PA_CHANNEL_MAP_ALSA);
206
207     if (!(p_sys->mainloop = pa_threaded_mainloop_new())) {
208         msg_Err(p_aout, "Failed to allocate main loop");
209         goto fail;
210     }
211
212     if ((p_client_name = var_InheritString(p_aout, "user-agent")) == NULL) {
213         msg_Err(p_aout, "No user-agent string available.");
214         goto fail;
215     }
216
217     if (!(p_sys->context = pa_context_new(pa_threaded_mainloop_get_api(p_sys->mainloop), p_client_name))) {
218         msg_Err(p_aout, "Failed to allocate context");
219         goto fail;
220     }
221
222     pa_context_set_state_callback(p_sys->context, context_state_cb, p_aout);
223
224     PULSE_DEBUG( "Pulse before context connect");
225
226     if (pa_context_connect(p_sys->context, NULL, 0, NULL) < 0) {
227         msg_Err(p_aout, "Failed to connect to server: %s", pa_strerror(pa_context_errno(p_sys->context)));
228         goto fail;
229     }
230
231     PULSE_DEBUG( "Pulse after context connect");
232
233     pa_threaded_mainloop_lock(p_sys->mainloop);
234
235     if (pa_threaded_mainloop_start(p_sys->mainloop) < 0) {
236         msg_Err(p_aout, "Failed to start main loop");
237         goto unlock_and_fail;
238     }
239
240     msg_Dbg(p_aout, "Pulse mainloop started");
241
242     /* Wait until the context is ready */
243     pa_threaded_mainloop_wait(p_sys->mainloop);
244
245     if (pa_context_get_state(p_sys->context) != PA_CONTEXT_READY) {
246         msg_Dbg(p_aout, "Failed to connect to server: %s", pa_strerror(pa_context_errno(p_sys->context)));
247         goto unlock_and_fail;
248     }
249
250     if (!(p_sys->stream = pa_stream_new(p_sys->context, "audio stream", &ss, &map))) {
251         msg_Err(p_aout, "Failed to create stream: %s", pa_strerror(pa_context_errno(p_sys->context)));
252         goto unlock_and_fail;
253     }
254
255     PULSE_DEBUG( "Pulse after new stream");
256
257     pa_stream_set_state_callback(p_sys->stream, stream_state_cb, p_aout);
258     pa_stream_set_write_callback(p_sys->stream, stream_request_cb, p_aout);
259     pa_stream_set_latency_update_callback(p_sys->stream, stream_latency_update_cb, p_aout);
260
261     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) {
262         msg_Err(p_aout, "Failed to connect stream: %s", pa_strerror(pa_context_errno(p_sys->context)));
263         goto unlock_and_fail;
264     }
265
266      PULSE_DEBUG("Pulse stream connect");
267
268     /* Wait until the stream is ready */
269     pa_threaded_mainloop_wait(p_sys->mainloop);
270
271     msg_Dbg(p_aout,"Pulse stream connected");
272
273     if (pa_stream_get_state(p_sys->stream) != PA_STREAM_READY) {
274         msg_Err(p_aout, "Failed to connect to server: %s", pa_strerror(pa_context_errno(p_sys->context)));
275         goto unlock_and_fail;
276     }
277
278
279     PULSE_DEBUG("Pulse after stream get status");
280
281     pa_threaded_mainloop_unlock(p_sys->mainloop);
282
283     buffer_attr = pa_stream_get_buffer_attr(p_sys->stream);
284     p_aout->output.i_nb_samples = buffer_attr->minreq / pa_frame_size(&ss);
285     p_aout->output.pf_play = Play;
286     aout_VolumeSoftInit(p_aout);
287     msg_Dbg(p_aout, "Pulse initialized successfully");
288     {
289         char cmt[PA_CHANNEL_MAP_SNPRINT_MAX], sst[PA_SAMPLE_SPEC_SNPRINT_MAX];
290
291         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);
292         msg_Dbg(p_aout, "Using sample spec '%s', channel map '%s'.",
293                 pa_sample_spec_snprint(sst, sizeof(sst), pa_stream_get_sample_spec(p_sys->stream)),
294                 pa_channel_map_snprint(cmt, sizeof(cmt), pa_stream_get_channel_map(p_sys->stream)));
295
296             msg_Dbg(p_aout, "Connected to device %s (%u, %ssuspended).",
297                         pa_stream_get_device_name(p_sys->stream),
298                         pa_stream_get_device_index(p_sys->stream),
299                         pa_stream_is_suspended(p_sys->stream) ? "" : "not ");
300     }
301
302     return VLC_SUCCESS;
303
304 unlock_and_fail:
305     msg_Dbg(p_aout, "Pulse initialization unlock and fail");
306
307     if (p_sys->mainloop)
308         pa_threaded_mainloop_unlock(p_sys->mainloop);
309 fail:
310     if (p_client_name)
311         free(p_client_name);
312     msg_Dbg(p_aout, "Pulse initialization failed");
313     uninit(p_aout);
314     return VLC_EGENERIC;
315 }
316
317 /*****************************************************************************
318  * Play: play a sound samples buffer
319  *****************************************************************************/
320 static void Play( aout_instance_t * p_aout )
321 {
322     struct aout_sys_t * p_sys = (struct aout_sys_t *) p_aout->output.p_sys;
323
324     pa_operation *o;
325
326     if(!p_sys->started){
327         msg_Dbg(p_aout, "Pulse stream started");
328         p_sys->start_date =
329             aout_FifoFirstDate( p_aout, &p_aout->output.fifo );
330         p_sys->started = 1;
331
332         pa_threaded_mainloop_lock(p_sys->mainloop);
333         if((o = pa_stream_flush(p_sys->stream, success_cb, p_aout))){
334             pa_operation_unref(o);
335         }
336         pa_threaded_mainloop_unlock(p_sys->mainloop);
337
338         pa_threaded_mainloop_signal(p_sys->mainloop, 0);
339     }
340 }
341
342 /*****************************************************************************
343  * Close: close the audio device
344  *****************************************************************************/
345 static void Close ( vlc_object_t *p_this )
346 {
347     aout_instance_t *p_aout = (aout_instance_t *)p_this;
348     struct aout_sys_t * p_sys = p_aout->output.p_sys;
349
350     msg_Dbg(p_aout, "Pulse Close");
351
352     if(p_sys->stream){
353         pa_threaded_mainloop_lock(p_sys->mainloop);
354         pa_stream_set_write_callback(p_sys->stream, NULL, NULL);
355
356 /* I didn't find any explanation why we need to do pa_stream_drain on close
357  * as we don't really care if we lose 20ms buffer in this point anyway?
358  * And disabling this speeds up closing pulseaudio quite a lot (atleast for me).
359  */
360 #if 0
361         pa_operation *o = pa_stream_drain(p_sys->stream, success_cb, p_aout);
362         if(o){
363             while (pa_operation_get_state(o) != PA_OPERATION_DONE) {
364                 CHECK_DEAD_GOTO(fail);
365                 pa_threaded_mainloop_wait(p_sys->mainloop);
366             }
367
368         fail:
369
370             pa_operation_unref(o);
371         }
372 #endif
373         pa_threaded_mainloop_unlock(p_sys->mainloop);
374     }
375     uninit(p_aout);
376 }
377
378 static void uninit(aout_instance_t *p_aout){
379     struct aout_sys_t * p_sys = p_aout->output.p_sys;
380
381     if (p_sys->mainloop)
382         pa_threaded_mainloop_stop(p_sys->mainloop);
383
384     if (p_sys->stream) {
385         pa_stream_disconnect(p_sys->stream);
386         pa_stream_unref(p_sys->stream);
387         p_sys->stream = NULL;
388     }
389
390     if (p_sys->context) {
391         pa_context_disconnect(p_sys->context);
392         pa_context_unref(p_sys->context);
393         p_sys->context = NULL;
394     }
395
396     if (p_sys->mainloop) {
397         pa_threaded_mainloop_free(p_sys->mainloop);
398         p_sys->mainloop = NULL;
399     }
400
401     free(p_sys);
402     p_aout->output.p_sys = NULL;
403 }
404
405 static void context_state_cb(pa_context *c, void *userdata) {
406     aout_instance_t *p_aout = (aout_instance_t *)userdata;
407     struct aout_sys_t * p_sys = (struct aout_sys_t *) p_aout->output.p_sys;
408
409     assert(c);
410
411     PULSE_DEBUG( "Pulse context state changed");
412
413     switch (pa_context_get_state(c)) {
414         case PA_CONTEXT_READY:
415         case PA_CONTEXT_TERMINATED:
416         case PA_CONTEXT_FAILED:
417         PULSE_DEBUG( "Pulse context state changed signal");
418             pa_threaded_mainloop_signal(p_sys->mainloop, 0);
419             break;
420
421         case PA_CONTEXT_UNCONNECTED:
422         case PA_CONTEXT_CONNECTING:
423         case PA_CONTEXT_AUTHORIZING:
424         case PA_CONTEXT_SETTING_NAME:
425         PULSE_DEBUG( "Pulse context state changed no signal");
426             break;
427     }
428 }
429
430 static void stream_state_cb(pa_stream *s, void * userdata) {
431     aout_instance_t *p_aout = (aout_instance_t *)userdata;
432     struct aout_sys_t * p_sys = (struct aout_sys_t *) p_aout->output.p_sys;
433
434     assert(s);
435
436     PULSE_DEBUG( "Pulse stream state changed");
437
438     switch (pa_stream_get_state(s)) {
439
440         case PA_STREAM_READY:
441         case PA_STREAM_FAILED:
442         case PA_STREAM_TERMINATED:
443             pa_threaded_mainloop_signal(p_sys->mainloop, 0);
444             break;
445
446         case PA_STREAM_UNCONNECTED:
447         case PA_STREAM_CREATING:
448             break;
449     }
450 }
451
452 static void stream_request_cb(pa_stream *s, size_t length, void *userdata) {
453     VLC_UNUSED( s );
454     aout_instance_t *p_aout = (aout_instance_t *)userdata;
455     struct aout_sys_t * p_sys = (struct aout_sys_t *) p_aout->output.p_sys;
456     mtime_t next_date;
457
458     assert(s);
459     assert(p_sys);
460
461     size_t buffer_size = p_sys->buffer_size;
462
463     PULSE_DEBUG( "Pulse stream request %d", length);
464
465     do{
466         aout_buffer_t *   p_buffer = NULL;
467         if(p_sys->started){
468             pa_usec_t latency;
469             int negative;
470             if(pa_stream_get_latency(p_sys->stream, &latency, &negative)<0){
471                 if (pa_context_errno(p_sys->context) != PA_ERR_NODATA) {
472                     msg_Err(p_aout, "pa_stream_get_latency() failed: %s", pa_strerror(pa_context_errno(p_sys->context)));
473                 }
474                 latency = 0;
475
476             }
477
478             PULSE_DEBUG( "Pulse stream request latency=%"PRId64"", latency);
479             next_date = mdate() + latency;
480
481             if(p_sys->start_date < next_date + AOUT_PTS_TOLERANCE ){
482                 p_buffer = aout_OutputNextBuffer( p_aout, next_date, 0);
483             }
484         }
485
486         if ( p_buffer != NULL )
487         {
488             PULSE_DEBUG( "Pulse stream request write buffer %d", p_buffer->i_buffer);
489             pa_stream_write(p_sys->stream, p_buffer->p_buffer, p_buffer->i_buffer, NULL, 0, PA_SEEK_RELATIVE);
490             length -= p_buffer->i_buffer;
491             aout_BufferFree( p_buffer );
492         }
493         else
494         {
495             PULSE_DEBUG( "Pulse stream request write zeroes");
496             void *data = pa_xmalloc(buffer_size);
497             bzero(data, buffer_size);
498             pa_stream_write(p_sys->stream, data, buffer_size, pa_xfree, 0, PA_SEEK_RELATIVE);
499             length -= buffer_size;
500         }
501     }while(length > buffer_size);
502
503     pa_threaded_mainloop_signal(p_sys->mainloop, 0);
504 }
505
506 static void stream_latency_update_cb(pa_stream *s, void *userdata) {
507     VLC_UNUSED( s );
508     aout_instance_t *p_aout = (aout_instance_t *)userdata;
509     struct aout_sys_t * p_sys = (struct aout_sys_t *) p_aout->output.p_sys;
510
511     assert(s);
512
513     PULSE_DEBUG( "Pulse stream latency update");
514
515     pa_threaded_mainloop_signal(p_sys->mainloop, 0);
516 }
517
518 static void success_cb(pa_stream *s, int sucess, void *userdata)
519 {
520     VLC_UNUSED( s );
521     aout_instance_t *p_aout = (aout_instance_t *)userdata;
522     struct aout_sys_t * p_sys = (struct aout_sys_t *) p_aout->output.p_sys;
523
524     VLC_UNUSED(sucess);
525
526     assert(s);
527
528     pa_threaded_mainloop_signal(p_sys->mainloop, 0);
529 }
530
531 #undef PULSE_DEBUG