3 * \brief PulseAudio input plugin for vlc
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 *****************************************************************************/
27 #include <vlc_common.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
*);
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
)
49 add_shortcut ("pulse", "pulseaudio", "pa")
50 set_callbacks (Open
, Close
)
55 pa_stream
*stream
; /**< PulseAudio playback stream object */
56 pa_context
*context
; /**< PulseAudio connection context */
57 pa_threaded_mainloop
*mainloop
; /**< PulseAudio thread */
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 */
66 static void stream_state_cb(pa_stream
*s
, void *userdata
)
68 pa_threaded_mainloop
*mainloop
= userdata
;
70 switch (pa_stream_get_state(s
)) {
72 case PA_STREAM_FAILED
:
73 case PA_STREAM_TERMINATED
:
74 pa_threaded_mainloop_signal(mainloop
, 0);
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);
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");
116 static void stream_started_cb(pa_stream
*s
, void *userdata
)
118 demux_t
*demux
= userdata
;
120 msg_Dbg(demux
, "started");
124 static void stream_suspended_cb(pa_stream
*s
, void *userdata
)
126 demux_t
*demux
= userdata
;
128 msg_Dbg(demux
, "suspended");
132 static void stream_underflow_cb(pa_stream
*s
, void *userdata
)
134 demux_t
*demux
= userdata
;
136 msg_Dbg(demux
, "underflow");
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
)
147 pa_threaded_mainloop_wait(mainloop
);
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
;
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
);
164 vlc_tick_t pts
= vlc_tick_now();
168 if (pa_stream_get_latency(s
, &latency
, &negative
) < 0) {
169 vlc_pa_error(demux
, "cannot determine latency", sys
->context
);
177 es_out_SetPCR(demux
->out
, pts
);
178 if (unlikely(sys
->es
== NULL
))
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
);
193 sys
->discontinuity
= true;
198 static int Control(demux_t
*demux
, int query
, va_list ap
)
200 demux_sys_t
*sys
= demux
->p_sys
;
208 if (pa_stream_get_time(sys
->stream
, &us
) < 0)
210 *(va_arg(ap
, int64_t *)) = us
;
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
;
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
:
227 *(va_arg(ap
, bool *)) = false;
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
)
261 demux_sys_t
*sys
= vlc_obj_malloc(obj
, sizeof (*sys
));
262 if (unlikely(sys
== NULL
))
265 sys
->context
= vlc_pa_connect(obj
, &sys
->mainloop
);
266 if (sys
->context
== NULL
)
271 sys
->discontinuity
= false;
272 sys
->caching
= INT64_C(1000) * var_InheritInteger(obj
, "live-caching");
275 /* Stream parameters */
276 struct pa_sample_spec ss
;
277 ss
.format
= PA_SAMPLE_S16NE
;
280 assert(pa_sample_spec_valid(&ss
));
282 struct pa_channel_map map
;
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
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
= {
301 .fragsize
= pa_usec_to_bytes(sys
->caching
, &ss
) / 2,
306 /* Create record stream */
310 pa_threaded_mainloop_lock(sys
->mainloop
);
311 s
= pa_stream_new(sys
->context
, "audio stream", &ss
, &map
);
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
);
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
);
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
);
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
;
372 pa_threaded_mainloop_unlock(sys
->mainloop
);
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
);
395 pa_threaded_mainloop_unlock(sys
->mainloop
);
398 vlc_pa_disconnect(obj
, sys
->context
, sys
->mainloop
);