]> git.sesse.net Git - vlc/blob - modules/audio_output/pulse.c
auhal: ignore invalid default audio device changes (fixes #9374)
[vlc] / modules / audio_output / pulse.c
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
6  *
7  * Authors: Martin Hamrle <hamrle @ post . cz>
8  *
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.
13  *
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.
18  *
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  *****************************************************************************/
23
24 #ifdef HAVE_CONFIG_H
25 # include "config.h"
26 #endif
27
28 #include <math.h>
29 #include <vlc_common.h>
30 #include <vlc_plugin.h>
31 #include <vlc_aout.h>
32 #include <vlc_cpu.h>
33
34 #include <pulse/pulseaudio.h>
35 #include "vlcpulse.h"
36 #if !PA_CHECK_VERSION(0,9,22)
37 # include <vlc_xlib.h>
38 #endif
39
40 static int  Open        ( vlc_object_t * );
41 static void Close       ( vlc_object_t * );
42
43 vlc_module_begin ()
44     set_shortname( "PulseAudio" )
45     set_description( N_("Pulseaudio audio output") )
46     set_capability( "audio output", 160 )
47     set_category( CAT_AUDIO )
48     set_subcategory( SUBCAT_AUDIO_AOUT )
49     add_shortcut( "pulseaudio", "pa" )
50     set_callbacks( Open, Close )
51 vlc_module_end ()
52
53 /* NOTE:
54  * Be careful what you do when the PulseAudio mainloop is held, which is to say
55  * within PulseAudio callbacks, or after pa_threaded_mainloop_lock().
56  * In particular, a VLC variable callback cannot be triggered nor deleted with
57  * the PulseAudio mainloop lock held, if the callback acquires the lock. */
58
59 struct sink
60 {
61     struct sink *next;
62     uint32_t index;
63     char name[1];
64 };
65
66 struct aout_sys_t
67 {
68     pa_stream *stream; /**< PulseAudio playback stream object */
69     pa_context *context; /**< PulseAudio connection context */
70     pa_threaded_mainloop *mainloop; /**< PulseAudio thread */
71     pa_time_event *trigger; /**< Deferred stream trigger */
72     pa_volume_t base_volume; /**< 0dB reference volume */
73     pa_cvolume cvolume; /**< actual sink input volume */
74     mtime_t first_pts; /**< Play time of buffer start */
75
76     pa_stream_flags_t flags_force; /**< Forced flags (stream must be NULL) */
77     char *sink_force; /**< Forced sink name (stream must be NULL) */
78
79     struct sink *sinks; /**< Locally-cached list of sinks */
80 };
81
82
83 /*** Sink ***/
84 static void sink_add_cb(pa_context *ctx, const pa_sink_info *i, int eol,
85                         void *userdata)
86 {
87     audio_output_t *aout = userdata;
88     aout_sys_t *sys = aout->sys;
89
90     if (eol)
91         return;
92     (void) ctx;
93
94     msg_Dbg(aout, "adding sink %"PRIu32": %s (%s)", i->index, i->name,
95             i->description);
96     aout_HotplugReport(aout, i->name, i->description);
97
98     size_t namelen = strlen(i->name);
99     struct sink *sink = malloc(sizeof (*sink) + namelen);
100     if (unlikely(sink == NULL))
101         return;
102
103     sink->next = sys->sinks;
104     sink->index = i->index;
105     memcpy(sink->name, i->name, namelen + 1);
106     sys->sinks = sink;
107 }
108
109 static void sink_mod_cb(pa_context *ctx, const pa_sink_info *i, int eol,
110                         void *userdata)
111 {
112     audio_output_t *aout = userdata;
113
114     if (eol)
115         return;
116     (void) ctx;
117
118     msg_Dbg(aout, "changing sink %"PRIu32": %s (%s)", i->index, i->name,
119             i->description);
120     aout_HotplugReport(aout, i->name, i->description);
121 }
122
123 static void sink_del(uint32_t index, audio_output_t *aout)
124 {
125     aout_sys_t *sys = aout->sys;
126     struct sink **pp = &sys->sinks, *sink;
127
128     msg_Dbg(aout, "removing sink %"PRIu32, index);
129
130     while ((sink = *pp) != NULL)
131         if (sink->index == index)
132         {
133             *pp = sink->next;
134             aout_HotplugReport(aout, sink->name, NULL);
135             free(sink);
136         }
137         else
138             pp = &sink->next;
139 }
140
141 static void sink_event(pa_context *ctx, unsigned type, uint32_t idx,
142                        audio_output_t *aout)
143 {
144     pa_operation *op = NULL;
145
146     switch (type)
147     {
148         case PA_SUBSCRIPTION_EVENT_NEW:
149             op = pa_context_get_sink_info_by_index(ctx, idx, sink_add_cb,
150                                                    aout);
151             break;
152         case PA_SUBSCRIPTION_EVENT_CHANGE:
153             op = pa_context_get_sink_info_by_index(ctx, idx, sink_mod_cb,
154                                                    aout);
155             break;
156         case PA_SUBSCRIPTION_EVENT_REMOVE:
157             sink_del(idx, aout);
158             break;
159     }
160     if (op != NULL)
161         pa_operation_unref(op);
162 }
163
164 static void sink_info_cb(pa_context *c, const pa_sink_info *i, int eol,
165                          void *userdata)
166 {
167     audio_output_t *aout = userdata;
168     aout_sys_t *sys = aout->sys;
169
170     if (eol)
171         return;
172     (void) c;
173
174     /* PulseAudio flat volume NORM / 100% / 0dB corresponds to no software
175      * amplification and maximum hardware amplification.
176      * VLC maps DEFAULT / 100% to no gain at all (software/hardware).
177      * Thus we need to use the sink base_volume as a multiplier,
178      * if and only if flat volume is active for our current sink. */
179     if (i->flags & PA_SINK_FLAT_VOLUME)
180         sys->base_volume = i->base_volume;
181     else
182         sys->base_volume = PA_VOLUME_NORM;
183     msg_Dbg(aout, "base volume: %"PRIu32, sys->base_volume);
184 }
185
186
187 /*** Latency management and lip synchronization ***/
188 static void stream_start_now(pa_stream *s, audio_output_t *aout)
189 {
190     pa_operation *op;
191
192     assert (aout->sys->trigger == NULL);
193
194     op = pa_stream_cork(s, 0, NULL, NULL);
195     if (op != NULL)
196         pa_operation_unref(op);
197     op = pa_stream_trigger(s, NULL, NULL);
198     if (likely(op != NULL))
199         pa_operation_unref(op);
200 }
201
202 static void stream_stop(pa_stream *s, audio_output_t *aout)
203 {
204     aout_sys_t *sys = aout->sys;
205     pa_operation *op;
206
207     if (sys->trigger != NULL) {
208         vlc_pa_rttime_free(sys->mainloop, sys->trigger);
209         sys->trigger = NULL;
210     }
211
212     op = pa_stream_cork(s, 1, NULL, NULL);
213     if (op != NULL)
214         pa_operation_unref(op);
215 }
216
217 static void stream_trigger_cb(pa_mainloop_api *api, pa_time_event *e,
218                               const struct timeval *tv, void *userdata)
219 {
220     audio_output_t *aout = userdata;
221     aout_sys_t *sys = aout->sys;
222
223     assert (sys->trigger == e);
224
225     msg_Dbg(aout, "starting deferred");
226     vlc_pa_rttime_free(sys->mainloop, sys->trigger);
227     sys->trigger = NULL;
228     stream_start_now(sys->stream, aout);
229     (void) api; (void) e; (void) tv;
230 }
231
232 /**
233  * Starts or resumes the playback stream.
234  * Tries start playing back audio samples at the most accurate time
235  * in order to minimize desync and resampling during early playback.
236  * @note PulseAudio lock required.
237  */
238 static void stream_start(pa_stream *s, audio_output_t *aout)
239 {
240     aout_sys_t *sys = aout->sys;
241     mtime_t delta;
242
243     assert (sys->first_pts != VLC_TS_INVALID);
244
245     if (sys->trigger != NULL) {
246         vlc_pa_rttime_free(sys->mainloop, sys->trigger);
247         sys->trigger = NULL;
248     }
249
250     delta = vlc_pa_get_latency(aout, sys->context, s);
251     if (unlikely(delta == VLC_TS_INVALID)) {
252         msg_Dbg(aout, "cannot synchronize start");
253         delta = 0; /* screwed */
254     }
255
256     delta = (sys->first_pts - mdate()) - delta;
257     if (delta > 0) {
258         msg_Dbg(aout, "deferring start (%"PRId64" us)", delta);
259         delta += pa_rtclock_now();
260         sys->trigger = pa_context_rttime_new(sys->context, delta,
261                                              stream_trigger_cb, aout);
262     } else {
263         msg_Warn(aout, "starting late (%"PRId64" us)", delta);
264         stream_start_now(s, aout);
265     }
266 }
267
268 static void stream_latency_cb(pa_stream *s, void *userdata)
269 {
270     audio_output_t *aout = userdata;
271     aout_sys_t *sys = aout->sys;
272
273     /* This callback is _never_ called while paused. */
274     if (sys->first_pts == VLC_TS_INVALID)
275         return; /* nothing to do if buffers are (still) empty */
276     if (pa_stream_is_corked(s) > 0)
277         stream_start(s, aout);
278 }
279
280
281 /*** Stream helpers ***/
282 static void stream_state_cb(pa_stream *s, void *userdata)
283 {
284     pa_threaded_mainloop *mainloop = userdata;
285
286     switch (pa_stream_get_state(s)) {
287         case PA_STREAM_READY:
288         case PA_STREAM_FAILED:
289         case PA_STREAM_TERMINATED:
290             pa_threaded_mainloop_signal(mainloop, 0);
291         default:
292             break;
293     }
294 }
295
296 static void stream_buffer_attr_cb(pa_stream *s, void *userdata)
297 {
298     audio_output_t *aout = userdata;
299     const pa_buffer_attr *pba = pa_stream_get_buffer_attr(s);
300
301     msg_Dbg(aout, "changed buffer metrics: maxlength=%u, tlength=%u, "
302             "prebuf=%u, minreq=%u",
303             pba->maxlength, pba->tlength, pba->prebuf, pba->minreq);
304 }
305
306 static void stream_event_cb(pa_stream *s, const char *name, pa_proplist *pl,
307                             void *userdata)
308 {
309     audio_output_t *aout = userdata;
310
311     if (!strcmp(name, PA_STREAM_EVENT_REQUEST_CORK))
312         aout_PolicyReport(aout, true);
313     else
314     if (!strcmp(name, PA_STREAM_EVENT_REQUEST_UNCORK))
315         aout_PolicyReport(aout, false);
316     else
317 #if PA_CHECK_VERSION(1,0,0)
318     /* FIXME: expose aout_Restart() directly */
319     if (!strcmp(name, PA_STREAM_EVENT_FORMAT_LOST)) {
320         msg_Dbg (aout, "format lost");
321         aout_RestartRequest (aout, AOUT_RESTART_OUTPUT);
322     } else
323 #endif
324         msg_Warn (aout, "unhandled stream event \"%s\"", name);
325     (void) s;
326     (void) pl;
327 }
328
329 static void stream_moved_cb(pa_stream *s, void *userdata)
330 {
331     audio_output_t *aout = userdata;
332     aout_sys_t *sys = aout->sys;
333     const char *name = pa_stream_get_device_name(s);
334     pa_operation *op;
335
336     msg_Dbg(aout, "connected to sink %s", name);
337     aout_DeviceReport(aout, name);
338
339     op = pa_context_get_sink_info_by_name(sys->context, name, sink_info_cb,
340                                           aout);
341     if (likely(op != NULL))
342         pa_operation_unref(op);
343 }
344
345 static void stream_overflow_cb(pa_stream *s, void *userdata)
346 {
347     audio_output_t *aout = userdata;
348     aout_sys_t *sys = aout->sys;
349     pa_operation *op;
350
351     msg_Err(aout, "overflow, flushing");
352     op = pa_stream_flush(s, NULL, NULL);
353     if (unlikely(op == NULL))
354         return;
355     pa_operation_unref(op);
356     sys->first_pts = VLC_TS_INVALID;
357 }
358
359 static void stream_started_cb(pa_stream *s, void *userdata)
360 {
361     audio_output_t *aout = userdata;
362
363     msg_Dbg(aout, "started");
364     (void) s;
365 }
366
367 static void stream_suspended_cb(pa_stream *s, void *userdata)
368 {
369     audio_output_t *aout = userdata;
370
371     msg_Dbg(aout, "suspended");
372     (void) s;
373 }
374
375 static void stream_underflow_cb(pa_stream *s, void *userdata)
376 {
377     audio_output_t *aout = userdata;
378
379     msg_Dbg(aout, "underflow");
380     (void) s;
381 }
382
383 static int stream_wait(pa_stream *stream, pa_threaded_mainloop *mainloop)
384 {
385     pa_stream_state_t state;
386
387     while ((state = pa_stream_get_state(stream)) != PA_STREAM_READY) {
388         if (state == PA_STREAM_FAILED || state == PA_STREAM_TERMINATED)
389             return -1;
390         pa_threaded_mainloop_wait(mainloop);
391     }
392     return 0;
393 }
394
395
396 /*** Sink input ***/
397 static void sink_input_info_cb(pa_context *ctx, const pa_sink_input_info *i,
398                                int eol, void *userdata)
399 {
400     audio_output_t *aout = userdata;
401     aout_sys_t *sys = aout->sys;
402
403     if (eol)
404         return;
405     (void) ctx;
406
407     sys->cvolume = i->volume; /* cache volume for balance preservation */
408
409     pa_volume_t volume = pa_cvolume_max(&i->volume);
410     volume = pa_sw_volume_divide(volume, sys->base_volume);
411     aout_VolumeReport(aout, (float)volume / PA_VOLUME_NORM);
412     aout_MuteReport(aout, i->mute);
413 }
414
415 static void sink_input_event(pa_context *ctx,
416                              pa_subscription_event_type_t type,
417                              uint32_t idx, audio_output_t *aout)
418 {
419     pa_operation *op;
420
421     /* Gee... PA will not provide the infos directly in the event. */
422     switch (type)
423     {
424         case PA_SUBSCRIPTION_EVENT_REMOVE:
425             msg_Err(aout, "sink input killed!");
426             break;
427
428         default:
429             op = pa_context_get_sink_input_info(ctx, idx, sink_input_info_cb,
430                                                 aout);
431             if (likely(op != NULL))
432                 pa_operation_unref(op);
433             break;
434     }
435 }
436
437
438 /*** Context ***/
439 static void context_cb(pa_context *ctx, pa_subscription_event_type_t type,
440                        uint32_t idx, void *userdata)
441 {
442     audio_output_t *aout = userdata;
443     aout_sys_t *sys = aout->sys;
444     unsigned facility = type & PA_SUBSCRIPTION_EVENT_FACILITY_MASK;
445
446     type &= PA_SUBSCRIPTION_EVENT_TYPE_MASK;
447     switch (facility)
448     {
449         case PA_SUBSCRIPTION_EVENT_SINK:
450             sink_event(ctx, type, idx, userdata);
451             break;
452
453         case PA_SUBSCRIPTION_EVENT_SINK_INPUT:
454             /* only interested in our sink input */
455             if (sys->stream != NULL && idx == pa_stream_get_index(sys->stream))
456                 sink_input_event(ctx, type, idx, userdata);
457             break;
458
459         default: /* unsubscribed facility?! */
460             assert(0);
461     }
462 }
463
464
465 /*** VLC audio output callbacks ***/
466
467 static int TimeGet(audio_output_t *aout, mtime_t *restrict delay)
468 {
469     aout_sys_t *sys = aout->sys;
470     pa_stream *s = sys->stream;
471
472     if (pa_stream_is_corked(s) > 0)
473         return -1; /* latency is irrelevant if corked */
474
475     mtime_t delta = vlc_pa_get_latency(aout, sys->context, s);
476     if (delta == VLC_TS_INVALID)
477         return -1;
478
479     *delay = delta;
480     return 0;
481 }
482
483 /* Memory free callback. The block_t address is in front of the data. */
484 static void data_free(void *data)
485 {
486     block_t **pp = data, *block;
487
488     memcpy(&block, pp - 1, sizeof (block));
489     block_Release(block);
490 }
491
492 static void *data_convert(block_t **pp)
493 {
494     block_t *block = *pp;
495     /* In most cases, there is enough head room, and this is really cheap: */
496     block = block_Realloc(block, sizeof (block), block->i_buffer);
497     *pp = block;
498     if (unlikely(block == NULL))
499         return NULL;
500
501     memcpy(block->p_buffer, &block, sizeof (block));
502     block->p_buffer += sizeof (block);
503     block->i_buffer -= sizeof (block);
504     return block->p_buffer;
505 }
506
507 /**
508  * Queue one audio frame to the playback stream
509  */
510 static void Play(audio_output_t *aout, block_t *block)
511 {
512     aout_sys_t *sys = aout->sys;
513     pa_stream *s = sys->stream;
514
515     const void *ptr = data_convert(&block);
516     if (unlikely(ptr == NULL))
517         return;
518
519     size_t len = block->i_buffer;
520
521     /* Note: The core already holds the output FIFO lock at this point.
522      * Therefore we must not under any circumstances (try to) acquire the
523      * output FIFO lock while the PulseAudio threaded main loop lock is held
524      * (including from PulseAudio stream callbacks). Otherwise lock inversion
525      * will take place, and sooner or later a deadlock. */
526     pa_threaded_mainloop_lock(sys->mainloop);
527
528     if (sys->first_pts == VLC_TS_INVALID)
529         sys->first_pts = block->i_pts;
530
531     if (pa_stream_is_corked(s) > 0)
532         stream_start(s, aout);
533
534 #if 0 /* Fault injector to test underrun recovery */
535     static volatile unsigned u = 0;
536     if ((++u % 1000) == 0) {
537         msg_Err(aout, "fault injection");
538         pa_operation_unref(pa_stream_flush(s, NULL, NULL));
539     }
540 #endif
541
542     if (pa_stream_write(s, ptr, len, data_free, 0, PA_SEEK_RELATIVE) < 0) {
543         vlc_pa_error(aout, "cannot write", sys->context);
544         block_Release(block);
545     }
546
547     pa_threaded_mainloop_unlock(sys->mainloop);
548 }
549
550 /**
551  * Cork or uncork the playback stream
552  */
553 static void Pause(audio_output_t *aout, bool paused, mtime_t date)
554 {
555     aout_sys_t *sys = aout->sys;
556     pa_stream *s = sys->stream;
557
558     pa_threaded_mainloop_lock(sys->mainloop);
559
560     if (paused) {
561         pa_stream_set_latency_update_callback(s, NULL, NULL);
562         stream_stop(s, aout);
563     } else {
564         pa_stream_set_latency_update_callback(s, stream_latency_cb, aout);
565         if (likely(sys->first_pts != VLC_TS_INVALID))
566             stream_start_now(s, aout);
567     }
568
569     pa_threaded_mainloop_unlock(sys->mainloop);
570     (void) date;
571 }
572
573 /**
574  * Flush or drain the playback stream
575  */
576 static void Flush(audio_output_t *aout, bool wait)
577 {
578     aout_sys_t *sys = aout->sys;
579     pa_stream *s = sys->stream;
580     pa_operation *op;
581
582     pa_threaded_mainloop_lock(sys->mainloop);
583
584     if (wait)
585         op = pa_stream_drain(s, NULL, NULL);
586         /* TODO: wait for drain completion*/
587     else
588         op = pa_stream_flush(s, NULL, NULL);
589     if (op != NULL)
590         pa_operation_unref(op);
591     pa_threaded_mainloop_unlock(sys->mainloop);
592 }
593
594 static int VolumeSet(audio_output_t *aout, float vol)
595 {
596     aout_sys_t *sys = aout->sys;
597     if (sys->stream == NULL)
598     {
599         msg_Err (aout, "cannot change volume while not playing");
600         return -1;
601     }
602
603     /* VLC provides the software volume so convert directly to PulseAudio
604      * software volume, pa_volume_t. This is not a linear amplification factor
605      * so do not use PulseAudio linear amplification! */
606     vol *= PA_VOLUME_NORM;
607     if (unlikely(vol >= PA_VOLUME_MAX))
608         vol = PA_VOLUME_MAX;
609     pa_volume_t volume = pa_sw_volume_multiply(lround(vol), sys->base_volume);
610
611     /* Preserve the balance (VLC does not support it). */
612     pa_cvolume cvolume = sys->cvolume;
613     pa_cvolume_scale(&cvolume, PA_VOLUME_NORM);
614     pa_sw_cvolume_multiply_scalar(&cvolume, &cvolume, volume);
615     assert(pa_cvolume_valid(&cvolume));
616
617     pa_operation *op;
618     uint32_t idx = pa_stream_get_index(sys->stream);
619     pa_threaded_mainloop_lock(sys->mainloop);
620     op = pa_context_set_sink_input_volume(sys->context, idx, &cvolume,
621                                           NULL, NULL);
622     if (likely(op != NULL))
623         pa_operation_unref(op);
624     pa_threaded_mainloop_unlock(sys->mainloop);
625
626     return 0;
627 }
628
629 static int MuteSet(audio_output_t *aout, bool mute)
630 {
631     aout_sys_t *sys = aout->sys;
632
633     if (sys->stream == NULL)
634     {
635         sys->flags_force &= ~(PA_STREAM_START_MUTED|PA_STREAM_START_UNMUTED);
636         sys->flags_force |=
637             mute ? PA_STREAM_START_MUTED : PA_STREAM_START_UNMUTED;
638         aout_MuteReport(aout, mute);
639         return 0;
640     }
641
642     pa_operation *op;
643     uint32_t idx = pa_stream_get_index(sys->stream);
644     pa_threaded_mainloop_lock(sys->mainloop);
645     op = pa_context_set_sink_input_mute(sys->context, idx, mute, NULL, NULL);
646     if (likely(op != NULL))
647         pa_operation_unref(op);
648     pa_threaded_mainloop_unlock(sys->mainloop);
649
650     return 0;
651 }
652
653 static int StreamMove(audio_output_t *aout, const char *name)
654 {
655     aout_sys_t *sys = aout->sys;
656
657     if (sys->stream == NULL)
658     {
659         msg_Dbg(aout, "will connect to sink %s", name);
660         free(sys->sink_force);
661         sys->sink_force = strdup(name);
662         return 0;
663     }
664
665     pa_operation *op;
666     uint32_t idx = pa_stream_get_index(sys->stream);
667
668     pa_threaded_mainloop_lock(sys->mainloop);
669     op = pa_context_move_sink_input_by_name(sys->context, idx, name,
670                                             NULL, NULL);
671     if (likely(op != NULL)) {
672         pa_operation_unref(op);
673         msg_Dbg(aout, "moving to sink %s", name);
674     } else
675         vlc_pa_error(aout, "cannot move sink input", sys->context);
676     pa_threaded_mainloop_unlock(sys->mainloop);
677
678     return (op != NULL) ? 0 : -1;
679 }
680
681 static void Stop(audio_output_t *);
682
683 /**
684  * Create a PulseAudio playback stream, a.k.a. a sink input.
685  */
686 static int Start(audio_output_t *aout, audio_sample_format_t *restrict fmt)
687 {
688     aout_sys_t *sys = aout->sys;
689
690     /* Sample format specification */
691     struct pa_sample_spec ss;
692 #if PA_CHECK_VERSION(1,0,0)
693     pa_encoding_t encoding = PA_ENCODING_INVALID;
694 #endif
695
696     switch (fmt->i_format)
697     {
698         case VLC_CODEC_FL64:
699             fmt->i_format = VLC_CODEC_FL32;
700         case VLC_CODEC_FL32:
701             ss.format = PA_SAMPLE_FLOAT32NE;
702             break;
703         case VLC_CODEC_S32N:
704             ss.format = PA_SAMPLE_S32NE;
705             break;
706         case VLC_CODEC_S16N:
707             ss.format = PA_SAMPLE_S16NE;
708             break;
709         case VLC_CODEC_U8:
710             ss.format = PA_SAMPLE_U8;
711             break;
712 #if PA_CHECK_VERSION(1,0,0)
713         case VLC_CODEC_A52:
714             fmt->i_format = VLC_CODEC_SPDIFL;
715             encoding = PA_ENCODING_AC3_IEC61937;
716             ss.format = HAVE_FPU ? PA_SAMPLE_FLOAT32NE : PA_SAMPLE_S16NE;
717             break;
718         /*case VLC_CODEC_EAC3:
719             fmt->i_format = VLC_CODEC_SPDIFL FIXME;
720             encoding = PA_ENCODING_EAC3_IEC61937;
721             ss.format = HAVE_FPU ? PA_SAMPLE_FLOAT32NE : PA_SAMPLE_S16NE;
722             break;
723         case VLC_CODEC_MPGA:
724             fmt->i_format = VLC_CODEC_SPDIFL FIXME;
725             encoding = PA_ENCODING_MPEG_IEC61937;
726             ss.format = HAVE_FPU ? PA_SAMPLE_FLOAT32NE : PA_SAMPLE_S16NE;
727             break;*/
728         case VLC_CODEC_DTS:
729             fmt->i_format = VLC_CODEC_SPDIFL;
730             encoding = PA_ENCODING_DTS_IEC61937;
731             ss.format = HAVE_FPU ? PA_SAMPLE_FLOAT32NE : PA_SAMPLE_S16NE;
732             break;
733 #endif
734         default:
735             if (HAVE_FPU)
736             {
737                 fmt->i_format = VLC_CODEC_FL32;
738                 ss.format = PA_SAMPLE_FLOAT32NE;
739             }
740             else
741             {
742                 fmt->i_format = VLC_CODEC_S16N;
743                 ss.format = PA_SAMPLE_S16NE;
744             }
745             break;
746     }
747
748     ss.rate = fmt->i_rate;
749     ss.channels = aout_FormatNbChannels(fmt);
750     if (!pa_sample_spec_valid(&ss)) {
751         msg_Err(aout, "unsupported sample specification");
752         return VLC_EGENERIC;
753     }
754
755     /* Channel mapping (order defined in vlc_aout.h) */
756     struct pa_channel_map map;
757     map.channels = 0;
758
759     if (fmt->i_physical_channels & AOUT_CHAN_LEFT)
760         map.map[map.channels++] = PA_CHANNEL_POSITION_FRONT_LEFT;
761     if (fmt->i_physical_channels & AOUT_CHAN_RIGHT)
762         map.map[map.channels++] = PA_CHANNEL_POSITION_FRONT_RIGHT;
763     if (fmt->i_physical_channels & AOUT_CHAN_MIDDLELEFT)
764         map.map[map.channels++] = PA_CHANNEL_POSITION_SIDE_LEFT;
765     if (fmt->i_physical_channels & AOUT_CHAN_MIDDLERIGHT)
766         map.map[map.channels++] = PA_CHANNEL_POSITION_SIDE_RIGHT;
767     if (fmt->i_physical_channels & AOUT_CHAN_REARLEFT)
768         map.map[map.channels++] = PA_CHANNEL_POSITION_REAR_LEFT;
769     if (fmt->i_physical_channels & AOUT_CHAN_REARRIGHT)
770         map.map[map.channels++] = PA_CHANNEL_POSITION_REAR_RIGHT;
771     if (fmt->i_physical_channels & AOUT_CHAN_REARCENTER)
772         map.map[map.channels++] = PA_CHANNEL_POSITION_REAR_CENTER;
773     if (fmt->i_physical_channels & AOUT_CHAN_CENTER)
774     {
775         if (ss.channels == 1)
776             map.map[map.channels++] = PA_CHANNEL_POSITION_MONO;
777         else
778             map.map[map.channels++] = PA_CHANNEL_POSITION_FRONT_CENTER;
779     }
780     if (fmt->i_physical_channels & AOUT_CHAN_LFE)
781         map.map[map.channels++] = PA_CHANNEL_POSITION_LFE;
782
783     for (unsigned i = 0; map.channels < ss.channels; i++) {
784         map.map[map.channels++] = PA_CHANNEL_POSITION_AUX0 + i;
785         msg_Warn(aout, "mapping channel %"PRIu8" to AUX%u", map.channels, i);
786     }
787
788     if (!pa_channel_map_valid(&map)) {
789         msg_Err(aout, "unsupported channel map");
790         return VLC_EGENERIC;
791     } else {
792         const char *name = pa_channel_map_to_name(&map);
793         msg_Dbg(aout, "using %s channel map", (name != NULL) ? name : "?");
794     }
795
796     /* Stream parameters */
797     pa_stream_flags_t flags = sys->flags_force
798                             | PA_STREAM_START_CORKED
799                             | PA_STREAM_INTERPOLATE_TIMING
800                             | PA_STREAM_NOT_MONOTONIC
801                             | PA_STREAM_AUTO_TIMING_UPDATE
802                             | PA_STREAM_FIX_RATE;
803
804     struct pa_buffer_attr attr;
805     attr.maxlength = -1;
806     /* PulseAudio goes berserk if the target length (tlength) is not
807      * significantly longer than 2 periods (minreq), or when the period length
808      * is unspecified and the target length is short. */
809     attr.tlength = pa_usec_to_bytes(3 * AOUT_MIN_PREPARE_TIME, &ss);
810     attr.prebuf = 0; /* trigger manually */
811     attr.minreq = pa_usec_to_bytes(AOUT_MIN_PREPARE_TIME, &ss);
812     attr.fragsize = 0; /* not used for output */
813
814     sys->stream = NULL;
815     sys->trigger = NULL;
816     sys->first_pts = VLC_TS_INVALID;
817
818     /* Channel volume */
819     sys->base_volume = PA_VOLUME_NORM;
820     pa_cvolume_set(&sys->cvolume, ss.channels, PA_VOLUME_NORM);
821
822 #if PA_CHECK_VERSION(1,0,0)
823     pa_format_info *formatv[2];
824     unsigned formatc = 0;
825
826     /* Favor digital pass-through if available*/
827     if (encoding != PA_ENCODING_INVALID) {
828         formatv[formatc] = pa_format_info_new();
829         formatv[formatc]->encoding = encoding;
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);
833         formatc++;
834
835         /* FIX flags are only permitted for PCM, and there is no way to pass
836          * different flags for different formats... */
837         flags &= ~(PA_STREAM_FIX_FORMAT
838                  | PA_STREAM_FIX_RATE
839                  | PA_STREAM_FIX_CHANNELS);
840     }
841
842     /* Fallback to PCM */
843     formatv[formatc] = pa_format_info_new();
844     formatv[formatc]->encoding = PA_ENCODING_PCM;
845     pa_format_info_set_sample_format(formatv[formatc], ss.format);
846     pa_format_info_set_rate(formatv[formatc], ss.rate);
847     pa_format_info_set_channels(formatv[formatc], ss.channels);
848     pa_format_info_set_channel_map(formatv[formatc], &map);
849     formatc++;
850
851     /* Create a playback stream */
852     pa_stream *s;
853     pa_proplist *props = pa_proplist_new();
854     if (likely(props != NULL))
855         /* TODO: set other stream properties */
856         pa_proplist_sets (props, PA_PROP_MEDIA_ROLE, "video");
857
858     pa_threaded_mainloop_lock(sys->mainloop);
859     s = pa_stream_new_extended(sys->context, "audio stream", formatv, formatc,
860                                props);
861     if (likely(props != NULL))
862         pa_proplist_free(props);
863
864     for (unsigned i = 0; i < formatc; i++)
865         pa_format_info_free(formatv[i]);
866 #else
867     pa_threaded_mainloop_lock(sys->mainloop);
868     pa_stream *s = pa_stream_new(sys->context, "audio stream", &ss, &map);
869 #endif
870     if (s == NULL) {
871         pa_threaded_mainloop_unlock(sys->mainloop);
872         vlc_pa_error(aout, "stream creation failure", sys->context);
873         return VLC_EGENERIC;
874     }
875     sys->stream = s;
876     pa_stream_set_state_callback(s, stream_state_cb, sys->mainloop);
877     pa_stream_set_buffer_attr_callback(s, stream_buffer_attr_cb, aout);
878     pa_stream_set_event_callback(s, stream_event_cb, aout);
879     pa_stream_set_latency_update_callback(s, stream_latency_cb, aout);
880     pa_stream_set_moved_callback(s, stream_moved_cb, aout);
881     pa_stream_set_overflow_callback(s, stream_overflow_cb, aout);
882     pa_stream_set_started_callback(s, stream_started_cb, aout);
883     pa_stream_set_suspended_callback(s, stream_suspended_cb, aout);
884     pa_stream_set_underflow_callback(s, stream_underflow_cb, aout);
885
886     if (pa_stream_connect_playback(s, sys->sink_force, &attr, flags, NULL,
887                                    NULL) < 0
888      || stream_wait(s, sys->mainloop)) {
889         vlc_pa_error(aout, "stream connection failure", sys->context);
890         goto fail;
891     }
892     sys->flags_force = PA_STREAM_NOFLAGS;
893     free(sys->sink_force);
894     sys->sink_force = NULL;
895
896     const struct pa_sample_spec *spec = pa_stream_get_sample_spec(s);
897 #if PA_CHECK_VERSION(1,0,0)
898     if (encoding != PA_ENCODING_INVALID) {
899         const pa_format_info *info = pa_stream_get_format_info(s);
900
901         assert (info != NULL);
902         if (pa_format_info_is_pcm (info)) {
903             msg_Dbg(aout, "digital pass-through not available");
904             fmt->i_format = HAVE_FPU ? VLC_CODEC_FL32 : VLC_CODEC_S16N;
905         } else {
906             msg_Dbg(aout, "digital pass-through enabled");
907             spec = NULL;
908         }
909     }
910 #endif
911     if (spec != NULL)
912         fmt->i_rate = spec->rate;
913
914     stream_buffer_attr_cb(s, aout);
915     stream_moved_cb(s, aout);
916     pa_threaded_mainloop_unlock(sys->mainloop);
917
918     return VLC_SUCCESS;
919
920 fail:
921     pa_threaded_mainloop_unlock(sys->mainloop);
922     Stop(aout);
923     return VLC_EGENERIC;
924 }
925
926 /**
927  * Removes a PulseAudio playback stream
928  */
929 static void Stop(audio_output_t *aout)
930 {
931     aout_sys_t *sys = aout->sys;
932     pa_stream *s = sys->stream;
933
934     pa_threaded_mainloop_lock(sys->mainloop);
935     if (unlikely(sys->trigger != NULL))
936         vlc_pa_rttime_free(sys->mainloop, sys->trigger);
937     pa_stream_disconnect(s);
938
939     /* Clear all callbacks */
940     pa_stream_set_state_callback(s, NULL, NULL);
941     pa_stream_set_buffer_attr_callback(s, NULL, NULL);
942     pa_stream_set_event_callback(s, NULL, NULL);
943     pa_stream_set_latency_update_callback(s, NULL, NULL);
944     pa_stream_set_moved_callback(s, NULL, NULL);
945     pa_stream_set_overflow_callback(s, NULL, NULL);
946     pa_stream_set_started_callback(s, NULL, NULL);
947     pa_stream_set_suspended_callback(s, NULL, NULL);
948     pa_stream_set_underflow_callback(s, NULL, NULL);
949
950     pa_stream_unref(s);
951     sys->stream = NULL;
952     pa_threaded_mainloop_unlock(sys->mainloop);
953 }
954
955 static int Open(vlc_object_t *obj)
956 {
957     audio_output_t *aout = (audio_output_t *)obj;
958     aout_sys_t *sys = malloc(sizeof (*sys));
959     pa_operation *op;
960
961 #if !PA_CHECK_VERSION(0,9,22)
962     if (!vlc_xlib_init(obj))
963         return VLC_EGENERIC;
964 #endif
965     if (unlikely(sys == NULL))
966         return VLC_ENOMEM;
967
968     /* Allocate structures */
969     pa_context *ctx = vlc_pa_connect(obj, &sys->mainloop);
970     if (ctx == NULL)
971     {
972         free(sys);
973         return VLC_EGENERIC;
974     }
975     sys->stream = NULL;
976     sys->context = ctx;
977     sys->flags_force = PA_STREAM_NOFLAGS;
978     sys->sink_force = NULL;
979     sys->sinks = NULL;
980
981     aout->sys = sys;
982     aout->start = Start;
983     aout->stop = Stop;
984     aout->time_get = TimeGet;
985     aout->play = Play;
986     aout->pause = Pause;
987     aout->flush = Flush;
988     aout->volume_set = VolumeSet;
989     aout->mute_set = MuteSet;
990     aout->device_select = StreamMove;
991
992     pa_threaded_mainloop_lock(sys->mainloop);
993     /* Sinks (output devices) list */
994     op = pa_context_get_sink_info_list(sys->context, sink_add_cb, aout);
995     if (op != NULL)
996         pa_operation_unref(op);
997
998     /* Context events */
999     const pa_subscription_mask_t mask = PA_SUBSCRIPTION_MASK_SINK
1000                                       | PA_SUBSCRIPTION_MASK_SINK_INPUT;
1001     pa_context_set_subscribe_callback(sys->context, context_cb, aout);
1002     op = pa_context_subscribe(sys->context, mask, NULL, NULL);
1003     if (likely(op != NULL))
1004        pa_operation_unref(op);
1005     pa_threaded_mainloop_unlock(sys->mainloop);
1006
1007     return VLC_SUCCESS;
1008 }
1009
1010 static void Close(vlc_object_t *obj)
1011 {
1012     audio_output_t *aout = (audio_output_t *)obj;
1013     aout_sys_t *sys = aout->sys;
1014     pa_context *ctx = sys->context;
1015
1016     pa_threaded_mainloop_lock(sys->mainloop);
1017     pa_context_set_subscribe_callback(sys->context, NULL, NULL);
1018     pa_threaded_mainloop_unlock(sys->mainloop);
1019     vlc_pa_disconnect(obj, ctx, sys->mainloop);
1020
1021     for (struct sink *sink = sys->sinks, *next; sink != NULL; sink = next)
1022     {
1023         next = sink->next;
1024         free(sink);
1025     }
1026     free(sys->sink_force);
1027     free(sys);
1028 }