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