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