1 /*****************************************************************************
2 * pulse.c : Pulseaudio output plugin for vlc
3 *****************************************************************************
4 * Copyright (C) 2008 VLC authors and VideoLAN
5 * Copyright (C) 2009-2011 RĂ©mi Denis-Courmont
7 * Authors: Martin Hamrle <hamrle @ post . cz>
9 * This program is free software; you can redistribute it and/or modify it
10 * under the terms of the GNU Lesser General Public License as published by
11 * the Free Software Foundation; either version 2.1 of the License, or
12 * (at your option) any later version.
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU Lesser General Public License for more details.
19 * You should have received a copy of the GNU Lesser General Public License
20 * along with this program; if not, write to the Free Software Foundation,
21 * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
22 *****************************************************************************/
29 #include <vlc_common.h>
30 #include <vlc_plugin.h>
34 #include <pulse/pulseaudio.h>
35 #include "audio_output/vlcpulse.h"
37 static int Open ( vlc_object_t * );
38 static void Close ( vlc_object_t * );
41 set_shortname( "PulseAudio" )
42 set_description( N_("Pulseaudio audio output") )
43 set_capability( "audio output", 160 )
44 set_category( CAT_AUDIO )
45 set_subcategory( SUBCAT_AUDIO_AOUT )
46 add_shortcut( "pulseaudio", "pa" )
47 set_callbacks( Open, Close )
51 * Be careful what you do when the PulseAudio mainloop is held, which is to say
52 * within PulseAudio callbacks, or after pa_threaded_mainloop_lock().
53 * In particular, a VLC variable callback cannot be triggered nor deleted with
54 * the PulseAudio mainloop lock held, if the callback acquires the lock. */
65 pa_stream *stream; /**< PulseAudio playback stream object */
66 pa_context *context; /**< PulseAudio connection context */
67 pa_threaded_mainloop *mainloop; /**< PulseAudio thread */
68 pa_time_event *trigger; /**< Deferred stream trigger */
69 pa_cvolume cvolume; /**< actual sink input volume */
70 mtime_t first_pts; /**< Play time of buffer start */
72 pa_volume_t volume_force; /**< Forced volume (stream must be NULL) */
73 pa_stream_flags_t flags_force; /**< Forced flags (stream must be NULL) */
74 char *sink_force; /**< Forced sink name (stream must be NULL) */
76 struct sink *sinks; /**< Locally-cached list of sinks */
79 static void VolumeReport(audio_output_t *aout)
81 aout_sys_t *sys = aout->sys;
82 pa_volume_t volume = pa_cvolume_max(&sys->cvolume);
84 aout_VolumeReport(aout, (float)volume / PA_VOLUME_NORM);
88 static void sink_add_cb(pa_context *ctx, const pa_sink_info *i, int eol,
91 audio_output_t *aout = userdata;
92 aout_sys_t *sys = aout->sys;
96 pa_threaded_mainloop_signal(sys->mainloop, 0);
101 msg_Dbg(aout, "adding sink %"PRIu32": %s (%s)", i->index, i->name,
103 aout_HotplugReport(aout, i->name, i->description);
105 size_t namelen = strlen(i->name);
106 struct sink *sink = malloc(sizeof (*sink) + namelen);
107 if (unlikely(sink == NULL))
110 sink->next = sys->sinks;
111 sink->index = i->index;
112 memcpy(sink->name, i->name, namelen + 1);
116 static void sink_mod_cb(pa_context *ctx, const pa_sink_info *i, int eol,
119 audio_output_t *aout = userdata;
125 msg_Dbg(aout, "changing sink %"PRIu32": %s (%s)", i->index, i->name,
127 aout_HotplugReport(aout, i->name, i->description);
130 static void sink_del(uint32_t index, audio_output_t *aout)
132 aout_sys_t *sys = aout->sys;
133 struct sink **pp = &sys->sinks, *sink;
135 msg_Dbg(aout, "removing sink %"PRIu32, index);
137 while ((sink = *pp) != NULL)
138 if (sink->index == index)
141 aout_HotplugReport(aout, sink->name, NULL);
148 static void sink_event(pa_context *ctx, unsigned type, uint32_t idx,
149 audio_output_t *aout)
151 pa_operation *op = NULL;
155 case PA_SUBSCRIPTION_EVENT_NEW:
156 op = pa_context_get_sink_info_by_index(ctx, idx, sink_add_cb,
159 case PA_SUBSCRIPTION_EVENT_CHANGE:
160 op = pa_context_get_sink_info_by_index(ctx, idx, sink_mod_cb,
163 case PA_SUBSCRIPTION_EVENT_REMOVE:
168 pa_operation_unref(op);
172 /*** Latency management and lip synchronization ***/
173 static void stream_start_now(pa_stream *s, audio_output_t *aout)
177 assert (aout->sys->trigger == NULL);
179 op = pa_stream_cork(s, 0, NULL, NULL);
181 pa_operation_unref(op);
182 op = pa_stream_trigger(s, NULL, NULL);
183 if (likely(op != NULL))
184 pa_operation_unref(op);
187 static void stream_stop(pa_stream *s, audio_output_t *aout)
189 aout_sys_t *sys = aout->sys;
192 if (sys->trigger != NULL) {
193 vlc_pa_rttime_free(sys->mainloop, sys->trigger);
197 op = pa_stream_cork(s, 1, NULL, NULL);
199 pa_operation_unref(op);
202 static void stream_trigger_cb(pa_mainloop_api *api, pa_time_event *e,
203 const struct timeval *tv, void *userdata)
205 audio_output_t *aout = userdata;
206 aout_sys_t *sys = aout->sys;
208 assert (sys->trigger == e);
210 msg_Dbg(aout, "starting deferred");
211 vlc_pa_rttime_free(sys->mainloop, sys->trigger);
213 stream_start_now(sys->stream, aout);
214 (void) api; (void) e; (void) tv;
218 * Starts or resumes the playback stream.
219 * Tries start playing back audio samples at the most accurate time
220 * in order to minimize desync and resampling during early playback.
221 * @note PulseAudio lock required.
223 static void stream_start(pa_stream *s, audio_output_t *aout)
225 aout_sys_t *sys = aout->sys;
228 assert (sys->first_pts != VLC_TS_INVALID);
230 if (sys->trigger != NULL) {
231 vlc_pa_rttime_free(sys->mainloop, sys->trigger);
235 delta = vlc_pa_get_latency(aout, sys->context, s);
236 if (unlikely(delta == VLC_TS_INVALID)) {
237 msg_Dbg(aout, "cannot synchronize start");
238 delta = 0; /* screwed */
241 delta = (sys->first_pts - mdate()) - delta;
243 msg_Dbg(aout, "deferring start (%"PRId64" us)", delta);
244 delta += pa_rtclock_now();
245 sys->trigger = pa_context_rttime_new(sys->context, delta,
246 stream_trigger_cb, aout);
248 msg_Warn(aout, "starting late (%"PRId64" us)", delta);
249 stream_start_now(s, aout);
253 static void stream_latency_cb(pa_stream *s, void *userdata)
255 audio_output_t *aout = userdata;
256 aout_sys_t *sys = aout->sys;
258 /* This callback is _never_ called while paused. */
259 if (sys->first_pts == VLC_TS_INVALID)
260 return; /* nothing to do if buffers are (still) empty */
261 if (pa_stream_is_corked(s) > 0)
262 stream_start(s, aout);
266 /*** Stream helpers ***/
267 static void stream_state_cb(pa_stream *s, void *userdata)
269 pa_threaded_mainloop *mainloop = userdata;
271 switch (pa_stream_get_state(s)) {
272 case PA_STREAM_READY:
273 case PA_STREAM_FAILED:
274 case PA_STREAM_TERMINATED:
275 pa_threaded_mainloop_signal(mainloop, 0);
281 static void stream_buffer_attr_cb(pa_stream *s, void *userdata)
283 audio_output_t *aout = userdata;
284 const pa_buffer_attr *pba = pa_stream_get_buffer_attr(s);
286 msg_Dbg(aout, "changed buffer metrics: maxlength=%u, tlength=%u, "
287 "prebuf=%u, minreq=%u",
288 pba->maxlength, pba->tlength, pba->prebuf, pba->minreq);
291 static void stream_event_cb(pa_stream *s, const char *name, pa_proplist *pl,
294 audio_output_t *aout = userdata;
296 if (!strcmp(name, PA_STREAM_EVENT_REQUEST_CORK))
297 aout_PolicyReport(aout, true);
299 if (!strcmp(name, PA_STREAM_EVENT_REQUEST_UNCORK))
300 aout_PolicyReport(aout, false);
302 /* FIXME: expose aout_Restart() directly */
303 if (!strcmp(name, PA_STREAM_EVENT_FORMAT_LOST)) {
304 msg_Dbg (aout, "format lost");
305 aout_RestartRequest (aout, AOUT_RESTART_OUTPUT);
307 msg_Warn (aout, "unhandled stream event \"%s\"", name);
312 static void stream_moved_cb(pa_stream *s, void *userdata)
314 audio_output_t *aout = userdata;
315 const char *name = pa_stream_get_device_name(s);
317 msg_Dbg(aout, "connected to sink %s", name);
318 aout_DeviceReport(aout, name);
321 static void stream_overflow_cb(pa_stream *s, void *userdata)
323 audio_output_t *aout = userdata;
324 aout_sys_t *sys = aout->sys;
327 msg_Err(aout, "overflow, flushing");
328 op = pa_stream_flush(s, NULL, NULL);
329 if (unlikely(op == NULL))
331 pa_operation_unref(op);
332 sys->first_pts = VLC_TS_INVALID;
335 static void stream_started_cb(pa_stream *s, void *userdata)
337 audio_output_t *aout = userdata;
339 msg_Dbg(aout, "started");
343 static void stream_suspended_cb(pa_stream *s, void *userdata)
345 audio_output_t *aout = userdata;
347 msg_Dbg(aout, "suspended");
351 static void stream_underflow_cb(pa_stream *s, void *userdata)
353 audio_output_t *aout = userdata;
355 msg_Dbg(aout, "underflow");
359 static int stream_wait(pa_stream *stream, pa_threaded_mainloop *mainloop)
361 pa_stream_state_t state;
363 while ((state = pa_stream_get_state(stream)) != PA_STREAM_READY) {
364 if (state == PA_STREAM_FAILED || state == PA_STREAM_TERMINATED)
366 pa_threaded_mainloop_wait(mainloop);
373 static void sink_input_info_cb(pa_context *ctx, const pa_sink_input_info *i,
374 int eol, void *userdata)
376 audio_output_t *aout = userdata;
377 aout_sys_t *sys = aout->sys;
383 sys->cvolume = i->volume; /* cache volume for balance preservation */
385 aout_MuteReport(aout, i->mute);
388 static void sink_input_event(pa_context *ctx,
389 pa_subscription_event_type_t type,
390 uint32_t idx, audio_output_t *aout)
394 /* Gee... PA will not provide the infos directly in the event. */
397 case PA_SUBSCRIPTION_EVENT_REMOVE:
398 msg_Err(aout, "sink input killed!");
402 op = pa_context_get_sink_input_info(ctx, idx, sink_input_info_cb,
404 if (likely(op != NULL))
405 pa_operation_unref(op);
412 static void context_cb(pa_context *ctx, pa_subscription_event_type_t type,
413 uint32_t idx, void *userdata)
415 audio_output_t *aout = userdata;
416 aout_sys_t *sys = aout->sys;
417 unsigned facility = type & PA_SUBSCRIPTION_EVENT_FACILITY_MASK;
419 type &= PA_SUBSCRIPTION_EVENT_TYPE_MASK;
422 case PA_SUBSCRIPTION_EVENT_SINK:
423 sink_event(ctx, type, idx, userdata);
426 case PA_SUBSCRIPTION_EVENT_SINK_INPUT:
427 /* only interested in our sink input */
428 if (sys->stream != NULL && idx == pa_stream_get_index(sys->stream))
429 sink_input_event(ctx, type, idx, userdata);
432 default: /* unsubscribed facility?! */
433 vlc_assert_unreachable();
438 /*** VLC audio output callbacks ***/
440 static int TimeGet(audio_output_t *aout, mtime_t *restrict delay)
442 aout_sys_t *sys = aout->sys;
443 pa_stream *s = sys->stream;
445 if (pa_stream_is_corked(s) > 0)
446 return -1; /* latency is irrelevant if corked */
448 mtime_t delta = vlc_pa_get_latency(aout, sys->context, s);
449 if (delta == VLC_TS_INVALID)
456 /* Memory free callback. The block_t address is in front of the data. */
457 static void data_free(void *data)
459 block_t **pp = data, *block;
461 memcpy(&block, pp - 1, sizeof (block));
462 block_Release(block);
465 static void *data_convert(block_t **pp)
467 block_t *block = *pp;
468 /* In most cases, there is enough head room, and this is really cheap: */
469 block = block_Realloc(block, sizeof (block), block->i_buffer);
471 if (unlikely(block == NULL))
474 memcpy(block->p_buffer, &block, sizeof (block));
475 block->p_buffer += sizeof (block);
476 block->i_buffer -= sizeof (block);
477 return block->p_buffer;
481 * Queue one audio frame to the playback stream
483 static void Play(audio_output_t *aout, block_t *block)
485 aout_sys_t *sys = aout->sys;
486 pa_stream *s = sys->stream;
488 const void *ptr = data_convert(&block);
489 if (unlikely(ptr == NULL))
492 size_t len = block->i_buffer;
494 /* Note: The core already holds the output FIFO lock at this point.
495 * Therefore we must not under any circumstances (try to) acquire the
496 * output FIFO lock while the PulseAudio threaded main loop lock is held
497 * (including from PulseAudio stream callbacks). Otherwise lock inversion
498 * will take place, and sooner or later a deadlock. */
499 pa_threaded_mainloop_lock(sys->mainloop);
501 if (sys->first_pts == VLC_TS_INVALID)
502 sys->first_pts = block->i_pts;
504 if (pa_stream_is_corked(s) > 0)
505 stream_start(s, aout);
507 #if 0 /* Fault injector to test underrun recovery */
508 static volatile unsigned u = 0;
509 if ((++u % 1000) == 0) {
510 msg_Err(aout, "fault injection");
511 pa_operation_unref(pa_stream_flush(s, NULL, NULL));
515 if (pa_stream_write(s, ptr, len, data_free, 0, PA_SEEK_RELATIVE) < 0) {
516 vlc_pa_error(aout, "cannot write", sys->context);
517 block_Release(block);
520 pa_threaded_mainloop_unlock(sys->mainloop);
524 * Cork or uncork the playback stream
526 static void Pause(audio_output_t *aout, bool paused, mtime_t date)
528 aout_sys_t *sys = aout->sys;
529 pa_stream *s = sys->stream;
531 pa_threaded_mainloop_lock(sys->mainloop);
534 pa_stream_set_latency_update_callback(s, NULL, NULL);
535 stream_stop(s, aout);
537 pa_stream_set_latency_update_callback(s, stream_latency_cb, aout);
538 if (likely(sys->first_pts != VLC_TS_INVALID))
539 stream_start_now(s, aout);
542 pa_threaded_mainloop_unlock(sys->mainloop);
547 * Flush or drain the playback stream
549 static void Flush(audio_output_t *aout, bool wait)
551 aout_sys_t *sys = aout->sys;
552 pa_stream *s = sys->stream;
555 pa_threaded_mainloop_lock(sys->mainloop);
558 op = pa_stream_drain(s, NULL, NULL);
559 /* TODO: wait for drain completion*/
561 op = pa_stream_flush(s, NULL, NULL);
563 pa_operation_unref(op);
564 pa_threaded_mainloop_unlock(sys->mainloop);
567 static int VolumeSet(audio_output_t *aout, float vol)
569 aout_sys_t *sys = aout->sys;
570 pa_stream *s = sys->stream;
574 /* VLC provides the software volume so convert directly to PulseAudio
575 * software volume, pa_volume_t. This is not a linear amplification factor
576 * so do not use PulseAudio linear amplification! */
577 vol *= PA_VOLUME_NORM;
578 if (unlikely(vol >= (float)PA_VOLUME_MAX))
579 volume = PA_VOLUME_MAX;
581 volume = lroundf(vol);
585 sys->volume_force = volume;
586 aout_VolumeReport(aout, (float)volume / (float)PA_VOLUME_NORM);
590 pa_threaded_mainloop_lock(sys->mainloop);
592 if (!pa_cvolume_valid(&sys->cvolume))
594 const pa_sample_spec *ss = pa_stream_get_sample_spec(s);
596 msg_Warn(aout, "balance clobbered by volume change");
597 pa_cvolume_set(&sys->cvolume, ss->channels, PA_VOLUME_NORM);
600 /* Preserve the balance (VLC does not support it). */
601 pa_cvolume cvolume = sys->cvolume;
602 pa_cvolume_scale(&cvolume, PA_VOLUME_NORM);
603 pa_sw_cvolume_multiply_scalar(&cvolume, &cvolume, volume);
604 assert(pa_cvolume_valid(&cvolume));
606 op = pa_context_set_sink_input_volume(sys->context, pa_stream_get_index(s),
607 &cvolume, NULL, NULL);
608 if (likely(op != NULL))
609 pa_operation_unref(op);
610 pa_threaded_mainloop_unlock(sys->mainloop);
611 return likely(op != NULL) ? 0 : -1;
614 static int MuteSet(audio_output_t *aout, bool mute)
616 aout_sys_t *sys = aout->sys;
618 if (sys->stream == NULL)
620 sys->flags_force &= ~(PA_STREAM_START_MUTED|PA_STREAM_START_UNMUTED);
622 mute ? PA_STREAM_START_MUTED : PA_STREAM_START_UNMUTED;
623 aout_MuteReport(aout, mute);
628 uint32_t idx = pa_stream_get_index(sys->stream);
629 pa_threaded_mainloop_lock(sys->mainloop);
630 op = pa_context_set_sink_input_mute(sys->context, idx, mute, NULL, NULL);
631 if (likely(op != NULL))
632 pa_operation_unref(op);
633 pa_threaded_mainloop_unlock(sys->mainloop);
638 static int StreamMove(audio_output_t *aout, const char *name)
640 aout_sys_t *sys = aout->sys;
642 if (sys->stream == NULL)
644 msg_Dbg(aout, "will connect to sink %s", name);
645 free(sys->sink_force);
646 sys->sink_force = strdup(name);
651 uint32_t idx = pa_stream_get_index(sys->stream);
653 pa_threaded_mainloop_lock(sys->mainloop);
654 op = pa_context_move_sink_input_by_name(sys->context, idx, name,
656 if (likely(op != NULL)) {
657 pa_operation_unref(op);
658 msg_Dbg(aout, "moving to sink %s", name);
660 vlc_pa_error(aout, "cannot move sink input", sys->context);
661 pa_threaded_mainloop_unlock(sys->mainloop);
663 return (op != NULL) ? 0 : -1;
666 static void Stop(audio_output_t *);
669 * Create a PulseAudio playback stream, a.k.a. a sink input.
671 static int Start(audio_output_t *aout, audio_sample_format_t *restrict fmt)
673 aout_sys_t *sys = aout->sys;
675 /* Sample format specification */
676 struct pa_sample_spec ss;
677 pa_encoding_t encoding = PA_ENCODING_INVALID;
679 switch (fmt->i_format)
682 fmt->i_format = VLC_CODEC_FL32;
684 ss.format = PA_SAMPLE_FLOAT32NE;
687 ss.format = PA_SAMPLE_S32NE;
690 ss.format = PA_SAMPLE_S16NE;
693 ss.format = PA_SAMPLE_U8;
696 fmt->i_format = VLC_CODEC_SPDIFL;
697 encoding = PA_ENCODING_AC3_IEC61937;
698 ss.format = HAVE_FPU ? PA_SAMPLE_FLOAT32NE : PA_SAMPLE_S16NE;
700 /*case VLC_CODEC_EAC3:
701 fmt->i_format = VLC_CODEC_SPDIFL FIXME;
702 encoding = PA_ENCODING_EAC3_IEC61937;
703 ss.format = HAVE_FPU ? PA_SAMPLE_FLOAT32NE : PA_SAMPLE_S16NE;
706 fmt->i_format = VLC_CODEC_SPDIFL FIXME;
707 encoding = PA_ENCODING_MPEG_IEC61937;
708 ss.format = HAVE_FPU ? PA_SAMPLE_FLOAT32NE : PA_SAMPLE_S16NE;
711 fmt->i_format = VLC_CODEC_SPDIFL;
712 encoding = PA_ENCODING_DTS_IEC61937;
713 ss.format = HAVE_FPU ? PA_SAMPLE_FLOAT32NE : PA_SAMPLE_S16NE;
718 fmt->i_format = VLC_CODEC_FL32;
719 ss.format = PA_SAMPLE_FLOAT32NE;
723 fmt->i_format = VLC_CODEC_S16N;
724 ss.format = PA_SAMPLE_S16NE;
729 ss.rate = fmt->i_rate;
730 ss.channels = aout_FormatNbChannels(fmt);
731 if (!pa_sample_spec_valid(&ss)) {
732 msg_Err(aout, "unsupported sample specification");
736 /* Channel mapping (order defined in vlc_aout.h) */
737 struct pa_channel_map map;
740 if (fmt->i_physical_channels & AOUT_CHAN_LEFT)
741 map.map[map.channels++] = PA_CHANNEL_POSITION_FRONT_LEFT;
742 if (fmt->i_physical_channels & AOUT_CHAN_RIGHT)
743 map.map[map.channels++] = PA_CHANNEL_POSITION_FRONT_RIGHT;
744 if (fmt->i_physical_channels & AOUT_CHAN_MIDDLELEFT)
745 map.map[map.channels++] = PA_CHANNEL_POSITION_SIDE_LEFT;
746 if (fmt->i_physical_channels & AOUT_CHAN_MIDDLERIGHT)
747 map.map[map.channels++] = PA_CHANNEL_POSITION_SIDE_RIGHT;
748 if (fmt->i_physical_channels & AOUT_CHAN_REARLEFT)
749 map.map[map.channels++] = PA_CHANNEL_POSITION_REAR_LEFT;
750 if (fmt->i_physical_channels & AOUT_CHAN_REARRIGHT)
751 map.map[map.channels++] = PA_CHANNEL_POSITION_REAR_RIGHT;
752 if (fmt->i_physical_channels & AOUT_CHAN_REARCENTER)
753 map.map[map.channels++] = PA_CHANNEL_POSITION_REAR_CENTER;
754 if (fmt->i_physical_channels & AOUT_CHAN_CENTER)
756 if (ss.channels == 1)
757 map.map[map.channels++] = PA_CHANNEL_POSITION_MONO;
759 map.map[map.channels++] = PA_CHANNEL_POSITION_FRONT_CENTER;
761 if (fmt->i_physical_channels & AOUT_CHAN_LFE)
762 map.map[map.channels++] = PA_CHANNEL_POSITION_LFE;
763 fmt->i_original_channels = fmt->i_physical_channels;
765 for (unsigned i = 0; map.channels < ss.channels; i++) {
766 map.map[map.channels++] = PA_CHANNEL_POSITION_AUX0 + i;
767 msg_Warn(aout, "mapping channel %"PRIu8" to AUX%u", map.channels, i);
770 if (!pa_channel_map_valid(&map)) {
771 msg_Err(aout, "unsupported channel map");
774 const char *name = pa_channel_map_to_name(&map);
775 msg_Dbg(aout, "using %s channel map", (name != NULL) ? name : "?");
778 /* Stream parameters */
779 pa_stream_flags_t flags = sys->flags_force
780 | PA_STREAM_START_CORKED
781 | PA_STREAM_INTERPOLATE_TIMING
782 | PA_STREAM_NOT_MONOTONIC
783 | PA_STREAM_AUTO_TIMING_UPDATE
784 | PA_STREAM_FIX_RATE;
786 struct pa_buffer_attr attr;
788 /* PulseAudio goes berserk if the target length (tlength) is not
789 * significantly longer than 2 periods (minreq), or when the period length
790 * is unspecified and the target length is short. */
791 attr.tlength = pa_usec_to_bytes(3 * AOUT_MIN_PREPARE_TIME, &ss);
792 attr.prebuf = 0; /* trigger manually */
793 attr.minreq = pa_usec_to_bytes(AOUT_MIN_PREPARE_TIME, &ss);
794 attr.fragsize = 0; /* not used for output */
796 pa_cvolume *cvolume = NULL, cvolumebuf;
797 if (PA_VOLUME_IS_VALID(sys->volume_force))
799 cvolume = &cvolumebuf;
800 pa_cvolume_set(cvolume, ss.channels, sys->volume_force);
804 pa_cvolume_init(&sys->cvolume);
805 sys->first_pts = VLC_TS_INVALID;
807 pa_format_info *formatv[2];
808 unsigned formatc = 0;
810 /* Favor digital pass-through if available*/
811 if (encoding != PA_ENCODING_INVALID) {
812 formatv[formatc] = pa_format_info_new();
813 formatv[formatc]->encoding = encoding;
814 pa_format_info_set_rate(formatv[formatc], ss.rate);
815 pa_format_info_set_channels(formatv[formatc], ss.channels);
816 pa_format_info_set_channel_map(formatv[formatc], &map);
819 /* FIX flags are only permitted for PCM, and there is no way to pass
820 * different flags for different formats... */
821 flags &= ~(PA_STREAM_FIX_FORMAT
823 | PA_STREAM_FIX_CHANNELS);
826 /* Fallback to PCM */
827 formatv[formatc] = pa_format_info_new();
828 formatv[formatc]->encoding = PA_ENCODING_PCM;
829 pa_format_info_set_sample_format(formatv[formatc], ss.format);
830 pa_format_info_set_rate(formatv[formatc], ss.rate);
831 pa_format_info_set_channels(formatv[formatc], ss.channels);
832 pa_format_info_set_channel_map(formatv[formatc], &map);
835 /* Create a playback stream */
836 pa_proplist *props = pa_proplist_new();
837 if (likely(props != NULL))
838 /* TODO: set other stream properties */
839 pa_proplist_sets (props, PA_PROP_MEDIA_ROLE, "video");
841 pa_threaded_mainloop_lock(sys->mainloop);
842 pa_stream *s = pa_stream_new_extended(sys->context, "audio stream",
843 formatv, formatc, props);
845 if (likely(props != NULL))
846 pa_proplist_free(props);
847 for (unsigned i = 0; i < formatc; i++)
848 pa_format_info_free(formatv[i]);
851 pa_threaded_mainloop_unlock(sys->mainloop);
852 vlc_pa_error(aout, "stream creation failure", sys->context);
855 assert(sys->stream == NULL);
857 pa_stream_set_state_callback(s, stream_state_cb, sys->mainloop);
858 pa_stream_set_buffer_attr_callback(s, stream_buffer_attr_cb, aout);
859 pa_stream_set_event_callback(s, stream_event_cb, aout);
860 pa_stream_set_latency_update_callback(s, stream_latency_cb, aout);
861 pa_stream_set_moved_callback(s, stream_moved_cb, aout);
862 pa_stream_set_overflow_callback(s, stream_overflow_cb, aout);
863 pa_stream_set_started_callback(s, stream_started_cb, aout);
864 pa_stream_set_suspended_callback(s, stream_suspended_cb, aout);
865 pa_stream_set_underflow_callback(s, stream_underflow_cb, aout);
867 if (pa_stream_connect_playback(s, sys->sink_force, &attr, flags,
869 || stream_wait(s, sys->mainloop)) {
870 vlc_pa_error(aout, "stream connection failure", sys->context);
873 sys->volume_force = PA_VOLUME_INVALID;
874 sys->flags_force = PA_STREAM_NOFLAGS;
875 free(sys->sink_force);
876 sys->sink_force = NULL;
878 const struct pa_sample_spec *spec = pa_stream_get_sample_spec(s);
879 if (encoding != PA_ENCODING_INVALID) {
880 const pa_format_info *info = pa_stream_get_format_info(s);
882 assert (info != NULL);
883 if (pa_format_info_is_pcm (info)) {
884 msg_Dbg(aout, "digital pass-through not available");
885 fmt->i_format = HAVE_FPU ? VLC_CODEC_FL32 : VLC_CODEC_S16N;
887 msg_Dbg(aout, "digital pass-through enabled");
892 fmt->i_rate = spec->rate;
894 stream_buffer_attr_cb(s, aout);
895 stream_moved_cb(s, aout);
896 pa_threaded_mainloop_unlock(sys->mainloop);
901 pa_threaded_mainloop_unlock(sys->mainloop);
907 * Removes a PulseAudio playback stream
909 static void Stop(audio_output_t *aout)
911 aout_sys_t *sys = aout->sys;
912 pa_stream *s = sys->stream;
914 pa_threaded_mainloop_lock(sys->mainloop);
915 if (unlikely(sys->trigger != NULL))
916 vlc_pa_rttime_free(sys->mainloop, sys->trigger);
917 pa_stream_disconnect(s);
919 /* Clear all callbacks */
920 pa_stream_set_state_callback(s, NULL, NULL);
921 pa_stream_set_buffer_attr_callback(s, NULL, NULL);
922 pa_stream_set_event_callback(s, NULL, NULL);
923 pa_stream_set_latency_update_callback(s, NULL, NULL);
924 pa_stream_set_moved_callback(s, NULL, NULL);
925 pa_stream_set_overflow_callback(s, NULL, NULL);
926 pa_stream_set_started_callback(s, NULL, NULL);
927 pa_stream_set_suspended_callback(s, NULL, NULL);
928 pa_stream_set_underflow_callback(s, NULL, NULL);
932 pa_threaded_mainloop_unlock(sys->mainloop);
935 static int Open(vlc_object_t *obj)
937 audio_output_t *aout = (audio_output_t *)obj;
938 aout_sys_t *sys = malloc(sizeof (*sys));
941 if (unlikely(sys == NULL))
944 /* Allocate structures */
945 pa_context *ctx = vlc_pa_connect(obj, &sys->mainloop);
953 sys->volume_force = PA_VOLUME_INVALID;
954 sys->flags_force = PA_STREAM_NOFLAGS;
955 sys->sink_force = NULL;
961 aout->time_get = TimeGet;
965 aout->volume_set = VolumeSet;
966 aout->mute_set = MuteSet;
967 aout->device_select = StreamMove;
969 pa_threaded_mainloop_lock(sys->mainloop);
970 /* Sinks (output devices) list */
971 op = pa_context_get_sink_info_list(sys->context, sink_add_cb, aout);
972 if (likely(op != NULL))
974 while (pa_operation_get_state(op) == PA_OPERATION_RUNNING)
975 pa_threaded_mainloop_wait(sys->mainloop);
976 pa_operation_unref(op);
980 const pa_subscription_mask_t mask = PA_SUBSCRIPTION_MASK_SINK
981 | PA_SUBSCRIPTION_MASK_SINK_INPUT;
982 pa_context_set_subscribe_callback(sys->context, context_cb, aout);
983 op = pa_context_subscribe(sys->context, mask, NULL, NULL);
984 if (likely(op != NULL))
985 pa_operation_unref(op);
986 pa_threaded_mainloop_unlock(sys->mainloop);
991 static void Close(vlc_object_t *obj)
993 audio_output_t *aout = (audio_output_t *)obj;
994 aout_sys_t *sys = aout->sys;
995 pa_context *ctx = sys->context;
997 pa_threaded_mainloop_lock(sys->mainloop);
998 pa_context_set_subscribe_callback(sys->context, NULL, NULL);
999 pa_threaded_mainloop_unlock(sys->mainloop);
1000 vlc_pa_disconnect(obj, ctx, sys->mainloop);
1002 for (struct sink *sink = sys->sinks, *next; sink != NULL; sink = next)
1007 free(sys->sink_force);