]> git.sesse.net Git - vlc/blob - modules/audio_output/alsa.c
Update NEWS, LIST and po for DASH
[vlc] / modules / audio_output / alsa.c
1 /*****************************************************************************
2  * alsa.c : alsa plugin for vlc
3  *****************************************************************************
4  * Copyright (C) 2000-2010 the VideoLAN team
5  * Copyright (C) 2009-2011 RĂ©mi Denis-Courmont
6  *
7  * Authors: Henri Fallon <henri@videolan.org> - Original Author
8  *          Jeffrey Baker <jwbaker@acm.org> - Port to ALSA 1.0 API
9  *          John Paul Lorenti <jpl31@columbia.edu> - Device selection
10  *          Arnaud de Bossoreille de Ribou <bozo@via.ecp.fr> - S/PDIF and aout3
11  *
12  * This program is free software; you can redistribute it and/or modify
13  * it under the terms of the GNU General Public License as published by
14  * the Free Software Foundation; either version 2 of the License, or
15  * (at your option) any later version.
16  *
17  * This program is distributed in the hope that it will be useful,
18  * but WITHOUT ANY WARRANTY; without even the implied warranty of
19  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20  * GNU General Public License for more details.
21  *
22  * You should have received a copy of the GNU General Public License
23  * along with this program; if not, write to the Free Software
24  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
25  *****************************************************************************/
26
27 #ifdef HAVE_CONFIG_H
28 # include "config.h"
29 #endif
30
31 #include <assert.h>
32
33 #include <vlc_common.h>
34 #include <vlc_plugin.h>
35 #include <vlc_dialog.h>
36 #include <vlc_aout.h>
37 #include <vlc_cpu.h>
38
39 #include <alsa/asoundlib.h>
40 #include <alsa/version.h>
41
42 /** Private data for an ALSA PCM playback stream */
43 struct aout_sys_t
44 {
45     snd_pcm_t *pcm;
46 };
47
48 #define A52_FRAME_NB 1536
49
50 /*****************************************************************************
51  * Local prototypes
52  *****************************************************************************/
53 static int Open (vlc_object_t *);
54 static void Close (vlc_object_t *);
55 static int FindDevicesCallback( vlc_object_t *p_this, char const *psz_name,
56                                 vlc_value_t newval, vlc_value_t oldval, void *p_unused );
57 static void GetDevices (vlc_object_t *, module_config_t *, const char *);
58
59 /*****************************************************************************
60  * Module descriptor
61  *****************************************************************************/
62 static const char *const ppsz_devices[] = {
63     "default", "plug:front",
64     "plug:side", "plug:rear", "plug:center_lfe",
65     "plug:surround40", "plug:surround41",
66     "plug:surround50", "plug:surround51",
67     "plug:surround71",
68     "hdmi", "iec958",
69 };
70 static const char *const ppsz_devices_text[] = {
71     N_("Default"), N_("Front speakers"),
72     N_("Side speakers"), N_("Rear speakers"), N_("Center and subwoofer"),
73     N_("Surround 4.0"), N_("Surround 4.1"),
74     N_("Surround 5.0"), N_("Surround 5.1"),
75     N_("Surround 7.1"),
76     N_("HDMI"), N_("S/PDIF"),
77 };
78
79 vlc_module_begin ()
80     set_shortname( "ALSA" )
81     set_description( N_("ALSA audio output") )
82     set_category( CAT_AUDIO )
83     set_subcategory( SUBCAT_AUDIO_AOUT )
84     add_string ("alsa-audio-device", "default", N_("ALSA device"), NULL, false)
85         change_string_list( ppsz_devices, ppsz_devices_text, FindDevicesCallback )
86         change_action_add( FindDevicesCallback, N_("Refresh list") )
87
88     set_capability( "audio output", 150 )
89     set_callbacks( Open, Close )
90 vlc_module_end ()
91
92
93 /** Helper for ALSA -> VLC debugging output */
94 static void Dump (vlc_object_t *obj, const char *msg,
95                   int (*cb)(void *, snd_output_t *), void *p)
96 {
97     snd_output_t *output;
98     char *str;
99
100     if (unlikely(snd_output_buffer_open (&output)))
101         return;
102
103     int val = cb (p, output);
104     if (val)
105     {
106         msg_Warn (obj, "cannot get info: %s", snd_strerror (val));
107         return;
108     }
109
110     size_t len = snd_output_buffer_string (output, &str);
111     if (len > 0 && str[len - 1])
112         len--; /* strip trailing newline */
113     msg_Dbg (obj, "%s%.*s", msg, (int)len, str);
114     snd_output_close (output);
115 }
116 #define Dump(o, m, cb, p) \
117         Dump(VLC_OBJECT(o), m, (int (*)(void *, snd_output_t *))(cb), p)
118
119 static void DumpDevice (vlc_object_t *obj, snd_pcm_t *pcm)
120 {
121     snd_pcm_info_t *info;
122
123     Dump (obj, " ", snd_pcm_dump, pcm);
124     snd_pcm_info_alloca (&info);
125     if (snd_pcm_info (pcm, info) == 0)
126     {
127         msg_Dbg (obj, " device name   : %s", snd_pcm_info_get_name (info));
128         msg_Dbg (obj, " device ID     : %s", snd_pcm_info_get_id (info));
129         msg_Dbg (obj, " subdevice name: %s",
130                 snd_pcm_info_get_subdevice_name (info));
131     }
132 }
133
134 static void DumpDeviceStatus (vlc_object_t *obj, snd_pcm_t *pcm)
135 {
136     snd_pcm_status_t *status;
137
138     snd_pcm_status_alloca (&status);
139     snd_pcm_status (pcm, status);
140     Dump (obj, "current status:\n", snd_pcm_status_dump, status);
141 }
142 #define DumpDeviceStatus(o, p) DumpDeviceStatus(VLC_OBJECT(o), p)
143
144 /**
145  * Initializes list of devices.
146  */
147 static void Probe (vlc_object_t *obj, const char *dev)
148 {
149     /* Due to design bug in audio output core, this hack is required: */
150     if (var_Type (obj, "audio-device") == 0)
151     {
152         /* The variable does not exist - first call. */
153         vlc_value_t text;
154
155         var_Create (obj, "audio-device", VLC_VAR_STRING | VLC_VAR_HASCHOICE);
156         text.psz_string = _("Audio Device");
157         var_Change (obj, "audio-device", VLC_VAR_SETTEXT, &text, NULL);
158
159         GetDevices (obj, NULL, dev);
160     }
161     var_AddCallback (obj, "audio-device", aout_ChannelsRestart, NULL);
162     var_TriggerCallback (obj, "intf-change");
163 }
164
165
166 static void Play  (audio_output_t *, block_t *);
167 static void Pause (audio_output_t *, bool, mtime_t);
168 static void PauseDummy (audio_output_t *, bool, mtime_t);
169 static void Flush (audio_output_t *, bool);
170
171 /** Initializes an ALSA playback stream */
172 static int Open (vlc_object_t *obj)
173 {
174     audio_output_t *aout = (audio_output_t *)obj;
175
176     /* Get device name */
177     char *device;
178
179     if (var_Type (aout, "audio-device"))
180         device = var_GetString (aout, "audio-device");
181     else
182         device = var_InheritString (aout, "alsa-audio-device");
183     if (unlikely(device == NULL))
184         return VLC_ENOMEM;
185
186     snd_pcm_format_t pcm_format; /* ALSA sample format */
187     vlc_fourcc_t fourcc = aout->format.i_format;
188     bool spdif = false;
189
190     switch (fourcc)
191     {
192         case VLC_CODEC_F64B:
193             pcm_format = SND_PCM_FORMAT_FLOAT64_BE;
194             break;
195         case VLC_CODEC_F64L:
196             pcm_format = SND_PCM_FORMAT_FLOAT64_LE;
197             break;
198         case VLC_CODEC_F32B:
199             pcm_format = SND_PCM_FORMAT_FLOAT_BE;
200             break;
201         case VLC_CODEC_F32L:
202             pcm_format = SND_PCM_FORMAT_FLOAT_LE;
203             break;
204         case VLC_CODEC_FI32:
205             fourcc = VLC_CODEC_FL32;
206             pcm_format = SND_PCM_FORMAT_FLOAT;
207             break;
208         case VLC_CODEC_S32B:
209             pcm_format = SND_PCM_FORMAT_S32_BE;
210             break;
211         case VLC_CODEC_S32L:
212             pcm_format = SND_PCM_FORMAT_S32_LE;
213             break;
214         case VLC_CODEC_S24B:
215             pcm_format = SND_PCM_FORMAT_S24_3BE;
216             break;
217         case VLC_CODEC_S24L:
218             pcm_format = SND_PCM_FORMAT_S24_3LE;
219             break;
220         case VLC_CODEC_U24B:
221             pcm_format = SND_PCM_FORMAT_U24_3BE;
222             break;
223         case VLC_CODEC_U24L:
224             pcm_format = SND_PCM_FORMAT_U24_3LE;
225             break;
226         case VLC_CODEC_S16B:
227             pcm_format = SND_PCM_FORMAT_S16_BE;
228             break;
229         case VLC_CODEC_S16L:
230             pcm_format = SND_PCM_FORMAT_S16_LE;
231             break;
232         case VLC_CODEC_U16B:
233             pcm_format = SND_PCM_FORMAT_U16_BE;
234             break;
235         case VLC_CODEC_U16L:
236             pcm_format = SND_PCM_FORMAT_U16_LE;
237             break;
238         case VLC_CODEC_S8:
239             pcm_format = SND_PCM_FORMAT_S8;
240             break;
241         case VLC_CODEC_U8:
242             pcm_format = SND_PCM_FORMAT_U8;
243             break;
244         default:
245             if (AOUT_FMT_SPDIF(&aout->format))
246                 spdif = var_InheritBool (aout, "spdif");
247             if (HAVE_FPU)
248             {
249                 fourcc = VLC_CODEC_FL32;
250                 pcm_format = SND_PCM_FORMAT_FLOAT;
251             }
252             else
253             {
254                 fourcc = VLC_CODEC_S16N;
255                 pcm_format = SND_PCM_FORMAT_S16;
256             }
257     }
258
259     /* Choose the IEC device for S/PDIF output:
260        if the device is overridden by the user then it will be the one.
261        Otherwise we compute the default device based on the output format. */
262     if (spdif && !strcmp (device, "default"))
263     {
264         unsigned aes3;
265
266         switch (aout->format.i_rate)
267         {
268 #define FS(freq) \
269             case freq: aes3 = IEC958_AES3_CON_FS_ ## freq; break;
270             FS( 44100) /* def. */ FS( 48000) FS( 32000)
271             FS( 22050)            FS( 24000)
272             FS( 88200) FS(768000) FS( 96000)
273             FS(176400)            FS(192000)
274 #undef FS
275             default:
276                 aes3 = IEC958_AES3_CON_FS_NOTID;
277                 break;
278         }
279
280         free (device);
281         if (asprintf (&device,
282                       "iec958:AES0=0x%x,AES1=0x%x,AES2=0x%x,AES3=0x%x",
283                       IEC958_AES0_CON_EMPHASIS_NONE | IEC958_AES0_NONAUDIO,
284                       IEC958_AES1_CON_ORIGINAL | IEC958_AES1_CON_PCM_CODER,
285                       0, aes3) == -1)
286             return VLC_ENOMEM;
287     }
288
289     /* Allocate structures */
290     aout_sys_t *sys = malloc (sizeof (*sys));
291     if (unlikely(sys == NULL))
292     {
293         free (device);
294         return VLC_ENOMEM;
295     }
296     aout->sys = sys;
297
298     /* Open the device */
299     snd_pcm_t *pcm;
300     /* VLC always has a resampler. No need for ALSA's. */
301     const int mode = SND_PCM_NO_AUTO_RESAMPLE
302     /* ALSA discards extra channels (by default). This is not good. */
303                    | SND_PCM_NO_AUTO_CHANNELS
304     /* VLC is currently unable to leverage ALSA softvol. No need for it. */
305                    | SND_PCM_NO_SOFTVOL;
306
307     int val = snd_pcm_open (&pcm, device, SND_PCM_STREAM_PLAYBACK, mode);
308 #if (SND_LIB_VERSION <= 0x010015)
309 # warning Please update alsa-lib to version > 1.0.21a.
310     var_Create (aout->p_libvlc, "alsa-working", VLC_VAR_BOOL);
311     if (val != 0 && var_GetBool (aout->p_libvlc, "alsa-working"))
312         dialog_Fatal (aout, "ALSA version problem",
313             "VLC failed to re-initialize your audio output device.\n"
314             "Please update alsa-lib to version 1.0.22 or higher "
315             "to fix this issue.");
316     var_SetBool (aout->p_libvlc, "alsa-working", !val);
317 #endif
318     if (val != 0)
319     {
320 #if (SND_LIB_VERSION <= 0x010017)
321 # warning Please update alsa-lib to version > 1.0.23.
322         var_Create (aout->p_libvlc, "alsa-broken", VLC_VAR_BOOL);
323         if (!var_GetBool (aout->p_libvlc, "alsa-broken"))
324         {
325             var_SetBool (aout->p_libvlc, "alsa-broken", true);
326             dialog_Fatal (aout, "Potential ALSA version problem",
327                 "VLC failed to initialize your audio output device (if any).\n"
328                 "Please update alsa-lib to version 1.0.24 or higher "
329                 "to try to fix this issue.");
330         }
331 #endif
332         msg_Err (aout, "cannot open ALSA device \"%s\": %s", device,
333                  snd_strerror (val));
334         dialog_Fatal (aout, _("Audio output failed"),
335                       _("The audio device \"%s\" could not be used:\n%s."),
336                       device, snd_strerror (val));
337         free (device);
338         free (sys);
339         return VLC_EGENERIC;
340     }
341     sys->pcm = pcm;
342
343     /* Print some potentially useful debug */
344     msg_Dbg (aout, "using ALSA device: %s", device);
345     DumpDevice (VLC_OBJECT(aout), pcm);
346
347     /* Setup */
348     unsigned channels = aout_FormatNbChannels (&aout->format);
349
350     if (spdif)
351     {
352         fourcc = VLC_CODEC_SPDIFL;
353         pcm_format = SND_PCM_FORMAT_S16;
354         channels = 2;
355     }
356
357     /* Get Initial hardware parameters */
358     snd_pcm_hw_params_t *hw;
359     unsigned param;
360
361     snd_pcm_hw_params_alloca (&hw);
362     snd_pcm_hw_params_any (pcm, hw);
363     Dump (aout, "initial hardware setup:\n", snd_pcm_hw_params_dump, hw);
364
365     /* Set sample format */
366     val = snd_pcm_hw_params_set_format (pcm, hw, pcm_format);
367     if (val == 0)
368         ;
369     else if (pcm_format != SND_PCM_FORMAT_FLOAT
370      && snd_pcm_hw_params_set_format (pcm, hw, SND_PCM_FORMAT_FLOAT) == 0)
371         fourcc = VLC_CODEC_FL32;
372     else if (pcm_format != SND_PCM_FORMAT_S32
373      && snd_pcm_hw_params_set_format (pcm, hw, SND_PCM_FORMAT_S32) == 0)
374         fourcc = VLC_CODEC_S32N;
375     else if (pcm_format != SND_PCM_FORMAT_S16
376      && snd_pcm_hw_params_set_format (pcm, hw, SND_PCM_FORMAT_S16) == 0)
377         fourcc = VLC_CODEC_S16N;
378     else
379     {
380         msg_Err (aout, "cannot set sample format: %s", snd_strerror (val));
381         goto error;
382     }
383
384     val = snd_pcm_hw_params_set_access (pcm, hw,
385                                         SND_PCM_ACCESS_RW_INTERLEAVED);
386     if (val)
387     {
388         msg_Err (aout, "cannot set access mode: %s", snd_strerror (val));
389         goto error;
390     }
391
392     /* Set channels count */
393     unsigned chans;
394     /* By default, ALSA plug will discard extra channels and zero missing ones
395      * instead of remixing, so remixing was disabled at snd_pcm_open() above.
396      * Then, the configuration space will contain only channels configurations
397      * supported by the audio device, but not necessarily functional (e.g.
398      * surround-capable card with stereo speakers). */
399     /* If there is only channels configuration, use that one.
400      * This should deal with "surround40", "surround51" and "surround71". */
401     if (snd_pcm_hw_params_get_channels (hw, &chans) == 0)
402         ;
403     /* Otherwise, if we have 5 channels and they are supported, use that.
404      * This should deal with "surround41" and "surround50" routers.
405      * This assumes that no real hardware supports exactly 5 channels. */
406     else if (channels == 5
407      && snd_pcm_hw_params_set_channels (pcm, hw, channels))
408         chans = channels;
409     /* Otherwise, if stereo is supported, then use that. This deals with
410      * the "front" device that fails to enforce stereo on Surround cards. */
411     else if (snd_pcm_hw_params_set_channels (pcm, hw, 2) == 0)
412         chans = 2;
413     /* Out of desperation, try the original channels count. */
414     else if (snd_pcm_hw_params_set_channels (pcm, hw, channels) == 0)
415         ;
416     /* As last chance, try anything. */
417     else
418     {
419         chans = channels;
420         val = snd_pcm_hw_params_set_channels_near (pcm, hw, &chans);
421         if (val)
422         {
423             msg_Err (aout, "cannot set channels count: %s",
424                      snd_strerror (val));
425             goto error;
426         }
427     }
428
429     if (channels != chans)
430         msg_Dbg (aout, "remixing from %u to %u channels", channels, chans);
431
432     /* Set sample rate */
433     unsigned rate = aout->format.i_rate;
434     val = snd_pcm_hw_params_set_rate_near (pcm, hw, &rate, NULL);
435     if (val)
436     {
437         msg_Err (aout, "cannot set sample rate: %s", snd_strerror (val));
438         goto error;
439     }
440     if (aout->format.i_rate != rate)
441         msg_Dbg (aout, "resampling from %d Hz to %d Hz",
442                  aout->format.i_rate, rate);
443
444     /* Set buffer size */
445     param = AOUT_MAX_ADVANCE_TIME;
446     val = snd_pcm_hw_params_set_buffer_time_near (pcm, hw, &param, NULL);
447     if (val)
448         msg_Warn (aout, "cannot set buffer duration near %u us: %s",
449                   param, snd_strerror (val));
450     val = snd_pcm_hw_params_set_buffer_time_last (pcm, hw, &param, NULL);
451     if (val)
452         msg_Warn (aout, "cannot set buffer duration: %s", snd_strerror (val));
453
454     /* Set number of periods (at least two) */
455     param = 2;
456     val = snd_pcm_hw_params_set_periods_min (pcm, hw, &param, NULL);
457     if (val)
458         msg_Warn (aout, "cannot set minimum of %u periods: %s", param,
459                   snd_strerror (val));
460     val = snd_pcm_hw_params_set_periods_first (pcm, hw, &param, NULL);
461     if (val)
462         msg_Warn (aout, "cannot set periods count near %u: %s", param,
463                   snd_strerror (val));
464
465     /* Commit hardware parameters */
466     val = snd_pcm_hw_params (pcm, hw);
467     if (val < 0)
468     {
469         msg_Err (aout, "cannot commit hardware parameters: %s",
470                  snd_strerror (val));
471         goto error;
472     }
473     Dump (aout, "final HW setup:\n", snd_pcm_hw_params_dump, hw);
474
475     /* Get Initial software parameters */
476     snd_pcm_sw_params_t *sw;
477
478     snd_pcm_sw_params_alloca (&sw);
479     snd_pcm_sw_params_current (pcm, sw);
480     Dump (aout, "initial software parameters:\n", snd_pcm_sw_params_dump, sw);
481
482     /* START REVISIT */
483     //snd_pcm_sw_params_set_avail_min( pcm, sw, i_period_size );
484     // FIXME: useful?
485     val = snd_pcm_sw_params_set_start_threshold (pcm, sw, 1);
486     if( val < 0 )
487     {
488         msg_Err( aout, "unable to set start threshold (%s)",
489                  snd_strerror( val ) );
490         goto error;
491     }
492     /* END REVISIT */
493
494     /* Commit software parameters. */
495     val = snd_pcm_sw_params (pcm, sw);
496     if (val)
497     {
498         msg_Err (aout, "cannot commit software parameters: %s",
499                  snd_strerror (val));
500         goto error;
501     }
502     Dump (aout, "final software parameters:\n", snd_pcm_sw_params_dump, sw);
503
504     val = snd_pcm_prepare (pcm);
505     if (val)
506     {
507         msg_Err (aout, "cannot prepare device: %s", snd_strerror (val));
508         goto error;
509     }
510
511     /* Guess the channel map */
512     switch (chans)
513     {
514         case 1:
515             chans = AOUT_CHAN_CENTER;
516             break;
517         case 2: /* front */
518             chans = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT;
519             break;
520         case 4: /* surround40 */
521             chans = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT
522                   | AOUT_CHAN_REARLEFT | AOUT_CHAN_REARRIGHT;
523             break;
524         case 5: /* surround50 ... or surround41! Uho! */
525 #if 1
526             chans = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT
527                   | AOUT_CHAN_REARLEFT | AOUT_CHAN_REARRIGHT
528                   | AOUT_CHAN_LFE;
529 #else
530             chans = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT
531                   | AOUT_CHAN_REARLEFT | AOUT_CHAN_REARRIGHT
532                   | AOUT_CHAN_CENTER;
533 #endif
534             break;
535         case 6: /* surround51 */
536             chans = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT
537                   | AOUT_CHAN_REARLEFT | AOUT_CHAN_REARRIGHT
538                   | AOUT_CHAN_CENTER | AOUT_CHAN_LFE;
539             break;
540 #if 0 /* FIXME reorder */
541          case 8: /* surround71 */
542             chans = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT
543                   | AOUT_CHAN_REARLEFT | AOUT_CHAN_REARRIGHT
544                   | AOUT_CHAN_CENTER | AOUT_CHAN_LFE
545                   | AOUT_CHAN_MIDDLELEFT | AOUT_CHAN_MIDDLERIGHT;
546             break;
547 #endif
548         default:
549             msg_Err (aout, "unknown %u channels configuration", chans);
550             goto error;
551     }
552
553     /* Setup audio_output_t */
554     aout->format.i_format = fourcc;
555     aout->format.i_rate = rate;
556     aout->format.i_original_channels =
557     aout->format.i_physical_channels = chans;
558     if (spdif)
559     {
560         aout->format.i_bytes_per_frame = AOUT_SPDIF_SIZE;
561         aout->format.i_frame_length = A52_FRAME_NB;
562         aout_VolumeNoneInit (aout);
563     }
564     else
565         aout_VolumeSoftInit (aout);
566
567     aout->pf_play = Play;
568     if (snd_pcm_hw_params_can_pause (hw))
569         aout->pf_pause = Pause;
570     else
571     {
572         aout->pf_pause = PauseDummy;
573         msg_Warn (aout, "device cannot be paused");
574     }
575     aout->pf_flush = Flush;
576
577     Probe (obj, device);
578     free (device);
579     return 0;
580
581 error:
582     snd_pcm_close (pcm);
583     free (device);
584     free (sys);
585     return VLC_EGENERIC;
586 }
587
588 /**
589  * Queues one audio buffer to the hardware.
590  */
591 static void Play (audio_output_t *aout, block_t *block)
592 {
593     aout_sys_t *sys = aout->sys;
594     snd_pcm_t *pcm = sys->pcm;
595     snd_pcm_sframes_t frames;
596     snd_pcm_state_t state = snd_pcm_state (pcm);
597
598     if (snd_pcm_delay (pcm, &frames) == 0)
599     {
600         mtime_t delay = frames * CLOCK_FREQ / aout->format.i_rate;
601
602         if (state != SND_PCM_STATE_RUNNING)
603         {
604             delay = block->i_pts - (mdate () + delay);
605             if (delay > 0)
606             {
607                 frames = (delay * aout->format.i_rate) / CLOCK_FREQ;
608                 msg_Dbg (aout, "prepending %ld zeroes", frames);
609
610                 void *pad = calloc (frames, aout->format.i_bytes_per_frame);
611                 if (likely(pad != NULL))
612                 {
613                     snd_pcm_writei (pcm, pad, frames);
614                     free (pad);
615                 }
616             }
617         }
618         else
619             aout_TimeReport (aout, block->i_pts - delay);
620     }
621
622     /* TODO: better overflow handling */
623     /* TODO: no period wake ups */
624
625     while (block->i_nb_samples > 0)
626     {
627         frames = snd_pcm_writei (pcm, block->p_buffer, block->i_nb_samples);
628         if (frames >= 0)
629         {
630             size_t bytes = snd_pcm_frames_to_bytes (pcm, frames);
631             block->i_nb_samples -= frames;
632             block->p_buffer += bytes;
633             block->i_buffer -= bytes;
634             // pts, length
635         }
636         else  
637         {
638             int val = snd_pcm_recover (pcm, frames, 1);
639             if (val)
640             {
641                 msg_Err (aout, "cannot recover playback stream: %s",
642                          snd_strerror (val));
643                 DumpDeviceStatus (aout, pcm);
644                 break;
645             }
646             msg_Warn (aout, "cannot write samples: %s", snd_strerror (frames));
647         }
648     }
649     block_Release (block);
650 }
651
652 /**
653  * Pauses/resumes the audio playback.
654  */
655 static void Pause (audio_output_t *aout, bool pause, mtime_t date)
656 {
657     snd_pcm_t *pcm = aout->sys->pcm;
658
659     int val = snd_pcm_pause (pcm, pause);
660     if (unlikely(val))
661         PauseDummy (aout, pause, date);
662 }
663
664 static void PauseDummy (audio_output_t *aout, bool pause, mtime_t date)
665 {
666     snd_pcm_t *pcm = aout->sys->pcm;
667
668     /* Stupid device cannot pause. Discard samples. */
669     if (pause)
670         snd_pcm_drop (pcm);
671     else
672         snd_pcm_prepare (pcm);
673     (void) date;
674 }
675
676 /**
677  * Flushes/drains the audio playback buffer.
678  */
679 static void Flush (audio_output_t *aout, bool wait)
680 {
681     snd_pcm_t *pcm = aout->sys->pcm;
682
683     if (wait)
684         snd_pcm_drain (pcm);
685     else
686         snd_pcm_drop (pcm);
687     snd_pcm_prepare (pcm);
688 }
689
690
691 /**
692  * Releases the audio output.
693  */
694 static void Close (vlc_object_t *obj)
695 {
696     audio_output_t *aout = (audio_output_t *)obj;
697     aout_sys_t *sys = aout->sys;
698     snd_pcm_t *pcm = aout->sys->pcm;
699
700     var_DelCallback (obj, "audio-device", aout_ChannelsRestart, NULL);
701     snd_pcm_drop (pcm);
702     snd_pcm_close (pcm);
703     free (sys);
704 }
705
706 /*****************************************************************************
707  * config variable callback
708  *****************************************************************************/
709 static int FindDevicesCallback( vlc_object_t *p_this, char const *psz_name,
710                                vlc_value_t newval, vlc_value_t oldval, void *p_unused )
711 {
712     module_config_t *p_item;
713     (void)newval;
714     (void)oldval;
715     (void)p_unused;
716
717     p_item = config_FindConfig( p_this, psz_name );
718     if( !p_item ) return VLC_SUCCESS;
719
720     /* Clear-up the current list */
721     if( p_item->i_list )
722     {
723         int i;
724
725         /* Keep the first entrie */
726         for( i = 1; i < p_item->i_list; i++ )
727         {
728             free( (char *)p_item->ppsz_list[i] );
729             free( (char *)p_item->ppsz_list_text[i] );
730         }
731         /* TODO: Remove when no more needed */
732         p_item->ppsz_list[i] = NULL;
733         p_item->ppsz_list_text[i] = NULL;
734     }
735     p_item->i_list = 1;
736
737     GetDevices (p_this, p_item, "default");
738
739     /* Signal change to the interface */
740     p_item->b_dirty = true;
741
742     return VLC_SUCCESS;
743 }
744
745
746 static void GetDevices (vlc_object_t *obj, module_config_t *item,
747                         const char *prefs_dev)
748 {
749     void **hints;
750     bool hinted_default = false;
751     bool hinted_prefs = !strcmp (prefs_dev, "default");
752
753     msg_Dbg(obj, "Available ALSA PCM devices:");
754
755     if (snd_device_name_hint(-1, "pcm", &hints) < 0)
756         return;
757
758     for (size_t i = 0; hints[i] != NULL; i++)
759     {
760         void *hint = hints[i];
761
762         char *name = snd_device_name_get_hint(hint, "NAME");
763         if (unlikely(name == NULL))
764             continue;
765
766         char *desc = snd_device_name_get_hint(hint, "DESC");
767         if (desc != NULL)
768             for (char *lf = strchr(desc, '\n'); lf; lf = strchr(lf, '\n'))
769                  *lf = ' ';
770         msg_Dbg(obj, "%s (%s)", (desc != NULL) ? desc : name, name);
771
772         if (!strcmp (name, "default"))
773             hinted_default = true;
774         if (!strcmp (name, prefs_dev))
775             hinted_prefs = true;
776
777         if (item != NULL)
778         {
779             item->ppsz_list = xrealloc(item->ppsz_list,
780                                        (item->i_list + 2) * sizeof(char *));
781             item->ppsz_list_text = xrealloc(item->ppsz_list_text,
782                                           (item->i_list + 2) * sizeof(char *));
783             item->ppsz_list[item->i_list] = name;
784             if (desc == NULL)
785                 desc = strdup(name);
786             item->ppsz_list_text[item->i_list] = desc;
787             item->i_list++;
788         }
789         else
790         {
791             vlc_value_t val, text;
792
793             val.psz_string = name;
794             text.psz_string = desc;
795             var_Change(obj, "audio-device", VLC_VAR_ADDCHOICE, &val, &text);
796             free(desc);
797             free(name);
798         }
799     }
800
801     snd_device_name_free_hint(hints);
802
803     if (item != NULL)
804     {
805         item->ppsz_list[item->i_list] = NULL;
806         item->ppsz_list_text[item->i_list] = NULL;
807     }
808     else
809     {
810         vlc_value_t val, text;
811
812         if (!hinted_default)
813         {
814             val.psz_string = (char *)"default";
815             text.psz_string = (char *)N_("Default");
816             var_Change(obj, "audio-device", VLC_VAR_ADDCHOICE, &val, &text);
817         }
818
819         val.psz_string = (char *)prefs_dev;
820         if (!hinted_prefs)
821         {
822             text.psz_string = (char *)N_("VLC preferences");
823             var_Change(obj, "audio-device", VLC_VAR_ADDCHOICE, &val, &text);
824         }
825         var_Change(obj, "audio-device", VLC_VAR_SETVALUE, &val, NULL);
826     }
827 }