]> git.sesse.net Git - vlc/blob - modules/access/pulse.c
Qt: use %tmp%/$TMP folder for updates
[vlc] / modules / access / pulse.c
1 /**
2  * \file pulse.c
3  * \brief PulseAudio input plugin for vlc
4  */
5 /*****************************************************************************
6  * Copyright (C) 2011 RĂ©mi Denis-Courmont
7  *
8  * This program is free software; you can redistribute it and/or modify it
9  * under the terms of the GNU Lesser General Public License as published by
10  * the Free Software Foundation; either version 2.1 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 Lesser General Public License for more details.
17  *
18  * You should have received a copy of the GNU Lesser General Public License
19  * along with this program; if not, write to the Free Software Foundation,
20  * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
21  *****************************************************************************/
22
23 #ifdef HAVE_CONFIG_H
24 # include "config.h"
25 #endif
26
27 #include <vlc_common.h>
28 #include <vlc_aout.h>
29 #include <vlc_cpu.h>
30 #include <vlc_demux.h>
31 #include <vlc_plugin.h>
32 #include <pulse/pulseaudio.h>
33 #include "../audio_output/vlcpulse.h"
34
35 #define HELP_TEXT N_( \
36     "Pass pulse:// to open the default PulseAudio source, " \
37     "or pulse://SOURCE to open a specific source named SOURCE.")
38
39 static int Open(vlc_object_t *);
40 static void Close(vlc_object_t *);
41
42 vlc_module_begin ()
43     set_shortname (N_("PulseAudio"))
44     set_description (N_("PulseAudio input"))
45     set_capability ("access_demux", 0)
46     set_category (CAT_INPUT)
47     set_subcategory (SUBCAT_INPUT_ACCESS)
48     set_help (HELP_TEXT)
49
50     add_shortcut ("pulse", "pulseaudio", "pa")
51     set_callbacks (Open, Close)
52 vlc_module_end ()
53
54 struct demux_sys_t
55 {
56     pa_stream *stream; /**< PulseAudio playback stream object */
57     pa_context *context; /**< PulseAudio connection context */
58     pa_threaded_mainloop *mainloop; /**< PulseAudio thread */
59
60     es_out_id_t *es;
61     bool discontinuity; /**< The next block will not follow the last one */
62     unsigned framesize; /**< Byte size of a sample */
63     mtime_t caching; /**< Caching value */
64 };
65
66 /* Stream helpers */
67 static void stream_state_cb(pa_stream *s, void *userdata)
68 {
69     pa_threaded_mainloop *mainloop = userdata;
70
71     switch (pa_stream_get_state(s)) {
72         case PA_STREAM_READY:
73         case PA_STREAM_FAILED:
74         case PA_STREAM_TERMINATED:
75             pa_threaded_mainloop_signal(mainloop, 0);
76         default:
77             break;
78     }
79 }
80
81 static void stream_success_cb (pa_stream *s, int success, void *userdata)
82 {
83     pa_threaded_mainloop *mainloop = userdata;
84
85     pa_threaded_mainloop_signal(mainloop, 0);
86     (void) s;
87     (void) success;
88 }
89
90 static void stream_buffer_attr_cb(pa_stream *s, void *userdata)
91 {
92     demux_t *demux = userdata;
93     const struct pa_buffer_attr *pba = pa_stream_get_buffer_attr(s);
94
95     msg_Dbg(demux, "using buffer metrics: maxlength=%"PRIu32", "
96             "fragsize=%"PRIu32, pba->maxlength, pba->fragsize);
97 }
98
99 static void stream_moved_cb(pa_stream *s, void *userdata)
100 {
101     demux_t *demux = userdata;
102     uint32_t idx = pa_stream_get_device_index(s);
103
104     msg_Dbg(demux, "connected to source %"PRIu32": %s", idx,
105                   pa_stream_get_device_name(s));
106     stream_buffer_attr_cb(s, userdata);
107 }
108
109 static void stream_overflow_cb(pa_stream *s, void *userdata)
110 {
111     demux_t *demux = userdata;
112
113     msg_Err(demux, "overflow");
114     (void) s;
115 }
116
117 static void stream_started_cb(pa_stream *s, void *userdata)
118 {
119     demux_t *demux = userdata;
120
121     msg_Dbg(demux, "started");
122     (void) s;
123 }
124
125 static void stream_suspended_cb(pa_stream *s, void *userdata)
126 {
127     demux_t *demux = userdata;
128
129     msg_Dbg(demux, "suspended");
130     (void) s;
131 }
132
133 static void stream_underflow_cb(pa_stream *s, void *userdata)
134 {
135     demux_t *demux = userdata;
136
137     msg_Dbg(demux, "underflow");
138     (void) s;
139 }
140
141 static int stream_wait(pa_stream *stream, pa_threaded_mainloop *mainloop)
142 {
143     pa_stream_state_t state;
144
145     while ((state = pa_stream_get_state(stream)) != PA_STREAM_READY) {
146         if (state == PA_STREAM_FAILED || state == PA_STREAM_TERMINATED)
147             return -1;
148         pa_threaded_mainloop_wait(mainloop);
149     }
150     return 0;
151 }
152
153 static void stream_read_cb(pa_stream *s, size_t length, void *userdata)
154 {
155     demux_t *demux = userdata;
156     demux_sys_t *sys = demux->p_sys;
157     const void *ptr;
158     unsigned samples = length / sys->framesize;
159
160     if (pa_stream_peek(s, &ptr, &length) < 0) {
161         vlc_pa_error(demux, "cannot peek stream", sys->context);
162         return;
163     }
164
165     mtime_t pts = mdate();
166     pa_usec_t latency;
167     int negative;
168
169     if (pa_stream_get_latency(s, &latency, &negative) < 0) {
170         vlc_pa_error(demux, "cannot determine latency", sys->context);
171         return;
172     }
173     if (negative)
174         pts += latency;
175     else
176         pts -= latency;
177
178     es_out_Control(demux->out, ES_OUT_SET_PCR, pts);
179     if (unlikely(sys->es == NULL))
180         goto race;
181
182     block_t *block = block_Alloc(length);
183     if (likely(block != NULL)) {
184         vlc_memcpy(block->p_buffer, ptr, length);
185         block->i_nb_samples = samples;
186         block->i_dts = block->i_pts = pts;
187         if (sys->discontinuity) {
188             block->i_flags |= BLOCK_FLAG_DISCONTINUITY;
189             sys->discontinuity = false;
190         }
191
192         es_out_Send(demux->out, sys->es, block);
193     } else
194         sys->discontinuity = true;
195 race:
196     pa_stream_drop(s);
197 }
198
199 static int Control(demux_t *demux, int query, va_list ap)
200 {
201     demux_sys_t *sys = demux->p_sys;
202
203     switch (query)
204     {
205         case DEMUX_GET_TIME:
206         {
207             pa_usec_t us;
208
209             if (pa_stream_get_time(sys->stream, &us) < 0)
210                 return VLC_EGENERIC;
211             *(va_arg(ap, int64_t *)) = us;
212             break;
213         }
214
215         //case DEMUX_SET_NEXT_DEMUX_TIME: TODO
216         //case DEMUX_GET_META TODO
217
218         case DEMUX_GET_PTS_DELAY:
219             *(va_arg(ap, int64_t *)) = sys->caching;
220             break;
221
222         case DEMUX_HAS_UNSUPPORTED_META:
223         case DEMUX_CAN_RECORD:
224         case DEMUX_CAN_PAUSE:
225         case DEMUX_CAN_CONTROL_PACE:
226         case DEMUX_CAN_CONTROL_RATE:
227         case DEMUX_CAN_SEEK:
228             *(va_arg(ap, bool *)) = false;
229             break;
230
231         default:
232             return VLC_EGENERIC;
233     }
234
235     return VLC_SUCCESS;
236 }
237
238 /** PulseAudio sample (PCM) format to VLC codec */
239 static const vlc_fourcc_t fourccs[] = {
240     [PA_SAMPLE_U8] =        VLC_CODEC_U8,
241     [PA_SAMPLE_ALAW] =      VLC_CODEC_ALAW,
242     [PA_SAMPLE_ULAW] =      VLC_CODEC_MULAW,
243     [PA_SAMPLE_S16LE] =     VLC_CODEC_S16L,
244     [PA_SAMPLE_S16BE] =     VLC_CODEC_S16B,
245     [PA_SAMPLE_FLOAT32LE] = VLC_CODEC_F32L,
246     [PA_SAMPLE_FLOAT32BE] = VLC_CODEC_F32B,
247     [PA_SAMPLE_S32LE] =     VLC_CODEC_S32L,
248     [PA_SAMPLE_S32BE] =     VLC_CODEC_S32B,
249     [PA_SAMPLE_S24LE] =     VLC_CODEC_S24L,
250     [PA_SAMPLE_S24BE] =     VLC_CODEC_S24B,
251     [PA_SAMPLE_S24_32LE] =  0,
252     [PA_SAMPLE_S24_32BE] =  0,
253 };
254
255 static int Open(vlc_object_t *obj)
256 {
257     demux_t *demux = (demux_t *)obj;
258
259     demux_sys_t *sys = malloc(sizeof (*sys));
260     if (unlikely(sys == NULL))
261         return VLC_ENOMEM;
262
263     sys->context = vlc_pa_connect(obj, &sys->mainloop);
264     if (sys->context == NULL) {
265         free(sys);
266         return VLC_EGENERIC;
267     }
268
269     sys->stream = NULL;
270     sys->es = NULL;
271     sys->discontinuity = false;
272     sys->caching = INT64_C(1000) * var_InheritInteger(obj, "live-caching");
273     demux->p_sys = sys;
274
275     /* Stream parameters */
276     struct pa_sample_spec ss;
277     ss.format = HAVE_FPU ? PA_SAMPLE_FLOAT32NE : PA_SAMPLE_S16NE;
278     ss.rate = 48000;
279     ss.channels = 2;
280     assert(pa_sample_spec_valid(&ss));
281
282     struct pa_channel_map map;
283     map.channels = 2;
284     map.map[0] = PA_CHANNEL_POSITION_FRONT_LEFT;
285     map.map[1] = PA_CHANNEL_POSITION_FRONT_RIGHT;
286     assert(pa_channel_map_valid(&map));
287
288     const pa_stream_flags_t flags = PA_STREAM_INTERPOLATE_TIMING
289                                   | PA_STREAM_AUTO_TIMING_UPDATE
290                                   | PA_STREAM_FIX_FORMAT
291                                   | PA_STREAM_FIX_RATE
292                                   /*| PA_STREAM_FIX_CHANNELS*/;
293
294     const char *dev = NULL;
295     if (demux->psz_location != NULL && demux->psz_location[0] != '\0')
296         dev = demux->psz_location;
297
298     struct pa_buffer_attr attr = {
299         .maxlength = -1,
300         .fragsize = pa_usec_to_bytes(sys->caching, &ss) / 2,
301     };
302
303     es_format_t fmt;
304
305     /* Create record stream */
306     pa_stream *s;
307     pa_operation *op;
308
309     pa_threaded_mainloop_lock(sys->mainloop);
310     s = pa_stream_new(sys->context, "audio stream", &ss, &map);
311     if (s == NULL)
312         goto error;
313
314     sys->stream = s;
315     pa_stream_set_state_callback(s, stream_state_cb, sys->mainloop);
316     pa_stream_set_read_callback(s, stream_read_cb, demux);
317     pa_stream_set_buffer_attr_callback(s, stream_buffer_attr_cb, demux);
318     pa_stream_set_moved_callback(s, stream_moved_cb, demux);
319     pa_stream_set_overflow_callback(s, stream_overflow_cb, demux);
320     pa_stream_set_started_callback(s, stream_started_cb, demux);
321     pa_stream_set_suspended_callback(s, stream_suspended_cb, demux);
322     pa_stream_set_underflow_callback(s, stream_underflow_cb, demux);
323
324     if (pa_stream_connect_record(s, dev, &attr, flags) < 0
325      || stream_wait(s, sys->mainloop)) {
326         vlc_pa_error(obj, "cannot connect record stream", sys->context);
327         goto error;
328     }
329
330     /* The ES should be initialized before stream_read_cb(), but how? */
331     const struct pa_sample_spec *pss = pa_stream_get_sample_spec(s);
332     if ((unsigned)pss->format >= sizeof (fourccs) / sizeof (fourccs[0])) {
333         msg_Err(obj, "unknown PulseAudio sample format %u",
334                 (unsigned)pss->format);
335         goto error;
336     }
337
338     vlc_fourcc_t format = fourccs[pss->format];
339     if (format == 0) { /* FIXME: should renegotiate something else */
340         msg_Err(obj, "unsupported PulseAudio sample format %u",
341                 (unsigned)pss->format);
342         goto error;
343     }
344
345     es_format_Init(&fmt, AUDIO_ES, format);
346     fmt.audio.i_physical_channels = fmt.audio.i_original_channels =
347         AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT;
348     fmt.audio.i_channels = ss.channels;
349     fmt.audio.i_rate = pss->rate;
350     fmt.audio.i_bitspersample = aout_BitsPerSample(format);
351     fmt.audio.i_blockalign = fmt.audio.i_bitspersample * ss.channels / 8;
352     fmt.i_bitrate = fmt.audio.i_bitspersample * ss.channels * pss->rate;
353     sys->framesize = fmt.audio.i_blockalign;
354     sys->es = es_out_Add (demux->out, &fmt);
355
356     /* Update the buffer attributes according to actual format */
357     attr.fragsize = pa_usec_to_bytes(sys->caching, pss) / 2;
358     op = pa_stream_set_buffer_attr(s, &attr, stream_success_cb, sys->mainloop);
359     if (likely(op != NULL)) {
360         while (pa_operation_get_state(op) == PA_OPERATION_RUNNING)
361             pa_threaded_mainloop_wait(sys->mainloop);
362         pa_operation_unref(op);
363     }
364     stream_buffer_attr_cb(s, demux);
365     pa_threaded_mainloop_unlock(sys->mainloop);
366
367     demux->pf_demux = NULL;
368     demux->pf_control = Control;
369     return VLC_SUCCESS;
370
371 error:
372     pa_threaded_mainloop_unlock(sys->mainloop);
373     Close(obj);
374     return VLC_EGENERIC;
375 }
376
377 static void Close (vlc_object_t *obj)
378 {
379     demux_t *demux = (demux_t *)obj;
380     demux_sys_t *sys = demux->p_sys;
381     pa_stream *s = sys->stream;
382
383     if (likely(s != NULL)) {
384         pa_threaded_mainloop_lock(sys->mainloop);
385         pa_stream_disconnect(s);
386         pa_stream_set_state_callback(s, NULL, NULL);
387         pa_stream_set_read_callback(s, NULL, NULL);
388         pa_stream_set_buffer_attr_callback(s, NULL, NULL);
389         pa_stream_set_moved_callback(s, NULL, NULL);
390         pa_stream_set_overflow_callback(s, NULL, NULL);
391         pa_stream_set_started_callback(s, NULL, NULL);
392         pa_stream_set_suspended_callback(s, NULL, NULL);
393         pa_stream_set_underflow_callback(s, NULL, NULL);
394         pa_stream_unref(s);
395         pa_threaded_mainloop_unlock(sys->mainloop);
396     }
397
398     vlc_pa_disconnect(obj, sys->context, sys->mainloop);
399     free(sys);
400 }