es: replace i_original_channels with i_chan_mode
[vlc.git] / modules / audio_output / pulse.c
blobe9c70c562d1c2a2afe46d3e21f8cfbff46ae02fb
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 *****************************************************************************/
24 #ifdef HAVE_CONFIG_H
25 # include "config.h"
26 #endif
28 #include <assert.h>
29 #include <math.h>
30 #include <vlc_common.h>
31 #include <vlc_plugin.h>
32 #include <vlc_aout.h>
33 #include <vlc_cpu.h>
35 #include <pulse/pulseaudio.h>
36 #include "audio_output/vlcpulse.h"
38 static int Open ( vlc_object_t * );
39 static void Close ( vlc_object_t * );
41 vlc_module_begin ()
42 set_shortname( "PulseAudio" )
43 set_description( N_("Pulseaudio audio output") )
44 set_capability( "audio output", 160 )
45 set_category( CAT_AUDIO )
46 set_subcategory( SUBCAT_AUDIO_AOUT )
47 add_shortcut( "pulseaudio", "pa" )
48 set_callbacks( Open, Close )
49 vlc_module_end ()
51 /* NOTE:
52 * Be careful what you do when the PulseAudio mainloop is held, which is to say
53 * within PulseAudio callbacks, or after pa_threaded_mainloop_lock().
54 * In particular, a VLC variable callback cannot be triggered nor deleted with
55 * the PulseAudio mainloop lock held, if the callback acquires the lock. */
57 struct sink
59 struct sink *next;
60 uint32_t index;
61 char name[1];
64 struct aout_sys_t
66 pa_stream *stream; /**< PulseAudio playback stream object */
67 pa_context *context; /**< PulseAudio connection context */
68 pa_threaded_mainloop *mainloop; /**< PulseAudio thread */
69 pa_time_event *trigger; /**< Deferred stream trigger */
70 pa_cvolume cvolume; /**< actual sink input volume */
71 mtime_t first_pts; /**< Play time of buffer start */
73 pa_volume_t volume_force; /**< Forced volume (stream must be NULL) */
74 pa_stream_flags_t flags_force; /**< Forced flags (stream must be NULL) */
75 char *sink_force; /**< Forced sink name (stream must be NULL) */
77 struct sink *sinks; /**< Locally-cached list of sinks */
80 static void VolumeReport(audio_output_t *aout)
82 aout_sys_t *sys = aout->sys;
83 pa_volume_t volume = pa_cvolume_max(&sys->cvolume);
85 aout_VolumeReport(aout, (float)volume / PA_VOLUME_NORM);
88 /*** Sink ***/
89 static void sink_add_cb(pa_context *ctx, const pa_sink_info *i, int eol,
90 void *userdata)
92 audio_output_t *aout = userdata;
93 aout_sys_t *sys = aout->sys;
95 if (eol)
97 pa_threaded_mainloop_signal(sys->mainloop, 0);
98 return;
100 (void) ctx;
102 msg_Dbg(aout, "adding sink %"PRIu32": %s (%s)", i->index, i->name,
103 i->description);
104 aout_HotplugReport(aout, i->name, i->description);
106 size_t namelen = strlen(i->name);
107 struct sink *sink = malloc(sizeof (*sink) + namelen);
108 if (unlikely(sink == NULL))
109 return;
111 sink->next = sys->sinks;
112 sink->index = i->index;
113 memcpy(sink->name, i->name, namelen + 1);
114 sys->sinks = sink;
117 static void sink_mod_cb(pa_context *ctx, const pa_sink_info *i, int eol,
118 void *userdata)
120 audio_output_t *aout = userdata;
122 if (eol)
123 return;
124 (void) ctx;
126 msg_Dbg(aout, "changing sink %"PRIu32": %s (%s)", i->index, i->name,
127 i->description);
128 aout_HotplugReport(aout, i->name, i->description);
131 static void sink_del(uint32_t index, audio_output_t *aout)
133 aout_sys_t *sys = aout->sys;
134 struct sink **pp = &sys->sinks, *sink;
136 msg_Dbg(aout, "removing sink %"PRIu32, index);
138 while ((sink = *pp) != NULL)
139 if (sink->index == index)
141 *pp = sink->next;
142 aout_HotplugReport(aout, sink->name, NULL);
143 free(sink);
145 else
146 pp = &sink->next;
149 static void sink_event(pa_context *ctx, unsigned type, uint32_t idx,
150 audio_output_t *aout)
152 pa_operation *op = NULL;
154 switch (type)
156 case PA_SUBSCRIPTION_EVENT_NEW:
157 op = pa_context_get_sink_info_by_index(ctx, idx, sink_add_cb,
158 aout);
159 break;
160 case PA_SUBSCRIPTION_EVENT_CHANGE:
161 op = pa_context_get_sink_info_by_index(ctx, idx, sink_mod_cb,
162 aout);
163 break;
164 case PA_SUBSCRIPTION_EVENT_REMOVE:
165 sink_del(idx, aout);
166 break;
168 if (op != NULL)
169 pa_operation_unref(op);
173 /*** Latency management and lip synchronization ***/
174 static void stream_start_now(pa_stream *s, audio_output_t *aout)
176 pa_operation *op;
178 assert (aout->sys->trigger == NULL);
180 op = pa_stream_cork(s, 0, NULL, NULL);
181 if (op != NULL)
182 pa_operation_unref(op);
183 op = pa_stream_trigger(s, NULL, NULL);
184 if (likely(op != NULL))
185 pa_operation_unref(op);
188 static void stream_stop(pa_stream *s, audio_output_t *aout)
190 aout_sys_t *sys = aout->sys;
191 pa_operation *op;
193 if (sys->trigger != NULL) {
194 vlc_pa_rttime_free(sys->mainloop, sys->trigger);
195 sys->trigger = NULL;
198 op = pa_stream_cork(s, 1, NULL, NULL);
199 if (op != NULL)
200 pa_operation_unref(op);
203 static void stream_trigger_cb(pa_mainloop_api *api, pa_time_event *e,
204 const struct timeval *tv, void *userdata)
206 audio_output_t *aout = userdata;
207 aout_sys_t *sys = aout->sys;
209 assert (sys->trigger == e);
211 msg_Dbg(aout, "starting deferred");
212 vlc_pa_rttime_free(sys->mainloop, sys->trigger);
213 sys->trigger = NULL;
214 stream_start_now(sys->stream, aout);
215 (void) api; (void) e; (void) tv;
219 * Starts or resumes the playback stream.
220 * Tries start playing back audio samples at the most accurate time
221 * in order to minimize desync and resampling during early playback.
222 * @note PulseAudio lock required.
224 static void stream_start(pa_stream *s, audio_output_t *aout)
226 aout_sys_t *sys = aout->sys;
227 mtime_t delta;
229 assert (sys->first_pts != VLC_TS_INVALID);
231 if (sys->trigger != NULL) {
232 vlc_pa_rttime_free(sys->mainloop, sys->trigger);
233 sys->trigger = NULL;
236 delta = vlc_pa_get_latency(aout, sys->context, s);
237 if (unlikely(delta == VLC_TS_INVALID)) {
238 msg_Dbg(aout, "cannot synchronize start");
239 delta = 0; /* screwed */
242 delta = (sys->first_pts - mdate()) - delta;
243 if (delta > 0) {
244 msg_Dbg(aout, "deferring start (%"PRId64" us)", delta);
245 delta += pa_rtclock_now();
246 sys->trigger = pa_context_rttime_new(sys->context, delta,
247 stream_trigger_cb, aout);
248 } else {
249 msg_Warn(aout, "starting late (%"PRId64" us)", delta);
250 stream_start_now(s, aout);
254 static void stream_latency_cb(pa_stream *s, void *userdata)
256 audio_output_t *aout = userdata;
257 aout_sys_t *sys = aout->sys;
259 /* This callback is _never_ called while paused. */
260 if (sys->first_pts == VLC_TS_INVALID)
261 return; /* nothing to do if buffers are (still) empty */
262 if (pa_stream_is_corked(s) > 0)
263 stream_start(s, aout);
267 /*** Stream helpers ***/
268 static void stream_state_cb(pa_stream *s, void *userdata)
270 pa_threaded_mainloop *mainloop = userdata;
272 switch (pa_stream_get_state(s)) {
273 case PA_STREAM_READY:
274 case PA_STREAM_FAILED:
275 case PA_STREAM_TERMINATED:
276 pa_threaded_mainloop_signal(mainloop, 0);
277 default:
278 break;
282 static void stream_buffer_attr_cb(pa_stream *s, void *userdata)
284 audio_output_t *aout = userdata;
285 const pa_buffer_attr *pba = pa_stream_get_buffer_attr(s);
287 msg_Dbg(aout, "changed buffer metrics: maxlength=%u, tlength=%u, "
288 "prebuf=%u, minreq=%u",
289 pba->maxlength, pba->tlength, pba->prebuf, pba->minreq);
292 static void stream_event_cb(pa_stream *s, const char *name, pa_proplist *pl,
293 void *userdata)
295 audio_output_t *aout = userdata;
297 if (!strcmp(name, PA_STREAM_EVENT_REQUEST_CORK))
298 aout_PolicyReport(aout, true);
299 else
300 if (!strcmp(name, PA_STREAM_EVENT_REQUEST_UNCORK))
301 aout_PolicyReport(aout, false);
302 else
303 /* FIXME: expose aout_Restart() directly */
304 if (!strcmp(name, PA_STREAM_EVENT_FORMAT_LOST)) {
305 msg_Dbg (aout, "format lost");
306 aout_RestartRequest (aout, AOUT_RESTART_OUTPUT);
307 } else
308 msg_Warn (aout, "unhandled stream event \"%s\"", name);
309 (void) s;
310 (void) pl;
313 static void stream_moved_cb(pa_stream *s, void *userdata)
315 audio_output_t *aout = userdata;
316 const char *name = pa_stream_get_device_name(s);
318 msg_Dbg(aout, "connected to sink %s", name);
319 aout_DeviceReport(aout, name);
322 static void stream_overflow_cb(pa_stream *s, void *userdata)
324 audio_output_t *aout = userdata;
325 aout_sys_t *sys = aout->sys;
326 pa_operation *op;
328 msg_Err(aout, "overflow, flushing");
329 op = pa_stream_flush(s, NULL, NULL);
330 if (unlikely(op == NULL))
331 return;
332 pa_operation_unref(op);
333 sys->first_pts = VLC_TS_INVALID;
336 static void stream_started_cb(pa_stream *s, void *userdata)
338 audio_output_t *aout = userdata;
340 msg_Dbg(aout, "started");
341 (void) s;
344 static void stream_suspended_cb(pa_stream *s, void *userdata)
346 audio_output_t *aout = userdata;
348 msg_Dbg(aout, "suspended");
349 (void) s;
352 static void stream_underflow_cb(pa_stream *s, void *userdata)
354 audio_output_t *aout = userdata;
356 msg_Dbg(aout, "underflow");
357 (void) s;
360 static int stream_wait(pa_stream *stream, pa_threaded_mainloop *mainloop)
362 pa_stream_state_t state;
364 while ((state = pa_stream_get_state(stream)) != PA_STREAM_READY) {
365 if (state == PA_STREAM_FAILED || state == PA_STREAM_TERMINATED)
366 return -1;
367 pa_threaded_mainloop_wait(mainloop);
369 return 0;
373 /*** Sink input ***/
374 static void sink_input_info_cb(pa_context *ctx, const pa_sink_input_info *i,
375 int eol, void *userdata)
377 audio_output_t *aout = userdata;
378 aout_sys_t *sys = aout->sys;
380 if (eol)
381 return;
382 (void) ctx;
384 sys->cvolume = i->volume; /* cache volume for balance preservation */
385 VolumeReport(aout);
386 aout_MuteReport(aout, i->mute);
389 static void sink_input_event(pa_context *ctx,
390 pa_subscription_event_type_t type,
391 uint32_t idx, audio_output_t *aout)
393 pa_operation *op;
395 /* Gee... PA will not provide the infos directly in the event. */
396 switch (type)
398 case PA_SUBSCRIPTION_EVENT_REMOVE:
399 msg_Err(aout, "sink input killed!");
400 break;
402 default:
403 op = pa_context_get_sink_input_info(ctx, idx, sink_input_info_cb,
404 aout);
405 if (likely(op != NULL))
406 pa_operation_unref(op);
407 break;
412 /*** Context ***/
413 static void context_cb(pa_context *ctx, pa_subscription_event_type_t type,
414 uint32_t idx, void *userdata)
416 audio_output_t *aout = userdata;
417 aout_sys_t *sys = aout->sys;
418 unsigned facility = type & PA_SUBSCRIPTION_EVENT_FACILITY_MASK;
420 type &= PA_SUBSCRIPTION_EVENT_TYPE_MASK;
421 switch (facility)
423 case PA_SUBSCRIPTION_EVENT_SINK:
424 sink_event(ctx, type, idx, userdata);
425 break;
427 case PA_SUBSCRIPTION_EVENT_SINK_INPUT:
428 /* only interested in our sink input */
429 if (sys->stream != NULL && idx == pa_stream_get_index(sys->stream))
430 sink_input_event(ctx, type, idx, userdata);
431 break;
433 default: /* unsubscribed facility?! */
434 vlc_assert_unreachable();
439 /*** VLC audio output callbacks ***/
441 static int TimeGet(audio_output_t *aout, mtime_t *restrict delay)
443 aout_sys_t *sys = aout->sys;
444 pa_stream *s = sys->stream;
445 int ret = -1;
447 pa_threaded_mainloop_lock(sys->mainloop);
448 if (pa_stream_is_corked(s) <= 0)
449 { /* latency is relevant only if not corked */
450 mtime_t delta = vlc_pa_get_latency(aout, sys->context, s);
451 if (delta != VLC_TS_INVALID)
453 *delay = delta;
454 ret = 0;
457 pa_threaded_mainloop_unlock(sys->mainloop);
458 return ret;
461 /* Memory free callback. The block_t address is in front of the data. */
462 static void data_free(void *data)
464 block_t **pp = data, *block;
466 memcpy(&block, pp - 1, sizeof (block));
467 block_Release(block);
470 static void *data_convert(block_t **pp)
472 block_t *block = *pp;
473 /* In most cases, there is enough head room, and this is really cheap: */
474 block = block_Realloc(block, sizeof (block), block->i_buffer);
475 *pp = block;
476 if (unlikely(block == NULL))
477 return NULL;
479 memcpy(block->p_buffer, &block, sizeof (block));
480 block->p_buffer += sizeof (block);
481 block->i_buffer -= sizeof (block);
482 return block->p_buffer;
486 * Queue one audio frame to the playback stream
488 static void Play(audio_output_t *aout, block_t *block)
490 aout_sys_t *sys = aout->sys;
491 pa_stream *s = sys->stream;
493 const void *ptr = data_convert(&block);
494 if (unlikely(ptr == NULL))
495 return;
497 size_t len = block->i_buffer;
499 /* Note: The core already holds the output FIFO lock at this point.
500 * Therefore we must not under any circumstances (try to) acquire the
501 * output FIFO lock while the PulseAudio threaded main loop lock is held
502 * (including from PulseAudio stream callbacks). Otherwise lock inversion
503 * will take place, and sooner or later a deadlock. */
504 pa_threaded_mainloop_lock(sys->mainloop);
506 if (sys->first_pts == VLC_TS_INVALID)
507 sys->first_pts = block->i_pts;
509 if (pa_stream_is_corked(s) > 0)
510 stream_start(s, aout);
512 #if 0 /* Fault injector to test underrun recovery */
513 static volatile unsigned u = 0;
514 if ((++u % 1000) == 0) {
515 msg_Err(aout, "fault injection");
516 pa_operation_unref(pa_stream_flush(s, NULL, NULL));
518 #endif
520 if (pa_stream_write(s, ptr, len, data_free, 0, PA_SEEK_RELATIVE) < 0) {
521 vlc_pa_error(aout, "cannot write", sys->context);
522 block_Release(block);
525 pa_threaded_mainloop_unlock(sys->mainloop);
529 * Cork or uncork the playback stream
531 static void Pause(audio_output_t *aout, bool paused, mtime_t date)
533 aout_sys_t *sys = aout->sys;
534 pa_stream *s = sys->stream;
536 pa_threaded_mainloop_lock(sys->mainloop);
538 if (paused) {
539 pa_stream_set_latency_update_callback(s, NULL, NULL);
540 stream_stop(s, aout);
541 } else {
542 pa_stream_set_latency_update_callback(s, stream_latency_cb, aout);
543 if (likely(sys->first_pts != VLC_TS_INVALID))
544 stream_start_now(s, aout);
547 pa_threaded_mainloop_unlock(sys->mainloop);
548 (void) date;
552 * Flush or drain the playback stream
554 static void Flush(audio_output_t *aout, bool wait)
556 aout_sys_t *sys = aout->sys;
557 pa_stream *s = sys->stream;
558 pa_operation *op;
560 pa_threaded_mainloop_lock(sys->mainloop);
562 if (wait)
563 op = pa_stream_drain(s, NULL, NULL);
564 /* TODO: wait for drain completion*/
565 else
566 op = pa_stream_flush(s, NULL, NULL);
567 if (op != NULL)
568 pa_operation_unref(op);
569 sys->first_pts = VLC_TS_INVALID;
570 stream_stop(s, aout);
572 pa_threaded_mainloop_unlock(sys->mainloop);
575 static int VolumeSet(audio_output_t *aout, float vol)
577 aout_sys_t *sys = aout->sys;
578 pa_stream *s = sys->stream;
579 pa_operation *op;
580 pa_volume_t volume;
582 /* VLC provides the software volume so convert directly to PulseAudio
583 * software volume, pa_volume_t. This is not a linear amplification factor
584 * so do not use PulseAudio linear amplification! */
585 vol *= PA_VOLUME_NORM;
586 if (unlikely(vol >= (float)PA_VOLUME_MAX))
587 volume = PA_VOLUME_MAX;
588 else
589 volume = lroundf(vol);
591 if (s == NULL)
593 sys->volume_force = volume;
594 aout_VolumeReport(aout, (float)volume / (float)PA_VOLUME_NORM);
595 return 0;
598 pa_threaded_mainloop_lock(sys->mainloop);
600 if (!pa_cvolume_valid(&sys->cvolume))
602 const pa_sample_spec *ss = pa_stream_get_sample_spec(s);
604 msg_Warn(aout, "balance clobbered by volume change");
605 pa_cvolume_set(&sys->cvolume, ss->channels, PA_VOLUME_NORM);
608 /* Preserve the balance (VLC does not support it). */
609 pa_cvolume cvolume = sys->cvolume;
610 pa_cvolume_scale(&cvolume, PA_VOLUME_NORM);
611 pa_sw_cvolume_multiply_scalar(&cvolume, &cvolume, volume);
612 assert(pa_cvolume_valid(&cvolume));
614 op = pa_context_set_sink_input_volume(sys->context, pa_stream_get_index(s),
615 &cvolume, NULL, NULL);
616 if (likely(op != NULL))
617 pa_operation_unref(op);
618 pa_threaded_mainloop_unlock(sys->mainloop);
619 return likely(op != NULL) ? 0 : -1;
622 static int MuteSet(audio_output_t *aout, bool mute)
624 aout_sys_t *sys = aout->sys;
626 if (sys->stream == NULL)
628 sys->flags_force &= ~(PA_STREAM_START_MUTED|PA_STREAM_START_UNMUTED);
629 sys->flags_force |=
630 mute ? PA_STREAM_START_MUTED : PA_STREAM_START_UNMUTED;
631 aout_MuteReport(aout, mute);
632 return 0;
635 pa_operation *op;
636 uint32_t idx = pa_stream_get_index(sys->stream);
637 pa_threaded_mainloop_lock(sys->mainloop);
638 op = pa_context_set_sink_input_mute(sys->context, idx, mute, NULL, NULL);
639 if (likely(op != NULL))
640 pa_operation_unref(op);
641 pa_threaded_mainloop_unlock(sys->mainloop);
643 return 0;
646 static int StreamMove(audio_output_t *aout, const char *name)
648 aout_sys_t *sys = aout->sys;
650 if (sys->stream == NULL)
652 msg_Dbg(aout, "will connect to sink %s", name);
653 free(sys->sink_force);
654 sys->sink_force = strdup(name);
655 aout_DeviceReport(aout, name);
656 return 0;
659 pa_operation *op;
660 uint32_t idx = pa_stream_get_index(sys->stream);
662 pa_threaded_mainloop_lock(sys->mainloop);
663 op = pa_context_move_sink_input_by_name(sys->context, idx, name,
664 NULL, NULL);
665 if (likely(op != NULL)) {
666 pa_operation_unref(op);
667 msg_Dbg(aout, "moving to sink %s", name);
668 } else
669 vlc_pa_error(aout, "cannot move sink input", sys->context);
670 pa_threaded_mainloop_unlock(sys->mainloop);
672 return (op != NULL) ? 0 : -1;
675 static void Stop(audio_output_t *);
677 static int strcmp_void(const void *a, const void *b)
679 const char *const *entry = b;
680 return strcmp(a, *entry);
683 static const char *str_map(const char *key, const char *const table[][2],
684 size_t n)
686 const char **r = bsearch(key, table, n, sizeof (*table), strcmp_void);
687 return (r != NULL) ? r[1] : NULL;
691 * Create a PulseAudio playback stream, a.k.a. a sink input.
693 static int Start(audio_output_t *aout, audio_sample_format_t *restrict fmt)
695 aout_sys_t *sys = aout->sys;
697 /* Sample format specification */
698 struct pa_sample_spec ss;
699 pa_encoding_t encoding = PA_ENCODING_INVALID;
701 switch (fmt->i_format)
703 case VLC_CODEC_FL64:
704 fmt->i_format = VLC_CODEC_FL32;
705 /* fall through */
706 case VLC_CODEC_FL32:
707 ss.format = PA_SAMPLE_FLOAT32NE;
708 break;
709 case VLC_CODEC_S32N:
710 ss.format = PA_SAMPLE_S32NE;
711 break;
712 case VLC_CODEC_S16N:
713 ss.format = PA_SAMPLE_S16NE;
714 break;
715 case VLC_CODEC_U8:
716 ss.format = PA_SAMPLE_U8;
717 break;
718 case VLC_CODEC_A52:
719 fmt->i_format = VLC_CODEC_SPDIFL;
720 fmt->i_bytes_per_frame = 4;
721 fmt->i_frame_length = 1;
722 fmt->i_physical_channels = AOUT_CHANS_2_0;
723 fmt->i_channels = 2;
724 encoding = PA_ENCODING_AC3_IEC61937;
725 ss.format = PA_SAMPLE_S16NE;
726 break;
727 case VLC_CODEC_EAC3:
728 fmt->i_format = VLC_CODEC_SPDIFL;
729 fmt->i_bytes_per_frame = 4;
730 fmt->i_frame_length = 1;
731 fmt->i_physical_channels = AOUT_CHANS_2_0;
732 fmt->i_channels = 2;
733 encoding = PA_ENCODING_EAC3_IEC61937;
734 ss.format = PA_SAMPLE_S16NE;
735 break;
736 /* case VLC_CODEC_MPGA:
737 fmt->i_format = VLC_CODEC_SPDIFL FIXME;
738 encoding = PA_ENCODING_MPEG_IEC61937;
739 ss.format = PA_SAMPLE_S16NE;
740 break;*/
741 case VLC_CODEC_DTS:
742 fmt->i_format = VLC_CODEC_SPDIFL;
743 fmt->i_bytes_per_frame = 4;
744 fmt->i_frame_length = 1;
745 fmt->i_physical_channels = AOUT_CHANS_2_0;
746 fmt->i_channels = 2;
747 encoding = PA_ENCODING_DTS_IEC61937;
748 ss.format = PA_SAMPLE_S16NE;
749 break;
750 default:
751 if (!AOUT_FMT_LINEAR(fmt) || aout_FormatNbChannels(fmt) == 0)
752 return VLC_EGENERIC;
754 if (HAVE_FPU)
756 fmt->i_format = VLC_CODEC_FL32;
757 ss.format = PA_SAMPLE_FLOAT32NE;
759 else
761 fmt->i_format = VLC_CODEC_S16N;
762 ss.format = PA_SAMPLE_S16NE;
764 break;
767 ss.rate = fmt->i_rate;
768 ss.channels = fmt->i_channels;
769 if (!pa_sample_spec_valid(&ss)) {
770 msg_Err(aout, "unsupported sample specification");
771 return VLC_EGENERIC;
774 /* Stream parameters */
775 pa_stream_flags_t flags = sys->flags_force
776 | PA_STREAM_START_CORKED
777 | PA_STREAM_INTERPOLATE_TIMING
778 | PA_STREAM_NOT_MONOTONIC
779 | PA_STREAM_AUTO_TIMING_UPDATE
780 | PA_STREAM_FIX_RATE;
782 struct pa_buffer_attr attr;
783 attr.maxlength = -1;
784 /* PulseAudio goes berserk if the target length (tlength) is not
785 * significantly longer than 2 periods (minreq), or when the period length
786 * is unspecified and the target length is short. */
787 attr.tlength = pa_usec_to_bytes(3 * AOUT_MIN_PREPARE_TIME, &ss);
788 attr.prebuf = 0; /* trigger manually */
789 attr.minreq = pa_usec_to_bytes(AOUT_MIN_PREPARE_TIME, &ss);
790 attr.fragsize = 0; /* not used for output */
792 pa_cvolume *cvolume = NULL, cvolumebuf;
793 if (PA_VOLUME_IS_VALID(sys->volume_force))
795 cvolume = &cvolumebuf;
796 pa_cvolume_set(cvolume, ss.channels, sys->volume_force);
799 sys->trigger = NULL;
800 pa_cvolume_init(&sys->cvolume);
801 sys->first_pts = VLC_TS_INVALID;
803 pa_format_info *formatv;
805 /* Favor digital pass-through if available*/
806 if (encoding != PA_ENCODING_INVALID) {
807 formatv = pa_format_info_new();
808 formatv->encoding = encoding;
809 pa_format_info_set_rate(formatv, ss.rate);
810 pa_format_info_set_channels(formatv, ss.channels);
812 /* FIX flags are only permitted for PCM, and there is no way to pass
813 * different flags for different formats... */
814 flags &= ~(PA_STREAM_FIX_FORMAT
815 | PA_STREAM_FIX_RATE
816 | PA_STREAM_FIX_CHANNELS);
818 else
820 /* Channel mapping (order defined in vlc_aout.h) */
821 struct pa_channel_map map;
822 map.channels = 0;
824 if (fmt->i_physical_channels & AOUT_CHAN_LEFT)
825 map.map[map.channels++] = PA_CHANNEL_POSITION_FRONT_LEFT;
826 if (fmt->i_physical_channels & AOUT_CHAN_RIGHT)
827 map.map[map.channels++] = PA_CHANNEL_POSITION_FRONT_RIGHT;
828 if (fmt->i_physical_channels & AOUT_CHAN_MIDDLELEFT)
829 map.map[map.channels++] = PA_CHANNEL_POSITION_SIDE_LEFT;
830 if (fmt->i_physical_channels & AOUT_CHAN_MIDDLERIGHT)
831 map.map[map.channels++] = PA_CHANNEL_POSITION_SIDE_RIGHT;
832 if (fmt->i_physical_channels & AOUT_CHAN_REARLEFT)
833 map.map[map.channels++] = PA_CHANNEL_POSITION_REAR_LEFT;
834 if (fmt->i_physical_channels & AOUT_CHAN_REARRIGHT)
835 map.map[map.channels++] = PA_CHANNEL_POSITION_REAR_RIGHT;
836 if (fmt->i_physical_channels & AOUT_CHAN_REARCENTER)
837 map.map[map.channels++] = PA_CHANNEL_POSITION_REAR_CENTER;
838 if (fmt->i_physical_channels & AOUT_CHAN_CENTER)
840 if (ss.channels == 1)
841 map.map[map.channels++] = PA_CHANNEL_POSITION_MONO;
842 else
843 map.map[map.channels++] = PA_CHANNEL_POSITION_FRONT_CENTER;
845 if (fmt->i_physical_channels & AOUT_CHAN_LFE)
846 map.map[map.channels++] = PA_CHANNEL_POSITION_LFE;
848 static_assert(AOUT_CHAN_MAX == 9, "Missing channels");
850 for (unsigned i = 0; map.channels < ss.channels; i++) {
851 map.map[map.channels++] = PA_CHANNEL_POSITION_AUX0 + i;
852 msg_Warn(aout, "mapping channel %"PRIu8" to AUX%u", map.channels, i);
855 if (!pa_channel_map_valid(&map)) {
856 msg_Err(aout, "unsupported channel map");
857 return VLC_EGENERIC;
858 } else {
859 const char *name = pa_channel_map_to_name(&map);
860 msg_Dbg(aout, "using %s channel map", (name != NULL) ? name : "?");
863 /* PCM */
864 formatv = pa_format_info_new();
865 formatv->encoding = PA_ENCODING_PCM;
866 pa_format_info_set_sample_format(formatv, ss.format);
867 pa_format_info_set_rate(formatv, ss.rate);
868 pa_format_info_set_channels(formatv, ss.channels);
869 pa_format_info_set_channel_map(formatv, &map);
872 /* Create a playback stream */
873 pa_proplist *props = pa_proplist_new();
874 if (likely(props != NULL))
876 /* TODO: set other stream properties */
877 char *str = var_InheritString(aout, "role");
878 if (str != NULL)
880 static const char *const role_map[][2] = {
881 { "accessibility", "a11y" },
882 { "animation", "animation" },
883 { "communication", "phone" },
884 { "game", "game" },
885 { "music", "music" },
886 { "notification", "event" },
887 { "production", "production" },
888 { "test", "test" },
889 { "video", "video" },
891 const char *role = str_map(str, role_map, ARRAY_SIZE(role_map));
892 if (role != NULL)
893 pa_proplist_sets(props, PA_PROP_MEDIA_ROLE, role);
894 free(str);
898 pa_threaded_mainloop_lock(sys->mainloop);
899 pa_stream *s = pa_stream_new_extended(sys->context, "audio stream",
900 &formatv, 1, props);
902 if (likely(props != NULL))
903 pa_proplist_free(props);
904 pa_format_info_free(formatv);
906 if (s == NULL) {
907 pa_threaded_mainloop_unlock(sys->mainloop);
908 vlc_pa_error(aout, "stream creation failure", sys->context);
909 return VLC_EGENERIC;
911 assert(sys->stream == NULL);
912 sys->stream = s;
913 pa_stream_set_state_callback(s, stream_state_cb, sys->mainloop);
914 pa_stream_set_buffer_attr_callback(s, stream_buffer_attr_cb, aout);
915 pa_stream_set_event_callback(s, stream_event_cb, aout);
916 pa_stream_set_latency_update_callback(s, stream_latency_cb, aout);
917 pa_stream_set_moved_callback(s, stream_moved_cb, aout);
918 pa_stream_set_overflow_callback(s, stream_overflow_cb, aout);
919 pa_stream_set_started_callback(s, stream_started_cb, aout);
920 pa_stream_set_suspended_callback(s, stream_suspended_cb, aout);
921 pa_stream_set_underflow_callback(s, stream_underflow_cb, aout);
923 if (pa_stream_connect_playback(s, sys->sink_force, &attr, flags,
924 cvolume, NULL) < 0
925 || stream_wait(s, sys->mainloop)) {
926 if (encoding != PA_ENCODING_INVALID)
927 vlc_pa_error(aout, "digital pass-through stream connection failure",
928 sys->context);
929 else
930 vlc_pa_error(aout, "stream connection failure", sys->context);
931 goto fail;
933 sys->volume_force = PA_VOLUME_INVALID;
934 sys->flags_force = PA_STREAM_NOFLAGS;
935 free(sys->sink_force);
936 sys->sink_force = NULL;
938 if (encoding == PA_ENCODING_INVALID)
940 const struct pa_sample_spec *spec = pa_stream_get_sample_spec(s);
941 fmt->i_rate = spec->rate;
944 stream_buffer_attr_cb(s, aout);
945 stream_moved_cb(s, aout);
946 pa_threaded_mainloop_unlock(sys->mainloop);
948 return VLC_SUCCESS;
950 fail:
951 pa_threaded_mainloop_unlock(sys->mainloop);
952 Stop(aout);
953 return VLC_EGENERIC;
957 * Removes a PulseAudio playback stream
959 static void Stop(audio_output_t *aout)
961 aout_sys_t *sys = aout->sys;
962 pa_stream *s = sys->stream;
964 pa_threaded_mainloop_lock(sys->mainloop);
965 if (unlikely(sys->trigger != NULL))
966 vlc_pa_rttime_free(sys->mainloop, sys->trigger);
967 pa_stream_disconnect(s);
969 /* Clear all callbacks */
970 pa_stream_set_state_callback(s, NULL, NULL);
971 pa_stream_set_buffer_attr_callback(s, NULL, NULL);
972 pa_stream_set_event_callback(s, NULL, NULL);
973 pa_stream_set_latency_update_callback(s, NULL, NULL);
974 pa_stream_set_moved_callback(s, NULL, NULL);
975 pa_stream_set_overflow_callback(s, NULL, NULL);
976 pa_stream_set_started_callback(s, NULL, NULL);
977 pa_stream_set_suspended_callback(s, NULL, NULL);
978 pa_stream_set_underflow_callback(s, NULL, NULL);
980 pa_stream_unref(s);
981 sys->stream = NULL;
982 pa_threaded_mainloop_unlock(sys->mainloop);
985 static int Open(vlc_object_t *obj)
987 audio_output_t *aout = (audio_output_t *)obj;
988 aout_sys_t *sys = malloc(sizeof (*sys));
989 pa_operation *op;
991 if (unlikely(sys == NULL))
992 return VLC_ENOMEM;
994 /* Allocate structures */
995 pa_context *ctx = vlc_pa_connect(obj, &sys->mainloop);
996 if (ctx == NULL)
998 free(sys);
999 return VLC_EGENERIC;
1001 sys->stream = NULL;
1002 sys->context = ctx;
1003 sys->volume_force = PA_VOLUME_INVALID;
1004 sys->flags_force = PA_STREAM_NOFLAGS;
1005 sys->sink_force = NULL;
1006 sys->sinks = NULL;
1008 aout->sys = sys;
1009 aout->start = Start;
1010 aout->stop = Stop;
1011 aout->time_get = TimeGet;
1012 aout->play = Play;
1013 aout->pause = Pause;
1014 aout->flush = Flush;
1015 aout->volume_set = VolumeSet;
1016 aout->mute_set = MuteSet;
1017 aout->device_select = StreamMove;
1019 pa_threaded_mainloop_lock(sys->mainloop);
1020 /* Sinks (output devices) list */
1021 op = pa_context_get_sink_info_list(sys->context, sink_add_cb, aout);
1022 if (likely(op != NULL))
1024 while (pa_operation_get_state(op) == PA_OPERATION_RUNNING)
1025 pa_threaded_mainloop_wait(sys->mainloop);
1026 pa_operation_unref(op);
1029 /* Context events */
1030 const pa_subscription_mask_t mask = PA_SUBSCRIPTION_MASK_SINK
1031 | PA_SUBSCRIPTION_MASK_SINK_INPUT;
1032 pa_context_set_subscribe_callback(sys->context, context_cb, aout);
1033 op = pa_context_subscribe(sys->context, mask, NULL, NULL);
1034 if (likely(op != NULL))
1035 pa_operation_unref(op);
1036 pa_threaded_mainloop_unlock(sys->mainloop);
1038 return VLC_SUCCESS;
1041 static void Close(vlc_object_t *obj)
1043 audio_output_t *aout = (audio_output_t *)obj;
1044 aout_sys_t *sys = aout->sys;
1045 pa_context *ctx = sys->context;
1047 pa_threaded_mainloop_lock(sys->mainloop);
1048 pa_context_set_subscribe_callback(sys->context, NULL, NULL);
1049 pa_threaded_mainloop_unlock(sys->mainloop);
1050 vlc_pa_disconnect(obj, ctx, sys->mainloop);
1052 for (struct sink *sink = sys->sinks, *next; sink != NULL; sink = next)
1054 next = sink->next;
1055 free(sink);
1057 free(sys->sink_force);
1058 free(sys);