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