]> git.sesse.net Git - vlc/blob - modules/audio_output/pulse.c
PulseAudio: log buffer attribute changes
[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_buffer_attr_cb(pa_stream *s, void *userdata)
374 {
375     audio_output_t *aout = userdata;
376     const pa_buffer_attr *pba = pa_stream_get_buffer_attr(s);
377
378     msg_Dbg(aout, "changed buffer metrics: maxlength=%u, tlength=%u, "
379             "prebuf=%u, minreq=%u",
380             pba->maxlength, pba->tlength, pba->prebuf, pba->minreq);
381 }
382
383 static void stream_event_cb(pa_stream *s, const char *name, pa_proplist *pl,
384                             void *userdata)
385 {
386     audio_output_t *aout = userdata;
387
388     if (!strcmp(name, PA_STREAM_EVENT_REQUEST_CORK))
389         aout_PolicyReport(aout, true);
390     else
391     if (!strcmp(name, PA_STREAM_EVENT_REQUEST_UNCORK))
392         aout_PolicyReport(aout, false);
393     else
394 #if PA_CHECK_VERSION(1,0,0)
395     /* FIXME: expose aout_Restart() directly */
396     if (!strcmp(name, PA_STREAM_EVENT_FORMAT_LOST)) {
397         vlc_value_t dummy = { .i_int = 0 };
398
399         msg_Dbg (aout, "format lost");
400         aout_ChannelsRestart (VLC_OBJECT(aout), "audio-device",
401                               dummy, dummy, NULL);
402     } else
403 #endif
404         msg_Warn (aout, "unhandled stream event \"%s\"", name);
405     (void) s;
406     (void) pl;
407 }
408
409 static void stream_moved_cb(pa_stream *s, void *userdata)
410 {
411     audio_output_t *aout = userdata;
412     aout_sys_t *sys = aout->sys;
413     pa_operation *op;
414     uint32_t idx = pa_stream_get_device_index(s);
415
416     msg_Dbg(aout, "connected to sink %"PRIu32": %s", idx,
417                   pa_stream_get_device_name(s));
418     op = pa_context_get_sink_info_by_index(sys->context, idx,
419                                            sink_info_cb, aout);
420     if (likely(op != NULL))
421         pa_operation_unref(op);
422
423     /* Update the variable if someone else moved our stream */
424     var_Change(aout, "audio-device", VLC_VAR_SETVALUE,
425                &(vlc_value_t){ .i_int = idx }, NULL);
426
427     /* Sink unknown as yet, create stub choice for it */
428     if (var_GetInteger(aout, "audio-device") != idx)
429     {
430         var_Change(aout, "audio-device", VLC_VAR_ADDCHOICE,
431                    &(vlc_value_t){ .i_int = idx },
432                    &(vlc_value_t){ .psz_string = (char *)"?" });
433         var_Change(aout, "audio-device", VLC_VAR_SETVALUE,
434                    &(vlc_value_t){ .i_int = idx }, NULL);
435     }
436 }
437
438 static void stream_overflow_cb(pa_stream *s, void *userdata)
439 {
440     audio_output_t *aout = userdata;
441     pa_operation *op;
442
443     msg_Err(aout, "overflow, flushing");
444     op = pa_stream_flush(s, NULL, NULL);
445     if (likely(op != NULL))
446         pa_operation_unref(op);
447     stream_reset_sync(s, aout);
448 }
449
450 static void stream_started_cb(pa_stream *s, void *userdata)
451 {
452     audio_output_t *aout = userdata;
453
454     msg_Dbg(aout, "started");
455     (void) s;
456 }
457
458 static void stream_suspended_cb(pa_stream *s, void *userdata)
459 {
460     audio_output_t *aout = userdata;
461
462     msg_Dbg(aout, "suspended");
463     (void) s;
464 }
465
466 static void stream_underflow_cb(pa_stream *s, void *userdata)
467 {
468     audio_output_t *aout = userdata;
469
470     msg_Warn(aout, "underflow");
471     stream_stop(s, aout);
472     stream_reset_sync(s, aout);
473 }
474
475 static int stream_wait(pa_stream *stream, pa_threaded_mainloop *mainloop)
476 {
477     pa_stream_state_t state;
478
479     while ((state = pa_stream_get_state(stream)) != PA_STREAM_READY) {
480         if (state == PA_STREAM_FAILED || state == PA_STREAM_TERMINATED)
481             return -1;
482         pa_threaded_mainloop_wait(mainloop);
483     }
484     return 0;
485 }
486
487
488 /*** Sink input ***/
489 static void sink_input_info_cb(pa_context *ctx, const pa_sink_input_info *i,
490                                int eol, void *userdata)
491 {
492     audio_output_t *aout = userdata;
493     aout_sys_t *sys = aout->sys;
494
495     if (eol)
496         return;
497     (void) ctx;
498
499     sys->cvolume = i->volume; /* cache volume for balance preservation */
500
501     pa_volume_t volume = pa_cvolume_max(&i->volume);
502     volume = pa_sw_volume_divide(volume, sys->base_volume);
503     aout_VolumeReport(aout, (float)volume / PA_VOLUME_NORM);
504     aout_MuteReport(aout, i->mute);
505 }
506
507
508 /*** VLC audio output callbacks ***/
509
510 /* Memory free callback. The block_t address is in front of the data. */
511 static void data_free(void *data)
512 {
513     block_t **pp = data, *block;
514
515     memcpy(&block, pp - 1, sizeof (block));
516     block_Release(block);
517 }
518
519 static void *data_convert(block_t **pp)
520 {
521     block_t *block = *pp;
522     /* In most cases, there is enough head room, and this is really cheap: */
523     block = block_Realloc(block, sizeof (block), block->i_buffer);
524     *pp = block;
525     if (unlikely(block == NULL))
526         return NULL;
527
528     memcpy(block->p_buffer, &block, sizeof (block));
529     block->p_buffer += sizeof (block);
530     block->i_buffer -= sizeof (block);
531     return block->p_buffer;
532 }
533
534 /**
535  * Queue one audio frame to the playback stream
536  */
537 static void Play(audio_output_t *aout, block_t *block, mtime_t *restrict drift)
538 {
539     aout_sys_t *sys = aout->sys;
540     pa_stream *s = sys->stream;
541
542     assert (sys->paused == VLC_TS_INVALID);
543
544     const void *ptr = data_convert(&block);
545     if (unlikely(ptr == NULL))
546         return;
547
548     size_t len = block->i_buffer;
549     mtime_t pts = block->i_pts + block->i_length;
550
551     /* Note: The core already holds the output FIFO lock at this point.
552      * Therefore we must not under any circumstances (try to) acquire the
553      * output FIFO lock while the PulseAudio threaded main loop lock is held
554      * (including from PulseAudio stream callbacks). Otherwise lock inversion
555      * will take place, and sooner or later a deadlock. */
556     pa_threaded_mainloop_lock(sys->mainloop);
557
558     if (sys->first_pts == VLC_TS_INVALID)
559         sys->first_pts = block->i_pts;
560     sys->last_pts = pts;
561
562     if (pa_stream_is_corked(s) > 0)
563         stream_start(s, aout);
564
565 #if 0 /* Fault injector to test underrun recovery */
566     static volatile unsigned u = 0;
567     if ((++u % 1000) == 0) {
568         msg_Err(aout, "fault injection");
569         pa_operation_unref(pa_stream_flush(s, NULL, NULL));
570     }
571 #endif
572
573     if (pa_stream_write(s, ptr, len, data_free, 0, PA_SEEK_RELATIVE) < 0) {
574         vlc_pa_error(aout, "cannot write", sys->context);
575         block_Release(block);
576     }
577
578     pa_threaded_mainloop_unlock(sys->mainloop);
579     (void) drift;
580 }
581
582 /**
583  * Cork or uncork the playback stream
584  */
585 static void Pause(audio_output_t *aout, bool paused, mtime_t date)
586 {
587     aout_sys_t *sys = aout->sys;
588     pa_stream *s = sys->stream;
589
590     pa_threaded_mainloop_lock(sys->mainloop);
591
592     if (paused) {
593         sys->paused = date;
594         stream_stop(s, aout);
595     } else {
596         assert (sys->paused != VLC_TS_INVALID);
597         date -= sys->paused;
598         msg_Dbg(aout, "resuming after %"PRId64" us", date);
599         sys->paused = VLC_TS_INVALID;
600
601         if (sys->last_pts != VLC_TS_INVALID) {
602             sys->first_pts += date;
603             sys->last_pts += date;
604             stream_start(s, aout);
605         }
606     }
607
608     pa_threaded_mainloop_unlock(sys->mainloop);
609 }
610
611 /**
612  * Flush or drain the playback stream
613  */
614 static void Flush(audio_output_t *aout, bool wait)
615 {
616     aout_sys_t *sys = aout->sys;
617     pa_stream *s = sys->stream;
618     pa_operation *op;
619
620     pa_threaded_mainloop_lock(sys->mainloop);
621
622     if (wait)
623         op = pa_stream_drain(s, NULL, NULL);
624         /* TODO: wait for drain completion*/
625     else
626         op = pa_stream_flush(s, NULL, NULL);
627     if (op != NULL)
628         pa_operation_unref(op);
629     pa_threaded_mainloop_unlock(sys->mainloop);
630 }
631
632 static int VolumeSet(audio_output_t *aout, float vol)
633 {
634     aout_sys_t *sys = aout->sys;
635     pa_operation *op;
636     uint32_t idx = pa_stream_get_index(sys->stream);
637
638     /* VLC provides the software volume so convert directly to PulseAudio
639      * software volume, pa_volume_t. This is not a linear amplification factor
640      * so do not use PulseAudio linear amplification! */
641     vol *= PA_VOLUME_NORM;
642     if (unlikely(vol >= PA_VOLUME_MAX))
643         vol = PA_VOLUME_MAX;
644     pa_volume_t volume = pa_sw_volume_multiply(lround(vol), sys->base_volume);
645
646     /* Preserve the balance (VLC does not support it). */
647     pa_cvolume cvolume = sys->cvolume;
648     pa_cvolume_scale(&cvolume, PA_VOLUME_NORM);
649     pa_sw_cvolume_multiply_scalar(&cvolume, &cvolume, volume);
650
651     assert(pa_cvolume_valid(&cvolume));
652
653     pa_threaded_mainloop_lock(sys->mainloop);
654     op = pa_context_set_sink_input_volume(sys->context, idx, &cvolume, NULL, NULL);
655     if (likely(op != NULL))
656         pa_operation_unref(op);
657     pa_threaded_mainloop_unlock(sys->mainloop);
658
659     return 0;
660 }
661
662 static int MuteSet(audio_output_t *aout, bool mute)
663 {
664     aout_sys_t *sys = aout->sys;
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_set_sink_input_mute(sys->context, idx, mute, NULL, NULL);
670     if (likely(op != NULL))
671         pa_operation_unref(op);
672     pa_threaded_mainloop_unlock(sys->mainloop);
673
674     return 0;
675 }
676
677 static int StreamMove(vlc_object_t *obj, const char *varname, vlc_value_t old,
678                       vlc_value_t val, void *userdata)
679 {
680     audio_output_t *aout = (audio_output_t *)obj;
681     aout_sys_t *sys = aout->sys;
682     pa_stream *s = userdata;
683     pa_operation *op;
684     uint32_t idx = pa_stream_get_index(s);
685     uint32_t sink_idx = val.i_int;
686
687     (void) varname; (void) old;
688
689     pa_threaded_mainloop_lock(sys->mainloop);
690     op = pa_context_move_sink_input_by_index(sys->context, idx, sink_idx,
691                                              NULL, NULL);
692     if (likely(op != NULL)) {
693         pa_operation_unref(op);
694         msg_Dbg(aout, "moving to sink %"PRIu32, sink_idx);
695     } else
696         vlc_pa_error(obj, "cannot move sink", sys->context);
697     pa_threaded_mainloop_unlock(sys->mainloop);
698
699     return (op != NULL) ? VLC_SUCCESS : VLC_EGENERIC;
700 }
701
702
703 /**
704  * Create a PulseAudio playback stream, a.k.a. a sink input.
705  */
706 static int Open(vlc_object_t *obj)
707 {
708 #if !PA_CHECK_VERSION(0,9,22)
709     if (!vlc_xlib_init(obj))
710         return VLC_EGENERIC;
711 #endif
712
713     audio_output_t *aout = (audio_output_t *)obj;
714     pa_operation *op;
715
716     /* Sample format specification */
717     struct pa_sample_spec ss;
718     vlc_fourcc_t format = aout->format.i_format;
719 #if PA_CHECK_VERSION(1,0,0)
720     pa_encoding_t encoding = PA_ENCODING_INVALID;
721 #endif
722
723     switch(format)
724     {
725         case VLC_CODEC_F64B:
726             format = VLC_CODEC_F32B;
727         case VLC_CODEC_F32B:
728             ss.format = PA_SAMPLE_FLOAT32BE;
729             break;
730         case VLC_CODEC_F64L:
731             format = VLC_CODEC_F32L;
732         case VLC_CODEC_F32L:
733             ss.format = PA_SAMPLE_FLOAT32LE;
734             break;
735         case VLC_CODEC_S32B:
736             ss.format = PA_SAMPLE_S32BE;
737             break;
738         case VLC_CODEC_S32L:
739             ss.format = PA_SAMPLE_S32LE;
740             break;
741         case VLC_CODEC_S24B:
742             ss.format = PA_SAMPLE_S24BE;
743             break;
744         case VLC_CODEC_S24L:
745             ss.format = PA_SAMPLE_S24LE;
746             break;
747         case VLC_CODEC_S16B:
748             ss.format = PA_SAMPLE_S16BE;
749             break;
750         case VLC_CODEC_S16L:
751             ss.format = PA_SAMPLE_S16LE;
752             break;
753         case VLC_CODEC_S8:
754             format = VLC_CODEC_U8;
755         case VLC_CODEC_U8:
756             ss.format = PA_SAMPLE_U8;
757             break;
758 #if PA_CHECK_VERSION(1,0,0)
759         case VLC_CODEC_A52:
760             format = VLC_CODEC_SPDIFL;
761             encoding = PA_ENCODING_AC3_IEC61937;
762             ss.format = HAVE_FPU ? PA_SAMPLE_FLOAT32NE : PA_SAMPLE_S16NE;
763             break;
764         /*case VLC_CODEC_EAC3:
765             format = VLC_CODEC_SPDIFL FIXME;
766             encoding = PA_ENCODING_EAC3_IEC61937;
767             ss.format = HAVE_FPU ? PA_SAMPLE_FLOAT32NE : PA_SAMPLE_S16NE;
768             break;
769         case VLC_CODEC_MPGA:
770             format = VLC_CODEC_SPDIFL FIXME;
771             encoding = PA_ENCODING_MPEG_IEC61937;
772             ss.format = HAVE_FPU ? PA_SAMPLE_FLOAT32NE : PA_SAMPLE_S16NE;
773             break;*/
774         case VLC_CODEC_DTS:
775             format = VLC_CODEC_SPDIFL;
776             encoding = PA_ENCODING_DTS_IEC61937;
777             ss.format = HAVE_FPU ? PA_SAMPLE_FLOAT32NE : PA_SAMPLE_S16NE;
778             break;
779 #endif
780         default:
781             if (HAVE_FPU)
782             {
783                 format = VLC_CODEC_FL32;
784                 ss.format = PA_SAMPLE_FLOAT32NE;
785             }
786             else
787             {
788                 format = VLC_CODEC_S16N;
789                 ss.format = PA_SAMPLE_S16NE;
790             }
791             break;
792     }
793
794     ss.rate = aout->format.i_rate;
795     ss.channels = aout_FormatNbChannels(&aout->format);
796     if (!pa_sample_spec_valid(&ss)) {
797         msg_Err(aout, "unsupported sample specification");
798         return VLC_EGENERIC;
799     }
800
801     /* Channel mapping (order defined in vlc_aout.h) */
802     struct pa_channel_map map;
803     map.channels = 0;
804
805     if (aout->format.i_physical_channels & AOUT_CHAN_LEFT)
806         map.map[map.channels++] = PA_CHANNEL_POSITION_FRONT_LEFT;
807     if (aout->format.i_physical_channels & AOUT_CHAN_RIGHT)
808         map.map[map.channels++] = PA_CHANNEL_POSITION_FRONT_RIGHT;
809     if (aout->format.i_physical_channels & AOUT_CHAN_MIDDLELEFT)
810         map.map[map.channels++] = PA_CHANNEL_POSITION_SIDE_LEFT;
811     if (aout->format.i_physical_channels & AOUT_CHAN_MIDDLERIGHT)
812         map.map[map.channels++] = PA_CHANNEL_POSITION_SIDE_RIGHT;
813     if (aout->format.i_physical_channels & AOUT_CHAN_REARLEFT)
814         map.map[map.channels++] = PA_CHANNEL_POSITION_REAR_LEFT;
815     if (aout->format.i_physical_channels & AOUT_CHAN_REARRIGHT)
816         map.map[map.channels++] = PA_CHANNEL_POSITION_REAR_RIGHT;
817     if (aout->format.i_physical_channels & AOUT_CHAN_REARCENTER)
818         map.map[map.channels++] = PA_CHANNEL_POSITION_REAR_CENTER;
819     if (aout->format.i_physical_channels & AOUT_CHAN_CENTER)
820     {
821         if (ss.channels == 1)
822             map.map[map.channels++] = PA_CHANNEL_POSITION_MONO;
823         else
824             map.map[map.channels++] = PA_CHANNEL_POSITION_FRONT_CENTER;
825     }
826     if (aout->format.i_physical_channels & AOUT_CHAN_LFE)
827         map.map[map.channels++] = PA_CHANNEL_POSITION_LFE;
828
829     for (unsigned i = 0; map.channels < ss.channels; i++) {
830         map.map[map.channels++] = PA_CHANNEL_POSITION_AUX0 + i;
831         msg_Warn(aout, "mapping channel %"PRIu8" to AUX%u", map.channels, i);
832     }
833
834     if (!pa_channel_map_valid(&map)) {
835         msg_Err(aout, "unsupported channel map");
836         return VLC_EGENERIC;
837     } else {
838         const char *name = pa_channel_map_to_name(&map);
839         msg_Dbg(aout, "using %s channel map", (name != NULL) ? name : "?");
840     }
841
842     /* Stream parameters */
843     const pa_stream_flags_t flags = PA_STREAM_START_CORKED
844                                   //| PA_STREAM_INTERPOLATE_TIMING
845                                     | PA_STREAM_NOT_MONOTONIC
846                                   | PA_STREAM_AUTO_TIMING_UPDATE
847                                   | PA_STREAM_VARIABLE_RATE;
848
849     struct pa_buffer_attr attr;
850     attr.maxlength = -1;
851     /* PulseAudio assumes that tlength bytes are available in the buffer. Thus
852      * we need to be conservative and set the minimum value that the VLC
853      * audio decoder thread warrants. Otherwise, PulseAudio buffers will
854      * underrun on hardware with large buffers. VLC keeps at least
855      * AOUT_MIN_PREPARE and at most AOUT_MAX_PREPARE worth of audio buffers.
856      * TODO? tlength could be adaptively increased to reduce wakeups. */
857     attr.tlength = pa_usec_to_bytes(AOUT_MIN_PREPARE_TIME, &ss);
858     attr.prebuf = 0; /* trigger manually */
859     attr.minreq = -1;
860     attr.fragsize = 0; /* not used for output */
861
862     /* Allocate structures */
863     aout_sys_t *sys = malloc(sizeof(*sys));
864     if (unlikely(sys == NULL))
865         return VLC_ENOMEM;
866
867     pa_context *ctx = vlc_pa_connect(obj, &sys->mainloop);
868     if (ctx == NULL)
869     {
870         free (sys);
871         return VLC_EGENERIC;
872     }
873
874     aout->sys = sys;
875     sys->stream = NULL;
876     sys->context = ctx;
877     sys->trigger = NULL;
878     sys->first_pts = VLC_TS_INVALID;
879     sys->last_pts = VLC_TS_INVALID;
880     sys->paused = VLC_TS_INVALID;
881     sys->desync = 0;
882     sys->rate = ss.rate;
883
884     /* Channel volume */
885     sys->base_volume = PA_VOLUME_NORM;
886     pa_cvolume_set(&sys->cvolume, ss.channels, PA_VOLUME_NORM);
887
888 #if PA_CHECK_VERSION(1,0,0)
889     pa_format_info *formatv[2];
890     unsigned formatc = 0;
891
892     /* Favor digital pass-through if available*/
893     if (encoding != PA_ENCODING_INVALID) {
894         formatv[formatc] = pa_format_info_new();
895         formatv[formatc]->encoding = encoding;
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
902     /* Fallback to PCM */
903     formatv[formatc] = pa_format_info_new();
904     formatv[formatc]->encoding = PA_ENCODING_PCM;
905     pa_format_info_set_sample_format(formatv[formatc], ss.format);
906     pa_format_info_set_rate(formatv[formatc], ss.rate);
907     pa_format_info_set_channels(formatv[formatc], ss.channels);
908     pa_format_info_set_channel_map(formatv[formatc], &map);
909     formatc++;
910
911     /* Create a playback stream */
912     pa_stream *s;
913     pa_proplist *props = pa_proplist_new();
914     if (likely(props != NULL))
915         /* TODO: set other stream properties */
916         pa_proplist_sets (props, PA_PROP_MEDIA_ROLE, "video");
917
918     pa_threaded_mainloop_lock(sys->mainloop);
919     s = pa_stream_new_extended(ctx, "audio stream", formatv, formatc, props);
920     if (likely(props != NULL))
921         pa_proplist_free(props);
922
923     for (unsigned i = 0; i < formatc; i++)
924         pa_format_info_free(formatv[i]);
925 #else
926     pa_threaded_mainloop_lock(sys->mainloop);
927     pa_stream *s = pa_stream_new(ctx, "audio stream", &ss, &map);
928 #endif
929     if (s == NULL) {
930         vlc_pa_error(obj, "stream creation failure", ctx);
931         goto fail;
932     }
933     sys->stream = s;
934     pa_stream_set_state_callback(s, stream_state_cb, sys->mainloop);
935     pa_stream_set_buffer_attr_callback(s, stream_buffer_attr_cb, aout);
936     pa_stream_set_event_callback(s, stream_event_cb, aout);
937     pa_stream_set_latency_update_callback(s, stream_latency_cb, aout);
938     pa_stream_set_moved_callback(s, stream_moved_cb, aout);
939     pa_stream_set_overflow_callback(s, stream_overflow_cb, aout);
940     pa_stream_set_started_callback(s, stream_started_cb, aout);
941     pa_stream_set_suspended_callback(s, stream_suspended_cb, aout);
942     pa_stream_set_underflow_callback(s, stream_underflow_cb, aout);
943
944     if (pa_stream_connect_playback(s, NULL, &attr, flags, NULL, NULL) < 0
945      || stream_wait(s, sys->mainloop)) {
946         vlc_pa_error(obj, "stream connection failure", ctx);
947         goto fail;
948     }
949
950 #if PA_CHECK_VERSION(1,0,0)
951     if (encoding != PA_ENCODING_INVALID) {
952         const pa_format_info *info = pa_stream_get_format_info(s);
953
954         assert (info != NULL);
955         if (pa_format_info_is_pcm (info)) {
956             msg_Dbg(aout, "digital pass-through not available");
957             format = HAVE_FPU ? VLC_CODEC_FL32 : VLC_CODEC_S16N;
958         } else {
959             msg_Dbg(aout, "digital pass-through enabled");
960             pa_stream_set_latency_update_callback(s, NULL, NULL);
961         }
962     }
963 #endif
964     stream_buffer_attr_cb(s, aout);
965
966     var_Create(aout, "audio-device", VLC_VAR_INTEGER|VLC_VAR_HASCHOICE);
967     var_Change(aout, "audio-device", VLC_VAR_SETTEXT,
968                &(vlc_value_t){ .psz_string = (char *)_("Audio device") },
969                NULL);
970     var_AddCallback (aout, "audio-device", StreamMove, s);
971     op = pa_context_get_sink_info_list(ctx, sink_list_cb, aout);
972     /* We may need to wait for completion... once LibVLC supports this */
973     if (op != NULL)
974         pa_operation_unref(op);
975     stream_moved_cb(s, aout);
976
977     /* Context events */
978     const pa_subscription_mask_t mask = PA_SUBSCRIPTION_MASK_SINK
979                                       | PA_SUBSCRIPTION_MASK_SINK_INPUT;
980     pa_context_set_subscribe_callback(ctx, context_cb, aout);
981     op = pa_context_subscribe(ctx, mask, NULL, NULL);
982     if (likely(op != NULL))
983        pa_operation_unref(op);
984     pa_threaded_mainloop_unlock(sys->mainloop);
985
986     aout->format.i_format = format;
987     aout->pf_play = Play;
988     aout->pf_pause = Pause;
989     aout->pf_flush = Flush;
990     aout->volume_set = VolumeSet;
991     aout->mute_set = MuteSet;
992     return VLC_SUCCESS;
993
994 fail:
995     pa_threaded_mainloop_unlock(sys->mainloop);
996     Close(obj);
997     return VLC_EGENERIC;
998 }
999
1000 /**
1001  * Removes a PulseAudio playback stream
1002  */
1003 static void Close (vlc_object_t *obj)
1004 {
1005     audio_output_t *aout = (audio_output_t *)obj;
1006     aout_sys_t *sys = aout->sys;
1007     pa_context *ctx = sys->context;
1008     pa_stream *s = sys->stream;
1009
1010     if (s != NULL) {
1011         /* The callback takes mainloop lock, so it CANNOT be held here! */
1012         var_DelCallback (aout, "audio-device", StreamMove, s);
1013         var_Destroy (aout, "audio-device");
1014
1015         pa_threaded_mainloop_lock(sys->mainloop);
1016         if (unlikely(sys->trigger != NULL))
1017             vlc_pa_rttime_free(sys->mainloop, sys->trigger);
1018         pa_stream_disconnect(s);
1019
1020         /* Clear all callbacks */
1021         pa_stream_set_state_callback(s, NULL, NULL);
1022         pa_stream_set_buffer_attr_callback(s, NULL, NULL);
1023         pa_stream_set_event_callback(s, NULL, NULL);
1024         pa_stream_set_latency_update_callback(s, NULL, NULL);
1025         pa_stream_set_moved_callback(s, NULL, NULL);
1026         pa_stream_set_overflow_callback(s, NULL, NULL);
1027         pa_stream_set_started_callback(s, NULL, NULL);
1028         pa_stream_set_suspended_callback(s, NULL, NULL);
1029         pa_stream_set_underflow_callback(s, NULL, NULL);
1030         pa_context_set_subscribe_callback(ctx, NULL, NULL);
1031
1032         pa_stream_unref(s);
1033         pa_threaded_mainloop_unlock(sys->mainloop);
1034     }
1035
1036     vlc_pa_disconnect(obj, ctx, sys->mainloop);
1037     free(sys);
1038 }