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