mux:ts: convert vlc_tick_t to seconds explicitly using SEC_FROM_VLC_TICK()
[vlc.git] / modules / access / pulse.c
blob35d1f60c1134778acf7925b6d310cec51255f724
1 /**
2 * \file pulse.c
3 * \brief PulseAudio input plugin for vlc
4 */
5 /*****************************************************************************
6 * Copyright (C) 2011 RĂ©mi Denis-Courmont
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.
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.
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 *****************************************************************************/
23 #ifdef HAVE_CONFIG_H
24 # include "config.h"
25 #endif
27 #include <vlc_common.h>
28 #include <vlc_aout.h>
29 #include <vlc_demux.h>
30 #include <vlc_plugin.h>
31 #include <pulse/pulseaudio.h>
32 #include "audio_output/vlcpulse.h"
34 #define HELP_TEXT N_( \
35 "Pass pulse:// to open the default PulseAudio source, " \
36 "or pulse://SOURCE to open a specific source named SOURCE.")
38 static int Open(vlc_object_t *);
39 static void Close(vlc_object_t *);
41 vlc_module_begin ()
42 set_shortname (N_("PulseAudio"))
43 set_description (N_("PulseAudio input"))
44 set_capability ("access", 0)
45 set_category (CAT_INPUT)
46 set_subcategory (SUBCAT_INPUT_ACCESS)
47 set_help (HELP_TEXT)
49 add_shortcut ("pulse", "pulseaudio", "pa")
50 set_callbacks (Open, Close)
51 vlc_module_end ()
53 typedef struct
55 pa_stream *stream; /**< PulseAudio playback stream object */
56 pa_context *context; /**< PulseAudio connection context */
57 pa_threaded_mainloop *mainloop; /**< PulseAudio thread */
59 es_out_id_t *es;
60 bool discontinuity; /**< The next block will not follow the last one */
61 unsigned framesize; /**< Byte size of a sample */
62 vlc_tick_t caching; /**< Caching value */
63 } demux_sys_t;
65 /* Stream helpers */
66 static void stream_state_cb(pa_stream *s, void *userdata)
68 pa_threaded_mainloop *mainloop = userdata;
70 switch (pa_stream_get_state(s)) {
71 case PA_STREAM_READY:
72 case PA_STREAM_FAILED:
73 case PA_STREAM_TERMINATED:
74 pa_threaded_mainloop_signal(mainloop, 0);
75 default:
76 break;
80 static void stream_success_cb (pa_stream *s, int success, void *userdata)
82 pa_threaded_mainloop *mainloop = userdata;
84 pa_threaded_mainloop_signal(mainloop, 0);
85 (void) s;
86 (void) success;
89 static void stream_buffer_attr_cb(pa_stream *s, void *userdata)
91 demux_t *demux = userdata;
92 const struct pa_buffer_attr *pba = pa_stream_get_buffer_attr(s);
94 msg_Dbg(demux, "using buffer metrics: maxlength=%"PRIu32", "
95 "fragsize=%"PRIu32, pba->maxlength, pba->fragsize);
98 static void stream_moved_cb(pa_stream *s, void *userdata)
100 demux_t *demux = userdata;
101 uint32_t idx = pa_stream_get_device_index(s);
103 msg_Dbg(demux, "connected to source %"PRIu32": %s", idx,
104 pa_stream_get_device_name(s));
105 stream_buffer_attr_cb(s, userdata);
108 static void stream_overflow_cb(pa_stream *s, void *userdata)
110 demux_t *demux = userdata;
112 msg_Err(demux, "overflow");
113 (void) s;
116 static void stream_started_cb(pa_stream *s, void *userdata)
118 demux_t *demux = userdata;
120 msg_Dbg(demux, "started");
121 (void) s;
124 static void stream_suspended_cb(pa_stream *s, void *userdata)
126 demux_t *demux = userdata;
128 msg_Dbg(demux, "suspended");
129 (void) s;
132 static void stream_underflow_cb(pa_stream *s, void *userdata)
134 demux_t *demux = userdata;
136 msg_Dbg(demux, "underflow");
137 (void) s;
140 static int stream_wait(pa_stream *stream, pa_threaded_mainloop *mainloop)
142 pa_stream_state_t state;
144 while ((state = pa_stream_get_state(stream)) != PA_STREAM_READY) {
145 if (state == PA_STREAM_FAILED || state == PA_STREAM_TERMINATED)
146 return -1;
147 pa_threaded_mainloop_wait(mainloop);
149 return 0;
152 static void stream_read_cb(pa_stream *s, size_t length, void *userdata)
154 demux_t *demux = userdata;
155 demux_sys_t *sys = demux->p_sys;
156 const void *ptr;
157 unsigned samples = length / sys->framesize;
159 if (pa_stream_peek(s, &ptr, &length) < 0) {
160 vlc_pa_error(demux, "cannot peek stream", sys->context);
161 return;
164 vlc_tick_t pts = vlc_tick_now();
165 pa_usec_t latency;
166 int negative;
168 if (pa_stream_get_latency(s, &latency, &negative) < 0) {
169 vlc_pa_error(demux, "cannot determine latency", sys->context);
170 return;
172 if (negative)
173 pts += latency;
174 else
175 pts -= latency;
177 es_out_SetPCR(demux->out, pts);
178 if (unlikely(sys->es == NULL))
179 goto race;
181 block_t *block = block_Alloc(length);
182 if (likely(block != NULL)) {
183 memcpy(block->p_buffer, ptr, length);
184 block->i_nb_samples = samples;
185 block->i_dts = block->i_pts = pts;
186 if (sys->discontinuity) {
187 block->i_flags |= BLOCK_FLAG_DISCONTINUITY;
188 sys->discontinuity = false;
191 es_out_Send(demux->out, sys->es, block);
192 } else
193 sys->discontinuity = true;
194 race:
195 pa_stream_drop(s);
198 static int Control(demux_t *demux, int query, va_list ap)
200 demux_sys_t *sys = demux->p_sys;
202 switch (query)
204 case DEMUX_GET_TIME:
206 pa_usec_t us;
208 if (pa_stream_get_time(sys->stream, &us) < 0)
209 return VLC_EGENERIC;
210 *(va_arg(ap, int64_t *)) = us;
211 break;
214 //case DEMUX_SET_NEXT_DEMUX_TIME: TODO
215 //case DEMUX_GET_META TODO
217 case DEMUX_GET_PTS_DELAY:
218 *(va_arg(ap, int64_t *)) = sys->caching;
219 break;
221 case DEMUX_HAS_UNSUPPORTED_META:
222 case DEMUX_CAN_RECORD:
223 case DEMUX_CAN_PAUSE:
224 case DEMUX_CAN_CONTROL_PACE:
225 case DEMUX_CAN_CONTROL_RATE:
226 case DEMUX_CAN_SEEK:
227 *(va_arg(ap, bool *)) = false;
228 break;
230 default:
231 return VLC_EGENERIC;
234 return VLC_SUCCESS;
237 /** PulseAudio sample (PCM) format to VLC codec */
238 static const vlc_fourcc_t fourccs[] = {
239 [PA_SAMPLE_U8] = VLC_CODEC_U8,
240 [PA_SAMPLE_ALAW] = VLC_CODEC_ALAW,
241 [PA_SAMPLE_ULAW] = VLC_CODEC_MULAW,
242 [PA_SAMPLE_S16LE] = VLC_CODEC_S16L,
243 [PA_SAMPLE_S16BE] = VLC_CODEC_S16B,
244 [PA_SAMPLE_FLOAT32LE] = VLC_CODEC_F32L,
245 [PA_SAMPLE_FLOAT32BE] = VLC_CODEC_F32B,
246 [PA_SAMPLE_S32LE] = VLC_CODEC_S32L,
247 [PA_SAMPLE_S32BE] = VLC_CODEC_S32B,
248 [PA_SAMPLE_S24LE] = VLC_CODEC_S24L,
249 [PA_SAMPLE_S24BE] = VLC_CODEC_S24B,
250 [PA_SAMPLE_S24_32LE] = VLC_CODEC_S24L32,
251 [PA_SAMPLE_S24_32BE] = VLC_CODEC_S24B32,
254 static int Open(vlc_object_t *obj)
256 demux_t *demux = (demux_t *)obj;
258 if (demux->out == NULL)
259 return VLC_EGENERIC;
261 demux_sys_t *sys = vlc_obj_malloc(obj, sizeof (*sys));
262 if (unlikely(sys == NULL))
263 return VLC_ENOMEM;
265 sys->context = vlc_pa_connect(obj, &sys->mainloop);
266 if (sys->context == NULL)
267 return VLC_EGENERIC;
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;
275 /* Stream parameters */
276 struct pa_sample_spec ss;
277 ss.format = PA_SAMPLE_S16NE;
278 ss.rate = 48000;
279 ss.channels = 2;
280 assert(pa_sample_spec_valid(&ss));
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));
288 const pa_stream_flags_t flags = PA_STREAM_INTERPOLATE_TIMING
289 | PA_STREAM_AUTO_TIMING_UPDATE
290 | PA_STREAM_ADJUST_LATENCY
291 | PA_STREAM_FIX_FORMAT
292 | PA_STREAM_FIX_RATE
293 /*| PA_STREAM_FIX_CHANNELS*/;
295 const char *dev = NULL;
296 if (demux->psz_location != NULL && demux->psz_location[0] != '\0')
297 dev = demux->psz_location;
299 struct pa_buffer_attr attr = {
300 .maxlength = -1,
301 .fragsize = pa_usec_to_bytes(sys->caching, &ss) / 2,
304 es_format_t fmt;
306 /* Create record stream */
307 pa_stream *s;
308 pa_operation *op;
310 pa_threaded_mainloop_lock(sys->mainloop);
311 s = pa_stream_new(sys->context, "audio stream", &ss, &map);
312 if (s == NULL)
313 goto error;
315 sys->stream = s;
316 pa_stream_set_state_callback(s, stream_state_cb, sys->mainloop);
317 pa_stream_set_read_callback(s, stream_read_cb, demux);
318 pa_stream_set_buffer_attr_callback(s, stream_buffer_attr_cb, demux);
319 pa_stream_set_moved_callback(s, stream_moved_cb, demux);
320 pa_stream_set_overflow_callback(s, stream_overflow_cb, demux);
321 pa_stream_set_started_callback(s, stream_started_cb, demux);
322 pa_stream_set_suspended_callback(s, stream_suspended_cb, demux);
323 pa_stream_set_underflow_callback(s, stream_underflow_cb, demux);
325 if (pa_stream_connect_record(s, dev, &attr, flags) < 0
326 || stream_wait(s, sys->mainloop)) {
327 vlc_pa_error(obj, "cannot connect record stream", sys->context);
328 goto error;
331 /* The ES should be initialized before stream_read_cb(), but how? */
332 const struct pa_sample_spec *pss = pa_stream_get_sample_spec(s);
333 if ((unsigned)pss->format >= sizeof (fourccs) / sizeof (fourccs[0])) {
334 msg_Err(obj, "unknown PulseAudio sample format %u",
335 (unsigned)pss->format);
336 goto error;
339 vlc_fourcc_t format = fourccs[pss->format];
340 if (format == 0) { /* FIXME: should renegotiate something else */
341 msg_Err(obj, "unsupported PulseAudio sample format %u",
342 (unsigned)pss->format);
343 goto error;
346 es_format_Init(&fmt, AUDIO_ES, format);
347 fmt.audio.i_physical_channels = 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);
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);
364 stream_buffer_attr_cb(s, demux);
365 pa_threaded_mainloop_unlock(sys->mainloop);
367 demux->pf_demux = NULL;
368 demux->pf_control = Control;
369 return VLC_SUCCESS;
371 error:
372 pa_threaded_mainloop_unlock(sys->mainloop);
373 Close(obj);
374 return VLC_EGENERIC;
377 static void Close (vlc_object_t *obj)
379 demux_t *demux = (demux_t *)obj;
380 demux_sys_t *sys = demux->p_sys;
381 pa_stream *s = sys->stream;
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);
398 vlc_pa_disconnect(obj, sys->context, sys->mainloop);