1 /*
2  * Copyright (C) 2000-2020 the xine project
3  *
4  * This file is part of xine, a free video player.
5  *
6  * xine is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * xine is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
19  *
20  * Credits go
21  * - for the SPDIF A/52 sync part
22  * - frame size calculation added (16-08-2001)
23  * (c) 2001 Andy Lo A Foe <andy@alsaplayer.org>
24  * for initial ALSA 0.9.x support.
25  *     adding MONO/STEREO/4CHANNEL/5CHANNEL/5.1CHANNEL analogue support.
26  * (c) 2001 James Courtier-Dutton <James@superbug.demon.co.uk>
27  */
28 
29 #ifdef HAVE_CONFIG_H
30 #include "config.h"
31 #endif
32 
33 #include <stdio.h>
34 #include <stdarg.h>
35 #include <errno.h>
36 #include <string.h>
37 #include <unistd.h>
38 #include <stdlib.h>
39 #include <fcntl.h>
40 #include <math.h>
41 #ifdef HAVE_ALLOCA_H
42 #include <alloca.h>
43 #endif
44 
45 #define ALSA_PCM_NEW_HW_PARAMS_API
46 #define ALSA_PCM_NEW_SW_PARAMS_API
47 #include <alsa/asoundlib.h>
48 
49 #include <sys/ioctl.h>
50 #include <inttypes.h>
51 #include <pthread.h>
52 
53 #include <xine/xine_internal.h>
54 #include <xine/xineutils.h>
55 #include <xine/compat.h>
56 #include <xine/audio_out.h>
57 
58 #include "speakers.h"
59 
60 /*
61 #define ALSA_LOG
62 #define ALSA_LOG_BUFFERS
63 */
64 /*
65 #define LOG_DEBUG
66 */
67 
68 #define AO_OUT_ALSA_IFACE_VERSION 9
69 
70 #define BUFFER_TIME               1000*1000
71 #define GAP_TOLERANCE             5000
72 
73 #define MIXER_MASK_LEFT           0x0001
74 #define MIXER_MASK_RIGHT          0x0002
75 #define MIXER_MASK_MUTE           0x0004
76 #define MIXER_MASK_STEREO         0x0008
77 #define MIXER_HAS_MUTE_SWITCH     0x0010
78 
79 typedef struct {
80   audio_driver_class_t driver_class;
81 
82   xine_t          *xine;
83 } alsa_class_t;
84 
85 typedef struct alsa_driver_s {
86 
87   ao_driver_t        ao_driver;
88 
89   alsa_class_t      *class;
90 
91   snd_pcm_t         *audio_fd;
92   int                open_mode;
93   int		     has_pause_resume;
94   int		     is_paused;
95 
96   int32_t            output_sample_rate, input_sample_rate;
97   double             sample_rate_factor;
98   uint32_t           num_channels;
99   uint32_t           bits_per_sample;
100   uint32_t           bytes_per_frame;
101   uint32_t           bytes_in_buffer;      /* number of bytes writen to audio hardware   */
102   snd_pcm_uframes_t  buffer_size;
103   int32_t            mmap;
104   uint32_t           supported_channels;   /* field of 1 << num_channels */
105   uint32_t           capabilities;
106 
107   struct _alsa_dev_info_s {
108     struct alsa_driver_s *this;
109     const char           *type;
110     const char           *config_key;
111     char                 *name;
112     uint32_t              supported_channels;   /* field of 1 << num_channels */
113     uint32_t              capabilities;
114   }                    devs[5];
115 
116   const char          *bits_names[4]; /* 8, 16, 24, 32 */
117 
118   struct {
119     pthread_t          thread;
120     int                thread_created;
121     pthread_mutex_t    mutex;
122     char              *name;
123     snd_mixer_t       *handle;
124     snd_mixer_elem_t  *elem;
125     long               min;
126     long               max;
127     long               left_vol;
128     long               right_vol;
129     int                mute;
130     int                running;
131   } mixer;
132 
133   /* avoid *_alloca () */
134   snd_pcm_hw_params_t   *hw_params;
135   snd_pcm_sw_params_t   *sw_params;
136   snd_pcm_access_mask_t *ac_mask;
137   snd_ctl_card_info_t   *card_info;
138   snd_pcm_status_t      *pcm_status;
139 } alsa_driver_t;
140 
141 static snd_output_t *jcd_out;
142 
143 /*
144  * Get and convert volume to percent value
145  */
ao_alsa_get_percent_from_volume(long val,long min,long max)146 static int ao_alsa_get_percent_from_volume(long val, long min, long max) {
147   int range = max - min;
148   return (range == 0) ? 0 : ((val - min) * 100.0 / range + .5);
149 }
150 
151 /* Stolen from alsa-lib */
my_snd_mixer_wait(snd_mixer_t * mixer,int timeout)152 static int my_snd_mixer_wait(snd_mixer_t *mixer, int timeout) {
153   struct pollfd  spfds[16];
154   struct pollfd *pfds = spfds;
155   int            err, count;
156   void          *freeme = NULL;
157 
158   count = snd_mixer_poll_descriptors(mixer, pfds, sizeof(spfds) / sizeof(spfds[0]));
159 
160   if (count < 0)
161     return count;
162 
163   if ((unsigned int) count > sizeof(spfds) / sizeof(spfds[0])) {
164     freeme = pfds = calloc(count, sizeof(*pfds));
165 
166     if (!pfds)
167       return -ENOMEM;
168 
169     err = snd_mixer_poll_descriptors(mixer, pfds, (unsigned int) count);
170     // XXX is this assert correct ? if triggered, it would be alsa bug, not xine bug ?
171     assert(err == count);
172     if (err < 0) {
173       free(freeme);
174       return err;
175     }
176   }
177 
178   err = poll(pfds, (unsigned int) count, timeout);
179 
180   free(freeme);
181 
182   if (err < 0)
183     return -errno;
184 
185   return err;
186 }
187 
188 /*
189  * Wait (non blocking) till a mixer event happen
190  */
ao_alsa_handle_event_thread(void * data)191 static void *ao_alsa_handle_event_thread(void *data) {
192   alsa_driver_t  *this = (alsa_driver_t *) data;
193 
194   do {
195 
196     if(my_snd_mixer_wait(this->mixer.handle, 333) > 0) {
197       int err, mute = 0, swl = 0, swr = 0;
198       long right_vol, left_vol;
199       int old_mute;
200 
201       pthread_mutex_lock(&this->mixer.mutex);
202 
203       old_mute = (this->mixer.mute & MIXER_MASK_MUTE) ? 1 : 0;
204 
205       if((err = snd_mixer_handle_events(this->mixer.handle)) < 0) {
206 	xprintf(this->class->xine, XINE_VERBOSITY_DEBUG,
207 		"audio_alsa_out: snd_mixer_handle_events(): %s\n",  snd_strerror(err));
208 	pthread_mutex_unlock(&this->mixer.mutex);
209 	continue;
210       }
211 
212       if((err = snd_mixer_selem_get_playback_volume(this->mixer.elem, SND_MIXER_SCHN_FRONT_LEFT, &left_vol)) < 0) {
213 	xprintf(this->class->xine, XINE_VERBOSITY_DEBUG,
214 		"audio_alsa_out: snd_mixer_selem_get_playback_volume(): %s\n",  snd_strerror(err));
215 	pthread_mutex_unlock(&this->mixer.mutex);
216 	continue;
217       }
218 
219       if((err = snd_mixer_selem_get_playback_volume(this->mixer.elem, SND_MIXER_SCHN_FRONT_RIGHT, &right_vol)) < 0) {
220 	xprintf(this->class->xine, XINE_VERBOSITY_DEBUG,
221 		"audio_alsa_out: snd_mixer_selem_get_playback_volume(): %s\n",  snd_strerror(err));
222 	pthread_mutex_unlock(&this->mixer.mutex);
223 	continue;
224       }
225 
226       if(this->mixer.mute & MIXER_HAS_MUTE_SWITCH) {
227 
228 	if(this->mixer.mute & MIXER_MASK_STEREO) {
229 	  snd_mixer_selem_get_playback_switch(this->mixer.elem, SND_MIXER_SCHN_FRONT_LEFT, &swl);
230 	  mute = (swl) ? 0 : 1;
231 	}
232 	else {
233 
234 	  if (this->mixer.mute & MIXER_MASK_LEFT)
235 	    snd_mixer_selem_get_playback_switch(this->mixer.elem, SND_MIXER_SCHN_FRONT_LEFT, &swl);
236 
237 	  if ((SND_MIXER_SCHN_FRONT_RIGHT != SND_MIXER_SCHN_UNKNOWN) && (this->mixer.mute & MIXER_MASK_RIGHT))
238 	    snd_mixer_selem_get_playback_switch(this->mixer.elem, SND_MIXER_SCHN_FRONT_RIGHT, &swr);
239 
240 	  mute = (swl || swr) ? 0 : 1;
241 	}
242       }
243 
244       if((this->mixer.right_vol != right_vol) || (this->mixer.left_vol != left_vol) || (old_mute != mute)) {
245 	xine_event_t              event;
246 	xine_audio_level_data_t   data;
247 	xine_stream_t            *stream;
248 	xine_list_iterator_t      ite;
249 
250 	this->mixer.right_vol = right_vol;
251 	this->mixer.left_vol  = left_vol;
252 	if(mute)
253 	  this->mixer.mute |= MIXER_MASK_MUTE;
254 	else
255 	  this->mixer.mute &= ~MIXER_MASK_MUTE;
256 
257 	data.right = ao_alsa_get_percent_from_volume(this->mixer.right_vol,
258 						     this->mixer.min, this->mixer.max);
259 	data.left  = ao_alsa_get_percent_from_volume(this->mixer.left_vol,
260 						     this->mixer.min, this->mixer.max);
261 	data.mute  = (this->mixer.mute & MIXER_MASK_MUTE) ? 1 : 0;
262 
263 	event.type        = XINE_EVENT_AUDIO_LEVEL;
264 	event.data        = &data;
265 	event.data_length = sizeof(data);
266 
267 	pthread_mutex_lock(&this->class->xine->streams_lock);
268         ite = NULL;
269         while ((stream = xine_list_next_value (this->class->xine->streams, &ite))) {
270 	  event.stream = stream;
271 	  xine_event_send(stream, &event);
272 	}
273 	pthread_mutex_unlock(&this->class->xine->streams_lock);
274       }
275 
276       pthread_mutex_unlock(&this->mixer.mutex);
277     }
278 
279   } while(this->mixer.running);
280 
281   pthread_exit(NULL);
282 }
283 
284 /*
285  * Convert percent value to volume and set
286  */
ao_alsa_get_volume_from_percent(int val,long min,long max)287 static long ao_alsa_get_volume_from_percent(int val, long min, long max) {
288   int range = max - min;
289   return (range == 0) ? min : (val * range / 100.0 + min + .5);
290 }
291 
292 /*
293  * Error callback, we need to control this,
294  * error message should be printed only in DEBUG mode.
295  * XINE_FORMAT_PRINTF(5, 6) is true but useless here,
296  * as alsa delivers "fmt" at runtime only.
297  */
error_callback(const char * file,int line,const char * function,int err,const char * fmt,...)298 static void error_callback(const char *file, int line,
299 			   const char *function, int err, const char *fmt, ...) {
300 #ifdef DEBUG
301   va_list   args;
302   char     *buf = NULL;
303   int       result;
304 
305   va_start(args, fmt);
306   result = vasprintf(&buf, fmt, args);
307   va_end(args);
308 
309   if (result >= 0) {
310     printf("%s: %s() %s.\n", file, function, buf);
311     free(buf);
312   }
313 #else
314   (void)file;
315   (void)function;
316   (void)fmt;
317 #endif
318   (void)err;
319   (void)line;
320 }
321 
322 /*
323  * open the audio device for writing to
324  */
ao_alsa_open(ao_driver_t * this_gen,uint32_t bits,uint32_t rate,int mode)325 static int ao_alsa_open(ao_driver_t *this_gen, uint32_t bits, uint32_t rate, int mode) {
326   alsa_driver_t        *this = (alsa_driver_t *) this_gen;
327   char                 *pcm_device;
328   int                   err;
329 
330   err = snd_output_stdio_attach(&jcd_out, stdout, 0);
331 
332   switch (mode) {
333   case AO_CAP_MODE_MONO:
334     this->num_channels = 1;
335     pcm_device = this->devs[0].name;
336     break;
337   case AO_CAP_MODE_STEREO:
338     this->num_channels = 2;
339     pcm_device = this->devs[1].name;
340     break;
341   case AO_CAP_MODE_4CHANNEL:
342     this->num_channels = 4;
343     pcm_device = this->devs[2].name;
344     break;
345   case AO_CAP_MODE_4_1CHANNEL:
346   case AO_CAP_MODE_5CHANNEL:
347   case AO_CAP_MODE_5_1CHANNEL:
348     this->num_channels = 6;
349     pcm_device = this->devs[3].name;
350     break;
351   case AO_CAP_MODE_A52:
352   case AO_CAP_MODE_AC5:
353     this->num_channels = 2;
354     pcm_device = this->devs[4].name;
355     break;
356   default:
357     xprintf (this->class->xine, XINE_VERBOSITY_DEBUG,
358 	     "audio_alsa_out: ALSA Driver does not support the requested mode: 0x%X\n",mode);
359     return 0;
360   }
361 
362 #ifdef ALSA_LOG
363   printf("audio_alsa_out: Audio Device name = %s\n",pcm_device);
364   printf("audio_alsa_out: Number of channels = %d\n",this->num_channels);
365 #endif
366 
367   if (this->audio_fd) {
368     xine_log (this->class->xine, XINE_LOG_MSG, _("audio_alsa_out:Already open...WHY!"));
369     snd_pcm_close (this->audio_fd);
370     this->audio_fd = NULL;
371   }
372 
373   this->open_mode              = mode;
374   this->input_sample_rate      = rate;
375   this->bits_per_sample        = bits;
376   this->bytes_in_buffer        = 0;
377 
378   /*
379    * open audio device
380    * When switching to surround, dmix blocks the device some time, so we just keep trying for 0.8sec.
381    */
382   {
383     struct timeval start_time, end_time;
384     gettimeofday (&start_time, NULL);
385     while (1) {
386       err = snd_pcm_open (&this->audio_fd, pcm_device, SND_PCM_STREAM_PLAYBACK, /* NONBLOCK */ 1);
387       if (err != -EBUSY)
388         break;
389       gettimeofday (&end_time, NULL);
390       if ((end_time.tv_sec - start_time.tv_sec) * 1000000 + end_time.tv_usec - start_time.tv_usec > 800000)
391         break;
392       usleep (10000);
393     }
394   }
395   if (err < 0) {
396     xprintf (this->class->xine, XINE_VERBOSITY_LOG,
397       _("audio_alsa_out: snd_pcm_open() of %s failed: %s\n"), pcm_device, snd_strerror (err));
398     if (err == -EBUSY) {
399       xprintf (this->class->xine, XINE_VERBOSITY_LOG,
400         _("audio_alsa_out: >>> check if another program already uses PCM <<<\n"));
401     }
402     return 0;
403   }
404   /* printf ("audio_alsa_out: snd_pcm_open() opened %s\n", pcm_device); */
405   /* We wanted non blocking open but now put it back to normal */
406   //snd_pcm_nonblock(this->audio_fd, 0);
407   snd_pcm_nonblock(this->audio_fd, 1);
408 
409   do {
410     /* configure audio device */
411     err = snd_pcm_hw_params_any (this->audio_fd, this->hw_params);
412     if (err < 0) {
413       xprintf (this->class->xine, XINE_VERBOSITY_LOG,
414         _("audio_alsa_out: broken configuration for this PCM: no configurations available: %s\n"),
415         snd_strerror (err));
416       break;
417     }
418 
419     /* set interleaved access */
420     do {
421       if (this->mmap != 0) {
422         snd_pcm_access_mask_none (this->ac_mask);
423         snd_pcm_access_mask_set (this->ac_mask, SND_PCM_ACCESS_MMAP_INTERLEAVED);
424         snd_pcm_access_mask_set (this->ac_mask, SND_PCM_ACCESS_MMAP_NONINTERLEAVED);
425         snd_pcm_access_mask_set (this->ac_mask, SND_PCM_ACCESS_MMAP_COMPLEX);
426         err = snd_pcm_hw_params_set_access_mask (this->audio_fd, this->hw_params, this->ac_mask);
427         if (err >= 0)
428           break;
429         xprintf (this->class->xine, XINE_VERBOSITY_DEBUG,
430           "audio_alsa_out: mmap not available, falling back to compatiblity mode\n");
431         this->mmap = 0;
432       }
433       err = snd_pcm_hw_params_set_access (this->audio_fd, this->hw_params, SND_PCM_ACCESS_RW_INTERLEAVED);
434     } while (0);
435     if (err < 0) {
436       xprintf (this->class->xine, XINE_VERBOSITY_DEBUG,
437         "audio_alsa_out: access type not available: %s\n", snd_strerror (err));
438       break;
439     }
440 
441     /* set the sample format ([SU]{8,16,24,FLOAT}) */
442     /* ALSA automatically appends _LE or _BE depending on the CPU */
443     if ((bits < 8) || (bits > 32)) {
444       xprintf (this->class->xine, XINE_VERBOSITY_DEBUG,
445         "audio_alsa_out: pcm format bits=%d unknown, trying 16.\n", (int)bits);
446       bits = 16;
447     }
448     {
449       static const snd_pcm_format_t fmts[5] = {
450         0,
451         SND_PCM_FORMAT_U8,
452         SND_PCM_FORMAT_S16,
453 #ifdef WORDS_BIGENDIAN
454         SND_PCM_FORMAT_S24_3BE, /* 24 bit samples taking 3 bytes. */
455 #else
456         SND_PCM_FORMAT_S24_3LE,
457 #endif
458         SND_PCM_FORMAT_FLOAT
459       };
460       snd_pcm_format_t format = fmts[bits >> 3];
461       err = snd_pcm_hw_params_set_format (this->audio_fd, this->hw_params, format);
462       if (err < 0) {
463         xprintf (this->class->xine, XINE_VERBOSITY_DEBUG,
464           "audio_alsa_out: sample format not available: %s\n", snd_strerror (err));
465         break;
466       }
467     }
468 
469     /* set the number of channels */
470     err = snd_pcm_hw_params_set_channels (this->audio_fd, this->hw_params, this->num_channels);
471     if (err < 0) {
472       xprintf (this->class->xine, XINE_VERBOSITY_DEBUG,
473         "audio_alsa_out: Cannot set number of channels to %d (err=%d:%s)\n",
474         this->num_channels, err, snd_strerror (err));
475       break;
476     }
477 
478     {
479       snd_pcm_uframes_t period_size, period_size_min, period_size_max;
480       snd_pcm_uframes_t buffer_size_min, buffer_size_max;
481       uint32_t buffer_time = BUFFER_TIME;
482       snd_pcm_uframes_t buffer_time_to_size;
483       int dir;
484 #if 0
485       uint32_t              periods;
486 #endif
487 
488 #if 0
489       /* Restrict a configuration space to contain only real hardware rates */
490       err = snd_pcm_hw_params_set_rate_resample (this->audio_fd, this->hw_params, 0);
491 #endif
492       /* set the stream rate [Hz] */
493       dir = 0;
494       err = snd_pcm_hw_params_set_rate_near (this->audio_fd, this->hw_params, &rate, &dir);
495       if (err < 0) {
496         xprintf (this->class->xine, XINE_VERBOSITY_DEBUG,
497           "audio_alsa_out: rate not available: %s\n", snd_strerror (err));
498         break;
499       }
500       this->output_sample_rate = (uint32_t)rate;
501       if (this->input_sample_rate != this->output_sample_rate) {
502         xprintf (this->class->xine, XINE_VERBOSITY_DEBUG,
503           "audio_alsa_out: audio rate : %d requested, %d provided by device/sec\n",
504             this->input_sample_rate, this->output_sample_rate);
505       }
506 
507       buffer_time_to_size = ((uint64_t)buffer_time * rate) / 1000000;
508       snd_pcm_hw_params_get_buffer_size_min (this->hw_params, &buffer_size_min);
509       snd_pcm_hw_params_get_buffer_size_max (this->hw_params, &buffer_size_max);
510       dir = 0;
511       snd_pcm_hw_params_get_period_size_min (this->hw_params, &period_size_min, &dir);
512       dir = 0;
513       snd_pcm_hw_params_get_period_size_max (this->hw_params, &period_size_max, &dir);
514 #ifdef ALSA_LOG_BUFFERS
515       printf ("Buffer size range from %lu to %lu\n", buffer_size_min, buffer_size_max);
516       printf ("Period size range from %lu to %lu\n", period_size_min, period_size_max);
517       printf ("Buffer time size %lu\n", buffer_time_to_size);
518 #endif
519       this->buffer_size = buffer_time_to_size;
520       if (buffer_size_max < this->buffer_size)
521         this->buffer_size = buffer_size_max;
522       if (buffer_size_min > this->buffer_size)
523         this->buffer_size = buffer_size_min;
524       period_size = this->buffer_size / 8;
525       this->buffer_size = period_size * 8;
526 #ifdef ALSA_LOG_BUFFERS
527       printf ("To choose buffer_size = %ld\n", this->buffer_size);
528       printf ("To choose period_size = %ld\n", period_size);
529 #endif
530 
531 #if 0
532       /* Set period to buffer size ratios at 8 periods to 1 buffer */
533       dir = -1;
534       periods = 8;
535       err = snd_pcm_hw_params_set_periods_near (this->audio_fd, this->hw_params, &periods, &dir);
536       if (err < 0) {
537         xprintf (this->class->xine, XINE_VERBOSITY_DEBUG,
538           "audio_alsa_out: unable to set any periods: %s\n", snd_strerror (err));
539         break;
540       }
541       /* set the ring-buffer time [us] (large enough for x us|y samples ...) */
542       dir = 0;
543       err = snd_pcm_hw_params_set_buffer_time_near (this->audio_fd, this->hw_params, &buffer_time, &dir);
544       if (err < 0) {
545         xprintf (this->class->xine, XINE_VERBOSITY_DEBUG,
546           "audio_alsa_out: buffer time not available: %s\n", snd_strerror (err));
547         break;
548       }
549 #endif
550 
551 #if 1
552       /* set the period time [us] (interrupt every x us|y samples ...) */
553       dir = 0;
554       err = snd_pcm_hw_params_set_period_size_near (this->audio_fd, this->hw_params, &period_size, &dir);
555       if (err < 0) {
556         xprintf (this->class->xine, XINE_VERBOSITY_DEBUG,
557           "audio_alsa_out: period time not available: %s\n", snd_strerror (err));
558         break;
559       }
560 #endif
561       dir = 0;
562       snd_pcm_hw_params_get_period_size (this->hw_params, &period_size, &dir);
563 
564       dir = 0;
565       err = snd_pcm_hw_params_set_buffer_size_near (this->audio_fd, this->hw_params, &this->buffer_size);
566       if (err < 0) {
567         xprintf (this->class->xine, XINE_VERBOSITY_DEBUG,
568           "audio_alsa_out: buffer time not available: %s\n", snd_strerror (err));
569         break;
570       }
571       snd_pcm_hw_params_get_buffer_size (this->hw_params, &(this->buffer_size));
572 #ifdef ALSA_LOG_BUFFERS
573       printf ("was set period_size = %ld\n", period_size);
574       printf ("was set buffer_size = %ld\n", this->buffer_size);
575 #endif
576       if (2 * period_size > this->buffer_size) {
577         xprintf (this->class->xine, XINE_VERBOSITY_DEBUG,
578           "audio_alsa_out: buffer too small, could not use\n");
579         break;
580       }
581 
582       /* write the parameters to device */
583       err = snd_pcm_hw_params (this->audio_fd, this->hw_params);
584       if (err < 0) {
585         xprintf (this->class->xine, XINE_VERBOSITY_DEBUG,
586           "audio_alsa_out: pcm hw_params failed: %s\n", snd_strerror (err));
587         break;
588       }
589 
590       /* Check for pause/resume support */
591       this->has_pause_resume = (snd_pcm_hw_params_can_pause (this->hw_params)
592                              && snd_pcm_hw_params_can_resume (this->hw_params));
593       xprintf (this->class->xine, XINE_VERBOSITY_DEBUG,
594         "audio_alsa_out:open pause_resume=%d\n", this->has_pause_resume);
595       if (this->has_pause_resume)
596         this->capabilities &= ~AO_CAP_NO_UNPAUSE;
597       else
598         this->capabilities |= AO_CAP_NO_UNPAUSE;
599 
600       this->sample_rate_factor = (double) this->output_sample_rate / (double) this->input_sample_rate;
601       this->bytes_per_frame = snd_pcm_frames_to_bytes (this->audio_fd, 1);
602 
603       /* audio buffer size handling */
604       /* Copy current parameters into swparams */
605       err = snd_pcm_sw_params_current (this->audio_fd, this->sw_params);
606       if (err < 0) {
607         xprintf (this->class->xine, XINE_VERBOSITY_DEBUG,
608           "audio_alsa_out: Unable to determine current swparams: %s\n", snd_strerror (err));
609         break;
610       }
611 
612 #if defined(SND_LIB_VERSION) && SND_LIB_VERSION >= 0x010016
613       /* snd_pcm_sw_params_set_xfer_align() is deprecated, alignment is always 1 */
614 #else
615       /* align all transfers to 1 sample */
616       err = snd_pcm_sw_params_set_xfer_align (this->audio_fd, this->sw_params, 1);
617       if (err < 0) {
618         xprintf (this->class->xine, XINE_VERBOSITY_DEBUG,
619           "audio_alsa_out: Unable to set transfer alignment: %s\n", snd_strerror (err));
620         break;
621       }
622 #endif
623 
624       /* allow the transfer when at least period_size samples can be processed */
625       err = snd_pcm_sw_params_set_avail_min (this->audio_fd, this->sw_params, period_size);
626       if (err < 0) {
627         xprintf (this->class->xine, XINE_VERBOSITY_DEBUG,
628           "audio_alsa_out: Unable to set available min: %s\n", snd_strerror (err));
629         break;
630       }
631 
632       /* start the transfer when the buffer contains at least period_size samples */
633       err = snd_pcm_sw_params_set_start_threshold (this->audio_fd, this->sw_params, period_size);
634       if (err < 0) {
635         xprintf (this->class->xine, XINE_VERBOSITY_DEBUG,
636           "audio_alsa_out: Unable to set start threshold: %s\n", snd_strerror (err));
637         break;
638       }
639     }
640 
641     /* never stop the transfer, even on xruns */
642     err = snd_pcm_sw_params_set_stop_threshold (this->audio_fd, this->sw_params, this->buffer_size);
643     if (err < 0) {
644       xprintf (this->class->xine, XINE_VERBOSITY_DEBUG,
645         "audio_alsa_out: Unable to set stop threshold: %s\n", snd_strerror (err));
646       break;
647     }
648 
649     /* Install swparams into current parameters */
650     err = snd_pcm_sw_params (this->audio_fd, this->sw_params);
651     if (err < 0) {
652       xprintf (this->class->xine, XINE_VERBOSITY_DEBUG,
653         "audio_alsa_out: Unable to set swparams: %s\n", snd_strerror (err));
654       break;
655     }
656 
657 #ifdef ALSA_LOG
658     snd_pcm_dump_setup (this->audio_fd, jcd_out);
659     snd_pcm_sw_params_dump (this->sw_params, jcd_out);
660 #endif
661 
662     return this->output_sample_rate;
663   } while (0);
664 
665   snd_pcm_close (this->audio_fd);
666   this->audio_fd = NULL;
667   return 0;
668 }
669 
670 /*
671  * Return the number of audio channels
672  */
ao_alsa_num_channels(ao_driver_t * this_gen)673 static int ao_alsa_num_channels(ao_driver_t *this_gen) {
674   alsa_driver_t *this = (alsa_driver_t *) this_gen;
675   return this->num_channels;
676 }
677 
678 /*
679  * Return the number of bytes per frame
680  */
ao_alsa_bytes_per_frame(ao_driver_t * this_gen)681 static int ao_alsa_bytes_per_frame(ao_driver_t *this_gen) {
682   alsa_driver_t *this = (alsa_driver_t *) this_gen;
683   return this->bytes_per_frame;
684 }
685 
686 /*
687  * Return gap tolerance (in pts)
688  */
ao_alsa_get_gap_tolerance(ao_driver_t * this_gen)689 static int ao_alsa_get_gap_tolerance (ao_driver_t *this_gen) {
690   (void)this_gen;
691   return GAP_TOLERANCE;
692 }
693 
694 /*
695  * Return the delay. is frames measured by looking at pending samples
696  */
697 /* FIXME: delay returns invalid data if status is not RUNNING.
698  * e.g When there is an XRUN or we are in PREPARED mode.
699  */
ao_alsa_delay(ao_driver_t * this_gen)700 static int ao_alsa_delay (ao_driver_t *this_gen)  {
701   snd_pcm_sframes_t delay = 0;
702   int err = 0;
703   alsa_driver_t *this = (alsa_driver_t *) this_gen;
704 #ifdef LOG_DEBUG
705   struct timeval now;
706   printf("audio_alsa_out:delay:ENTERED\n");
707 #endif
708   err = snd_pcm_delay( this->audio_fd, &delay );
709 
710 #ifdef LOG_DEBUG
711   printf("audio_alsa_out:delay:delay all=%ld err=%d\n",delay, err);
712   gettimeofday(&now, 0);
713   printf("audio_alsa_out:delay: Time = %ld.%ld\n", now.tv_sec, now.tv_usec);
714   printf("audio_alsa_out:delay:FINISHED\n");
715 #endif
716 
717   /*
718    * try to recover from errors and recalculate delay
719    */
720   if(err) {
721 #ifdef LOG_DEBUG
722     printf("gap audio_alsa_out:delay: recovery\n");
723 #endif
724     err = snd_pcm_recover( this->audio_fd, err, 1 );
725     err = snd_pcm_delay( this->audio_fd, &delay );
726   }
727 
728   /*
729    * if we have a negative delay try to forward within the buffer
730    */
731   if(!err && (delay < 0)) {
732 #ifdef LOG_DEBUG
733     printf("gap audio_alsa_out:delay: forwarding frames: %d\n", (int)-delay);
734 #endif
735     err = snd_pcm_forward( this->audio_fd, -delay );
736     if(err >= 0) {
737       err = snd_pcm_delay( this->audio_fd, &delay );
738     }
739   }
740 
741   /*
742    * on error or (still) negative delays ensure delay
743    * is not negative
744    */
745   if (err || (delay < 0))
746     delay = 0;
747 
748   return delay;
749 }
750 
751 #if 0
752 /*
753  * Handle over/under-run
754  */
755 static void xrun(alsa_driver_t *this)
756 {
757   int res;
758 
759   /*
760      if ((res = snd_pcm_status (this->audio_fd, this->pcm_status)) < 0) {
761        printf ("audio_alsa_out: status error: %s\n", snd_strerror(res));
762        return;
763      }
764      snd_pcm_status_dump (this->pcm_status, jcd_out);
765   */
766   if (snd_pcm_state(this->audio_fd) == SND_PCM_STATE_XRUN) {
767     /*
768       struct timeval now, diff, tstamp;
769       gettimeofday(&now, 0);
770       snd_pcm_status_get_trigger_tstamp (this->pcm_status, &tstamp);
771       timersub(&now, &tstamp, &diff);
772       printf ("audio_alsa_out: xrun!!! (at least %.3f ms long)\n", diff.tv_sec * 1000 + diff.tv_usec / 1000.0);
773     */
774     xprintf (this->class->xine, XINE_VERBOSITY_DEBUG, "audio_alsa_out: XRUN!!!\n");
775     if ((res = snd_pcm_prepare(this->audio_fd))<0) {
776       xprintf (this->class->xine, XINE_VERBOSITY_DEBUG, "audio_alsa_out: xrun: prepare error: %s", snd_strerror(res));
777       return;
778     }
779     return;         /* ok, data should be accepted again */
780   }
781 }
782 #endif
783 
784 /*
785  * resume from suspend
786  */
resume(snd_pcm_t * pcm)787 static int resume(snd_pcm_t *pcm)
788 {
789   int res;
790   while ((res = snd_pcm_resume(pcm)) == -EAGAIN)
791     sleep(1);
792   if (! res)
793     return 0;
794   return snd_pcm_prepare(pcm);
795 }
796 
797 /*
798  * Write audio data to output buffer (blocking using snd_pcm_wait)
799  */
ao_alsa_write(ao_driver_t * this_gen,int16_t * data,uint32_t count)800 static int ao_alsa_write(ao_driver_t *this_gen, int16_t *data, uint32_t count) {
801   snd_pcm_sframes_t result;
802   snd_pcm_state_t    state;
803 #ifdef LOG_DEBUG
804   struct timeval now;
805 #endif
806   int wait_result;
807   int res;
808   uint8_t *buffer=(uint8_t *)data;
809   snd_pcm_uframes_t number_of_frames = (snd_pcm_uframes_t) count;
810   alsa_driver_t *this = (alsa_driver_t *) this_gen;
811 
812 #ifdef LOG_DEBUG
813   printf("audio_alsa_out:write:ENTERED\n");
814   gettimeofday(&now, 0);
815   printf("audio_alsa_out:write: Time = %ld.%ld\n", now.tv_sec, now.tv_usec);
816   printf("audio_alsa_out:write:count=%u\n",count);
817 #endif
818   state = snd_pcm_state(this->audio_fd);
819   if (state == SND_PCM_STATE_SUSPENDED) {
820     res = resume(this->audio_fd);
821     if (res < 0)
822       return 0;
823     state = snd_pcm_state(this->audio_fd);
824   } else if (state == SND_PCM_STATE_DISCONNECTED) {
825     /* the device is gone. audio_out.c handles it if we return something < 0 */
826     return -1;
827   }
828   if (state == SND_PCM_STATE_XRUN) {
829 #ifdef LOG_DEBUG
830     printf("audio_alsa_out:write:XRUN before\n");
831     snd_pcm_status (this->audio_fd, this->pcm_status);
832     snd_pcm_status_dump (this->pcm_status, jcd_out);
833 #endif
834     if ((res = snd_pcm_prepare(this->audio_fd))<0) {
835       xprintf(this->class->xine, XINE_VERBOSITY_DEBUG,
836               "audio_alsa_out: xrun: prepare error: %s", snd_strerror(res));
837       return 0;
838     }
839     state = snd_pcm_state(this->audio_fd);
840 #ifdef LOG_DEBUG
841     printf("audio_alsa_out:write:XRUN after\n");
842 #endif
843   }
844   if ( (state != SND_PCM_STATE_PREPARED) &&
845        (state != SND_PCM_STATE_RUNNING) &&
846        (state != SND_PCM_STATE_DRAINING) ) {
847     xprintf(this->class->xine, XINE_VERBOSITY_DEBUG,
848 	    "audio_alsa_out:write:BAD STATE, state = %d\n",state);
849   }
850 
851   while( number_of_frames > 0) {
852     if ( state == SND_PCM_STATE_RUNNING ) {
853 #ifdef LOG_DEBUG
854       printf("audio_alsa_out:write:loop:waiting for Godot\n");
855 #endif
856       snd_pcm_status (this->audio_fd, this->pcm_status);
857       if (snd_pcm_status_get_avail (this->pcm_status) < number_of_frames) {
858         wait_result = snd_pcm_wait(this->audio_fd, 1000);
859 #ifdef LOG_DEBUG
860         printf("audio_alsa_out:write:loop:wait_result=%d\n",wait_result);
861 #endif
862         if (wait_result <= 0) return 0;
863       }
864     }
865     if (this->mmap != 0) {
866       result = snd_pcm_mmap_writei(this->audio_fd, buffer, number_of_frames);
867     } else {
868       result = snd_pcm_writei(this->audio_fd, buffer, number_of_frames);
869     }
870 
871     if (result < 0) {
872 #ifdef LOG_DEBUG
873       printf("audio_alsa_out:write:result=%ld:%s\n",result, snd_strerror(result));
874 #endif
875       state = snd_pcm_state(this->audio_fd);
876       if (state == SND_PCM_STATE_SUSPENDED) {
877 	res = resume(this->audio_fd);
878 	if (res < 0)
879 	  return 0;
880 	continue;
881       }
882       if (state == SND_PCM_STATE_DISCONNECTED) {
883         /* the device is gone. audio_out.c handles it if we return something < 0 */
884         return -1;
885       } else if ( (state != SND_PCM_STATE_PREPARED) &&
886            (state != SND_PCM_STATE_RUNNING) &&
887            (state != SND_PCM_STATE_DRAINING) ) {
888         xprintf(this->class->xine, XINE_VERBOSITY_DEBUG,
889 		"audio_alsa_out:write:BAD STATE2, state = %d, going to try XRUN\n",state);
890         if ((res = snd_pcm_prepare(this->audio_fd))<0) {
891           xprintf(this->class->xine, XINE_VERBOSITY_DEBUG,
892 		  "audio_alsa_out: xrun: prepare error: %s", snd_strerror(res));
893           return 0;
894         }
895       }
896     }
897     if (result > 0) {
898       number_of_frames -= result;
899       buffer += result * this->bytes_per_frame;
900     }
901   }
902 #if 0
903   if ( (state == SND_PCM_STATE_RUNNING) ) {
904 #ifdef LOG_DEBUG
905     printf("audio_alsa_out:write:loop:waiting for Godot2\n");
906 #endif
907     wait_result = snd_pcm_wait(this->audio_fd, 1000000);
908 #ifdef LOG_DEBUG
909     printf("audio_alsa_out:write:loop:wait_result=%d\n",wait_result);
910 #endif
911     if (wait_result < 0) return 0;
912   }
913 #endif
914 #ifdef LOG_DEBUG
915   gettimeofday(&now, 0);
916   printf("audio_alsa_out:write: Time = %ld.%ld\n", now.tv_sec, now.tv_usec);
917   printf("audio_alsa_out:write:FINISHED\n");
918 #endif
919   return 1; /* audio samples were processed ok */
920 }
921 
922 /*
923  * This is called when the decoder no longer uses the audio
924  */
ao_alsa_close(ao_driver_t * this_gen)925 static void ao_alsa_close(ao_driver_t *this_gen) {
926   alsa_driver_t *this = (alsa_driver_t *) this_gen;
927 
928   if(this->audio_fd) {
929     snd_pcm_nonblock(this->audio_fd, 0);
930     snd_pcm_drain(this->audio_fd);
931     snd_pcm_close(this->audio_fd);
932   }
933   this->audio_fd = NULL;
934   this->has_pause_resume = 0; /* This is set at open time */
935 }
936 
937 /*
938  * Find out what output modes + capatilities are supported
939  */
ao_alsa_get_capabilities(ao_driver_t * this_gen)940 static uint32_t ao_alsa_get_capabilities (ao_driver_t *this_gen) {
941   alsa_driver_t *this = (alsa_driver_t *) this_gen;
942   return this->capabilities;
943 }
944 
945 /*
946  * Shut down audio output driver plugin and free all resources allocated
947  */
ao_alsa_exit(ao_driver_t * this_gen)948 static void ao_alsa_exit(ao_driver_t *this_gen) {
949   alsa_driver_t *this = (alsa_driver_t *) this_gen;
950 
951   this->class->xine->config->unregister_callbacks (this->class->xine->config,
952     NULL, NULL, this, sizeof (*this));
953 
954   /*
955    * Destroy the mixer thread and cleanup the mixer, so that
956    * any child processes (such as xscreensaver) cannot inherit
957    * the mixer's handle and keep it open.
958    * By rejoining the mixer thread, we remove a race condition
959    * between closing the handle and spawning the child process
960    * (i.e. xscreensaver).
961    */
962 
963   if(this->mixer.handle && this->mixer.thread_created) {
964     this->mixer.running = 0;
965     pthread_join(this->mixer.thread, NULL);
966     snd_mixer_close(this->mixer.handle);
967     this->mixer.handle=0;
968   }
969   pthread_mutex_destroy(&this->mixer.mutex);
970 
971   if (this->audio_fd) snd_pcm_close(this->audio_fd);
972   this->audio_fd=NULL;
973 
974   xine_config_free_string(this->class->xine, &this->mixer.name);
975 
976   {
977     uint32_t u;
978     for (u = 0; u < sizeof (this->devs) / sizeof (this->devs[0]); u++) {
979       _x_freep (&this->devs[u].name);
980     }
981   }
982 
983   free (this);
984 }
985 
986 /*
987  * Get a property of audio driver
988  */
ao_alsa_get_property(ao_driver_t * this_gen,int property)989 static int ao_alsa_get_property (ao_driver_t *this_gen, int property) {
990   alsa_driver_t *this = (alsa_driver_t *) this_gen;
991   int err;
992 
993   switch(property) {
994   case AO_PROP_MIXER_VOL:
995   case AO_PROP_PCM_VOL:
996     if(this->mixer.elem) {
997       int vol;
998 
999       pthread_mutex_lock(&this->mixer.mutex);
1000 
1001       if((err = snd_mixer_selem_get_playback_volume(this->mixer.elem, SND_MIXER_SCHN_FRONT_LEFT,
1002 						    &this->mixer.left_vol)) < 0) {
1003 	xprintf(this->class->xine, XINE_VERBOSITY_DEBUG,
1004 		"audio_alsa_out: snd_mixer_selem_get_playback_volume(): %s\n",  snd_strerror(err));
1005 	goto done;
1006       }
1007 
1008       if((err = snd_mixer_selem_get_playback_volume(this->mixer.elem, SND_MIXER_SCHN_FRONT_RIGHT,
1009 						    &this->mixer.right_vol)) < 0) {
1010 	xprintf(this->class->xine, XINE_VERBOSITY_DEBUG,
1011 		"audio_alsa_out: snd_mixer_selem_get_playback_volume(): %s\n",  snd_strerror(err));
1012 	goto done;
1013       }
1014 
1015     done:
1016       vol = (((ao_alsa_get_percent_from_volume(this->mixer.left_vol, this->mixer.min, this->mixer.max)) +
1017 	      (ao_alsa_get_percent_from_volume(this->mixer.right_vol, this->mixer.min, this->mixer.max))) /2);
1018       pthread_mutex_unlock(&this->mixer.mutex);
1019 
1020       return vol;
1021     }
1022     break;
1023 
1024   case AO_PROP_MUTE_VOL:
1025     {
1026       int mute;
1027 
1028       pthread_mutex_lock(&this->mixer.mutex);
1029       mute = ((this->mixer.mute & MIXER_HAS_MUTE_SWITCH) && (this->mixer.mute & MIXER_MASK_MUTE)) ? 1 : 0;
1030       pthread_mutex_unlock(&this->mixer.mutex);
1031 
1032       return mute;
1033     }
1034     break;
1035   }
1036 
1037   return 0;
1038 }
1039 
1040 /*
1041  * Set a property of audio driver
1042  */
ao_alsa_set_property(ao_driver_t * this_gen,int property,int value)1043 static int ao_alsa_set_property (ao_driver_t *this_gen, int property, int value) {
1044   alsa_driver_t *this = (alsa_driver_t *) this_gen;
1045   int err;
1046 
1047   switch(property) {
1048   case AO_PROP_MIXER_VOL:
1049   case AO_PROP_PCM_VOL:
1050     if(this->mixer.elem) {
1051 
1052       pthread_mutex_lock(&this->mixer.mutex);
1053 
1054       this->mixer.left_vol = this->mixer.right_vol = ao_alsa_get_volume_from_percent(value, this->mixer.min, this->mixer.max);
1055 
1056       if((err = snd_mixer_selem_set_playback_volume(this->mixer.elem, SND_MIXER_SCHN_FRONT_LEFT,
1057 						    this->mixer.left_vol)) < 0) {
1058 	xprintf(this->class->xine, XINE_VERBOSITY_DEBUG,
1059 		"audio_alsa_out: snd_mixer_selem_get_playback_volume(): %s\n",  snd_strerror(err));
1060 	pthread_mutex_unlock(&this->mixer.mutex);
1061 	return ~value;
1062       }
1063 
1064       if((err = snd_mixer_selem_set_playback_volume(this->mixer.elem, SND_MIXER_SCHN_FRONT_RIGHT,
1065 						    this->mixer.right_vol)) < 0) {
1066 	xprintf(this->class->xine, XINE_VERBOSITY_DEBUG,
1067 		"audio_alsa_out: snd_mixer_selem_get_playback_volume(): %s\n",  snd_strerror(err));
1068 	pthread_mutex_unlock(&this->mixer.mutex);
1069 	return ~value;
1070       }
1071       pthread_mutex_unlock(&this->mixer.mutex);
1072       return value;
1073     }
1074     break;
1075 
1076   case AO_PROP_MUTE_VOL:
1077     if(this->mixer.elem) {
1078 
1079       if(this->mixer.mute & MIXER_HAS_MUTE_SWITCH) {
1080 	int swl = 0, swr = 0;
1081 	int old_mute;
1082 
1083 	pthread_mutex_lock(&this->mixer.mutex);
1084 
1085 	old_mute = this->mixer.mute;
1086 	if(value)
1087 	  this->mixer.mute |= MIXER_MASK_MUTE;
1088 	else
1089 	  this->mixer.mute &= ~MIXER_MASK_MUTE;
1090 
1091 	if ((this->mixer.mute & MIXER_MASK_MUTE) != (old_mute & MIXER_MASK_MUTE)) {
1092 	  if(this->mixer.mute & MIXER_MASK_STEREO) {
1093 	    snd_mixer_selem_get_playback_switch(this->mixer.elem, SND_MIXER_SCHN_FRONT_LEFT, &swl);
1094 	    snd_mixer_selem_set_playback_switch_all(this->mixer.elem, !swl);
1095 	  }
1096 	  else {
1097 	    if (this->mixer.mute & MIXER_MASK_LEFT) {
1098 	      snd_mixer_selem_get_playback_switch(this->mixer.elem, SND_MIXER_SCHN_FRONT_LEFT, &swl);
1099 	      snd_mixer_selem_set_playback_switch(this->mixer.elem, SND_MIXER_SCHN_FRONT_LEFT, !swl);
1100 	    }
1101 	    if (SND_MIXER_SCHN_FRONT_RIGHT != SND_MIXER_SCHN_UNKNOWN && (this->mixer.mute & MIXER_MASK_RIGHT)) {
1102 	      snd_mixer_selem_get_playback_switch(this->mixer.elem, SND_MIXER_SCHN_FRONT_RIGHT, &swr);
1103 	      snd_mixer_selem_set_playback_switch(this->mixer.elem, SND_MIXER_SCHN_FRONT_RIGHT, !swr);
1104 	    }
1105 	  }
1106 	}
1107 
1108 	pthread_mutex_unlock(&this->mixer.mutex);
1109       }
1110       return value;
1111     }
1112     return ~value;
1113     break;
1114   }
1115 
1116   return ~value;
1117 }
1118 
1119 /*
1120  * Misc control operations
1121  */
ao_alsa_ctrl(ao_driver_t * this_gen,int cmd,...)1122 static int ao_alsa_ctrl(ao_driver_t *this_gen, int cmd, ...) {
1123   alsa_driver_t *this = (alsa_driver_t *) this_gen;
1124   int err;
1125 
1126   /* Alsa 0.9.x pause and resume is not stable enough at the moment.
1127    * Use snd_pcm_drop and restart instead.
1128    */
1129   switch (cmd) {
1130 
1131   case AO_CTRL_PLAY_PAUSE:
1132     if (this->audio_fd) {
1133       if (this->has_pause_resume) {
1134         if ((err=snd_pcm_pause(this->audio_fd, 1)) < 0) {
1135           xprintf(this->class->xine, XINE_VERBOSITY_DEBUG,
1136 		  "audio_alsa_out: Pause call failed. (err=%d:%s)\n",err, snd_strerror(err));
1137           this->has_pause_resume = 0;
1138           ao_alsa_ctrl(this_gen, AO_CTRL_PLAY_PAUSE, NULL);
1139         } else {
1140           this->is_paused = 1;
1141 	}
1142       } else {
1143         if ((err=snd_pcm_reset(this->audio_fd)) < 0) {
1144           xprintf(this->class->xine, XINE_VERBOSITY_DEBUG,
1145 		  "audio_alsa_out: Reset call failed. (err=%d:%s)\n",err, snd_strerror(err));
1146         }
1147         if ((err=snd_pcm_drain(this->audio_fd)) < 0) {
1148           xprintf(this->class->xine, XINE_VERBOSITY_DEBUG,
1149 		  "audio_alsa_out: Drain call failed. (err=%d:%s)\n",err, snd_strerror(err));
1150         }
1151         if ((err=snd_pcm_prepare(this->audio_fd)) < 0) {
1152           xprintf(this->class->xine, XINE_VERBOSITY_DEBUG,
1153 		  "audio_alsa_out: Prepare call failed. (err=%d:%s)\n",err, snd_strerror(err));
1154         }
1155       }
1156     }
1157     break;
1158 
1159   case AO_CTRL_PLAY_RESUME:
1160     if (this->audio_fd) {
1161       if (this->has_pause_resume && this->is_paused) {
1162         if ((err=snd_pcm_pause(this->audio_fd, 0)) < 0) {
1163           if (err == -77) {
1164             xprintf(this->class->xine, XINE_VERBOSITY_DEBUG,
1165 		    "audio_alsa_out: Warning: How am I supposed to RESUME, if I am not PAUSED. "
1166 		    "audio_out.c, please don't call me!\n");
1167             break;
1168           }
1169           xprintf(this->class->xine, XINE_VERBOSITY_DEBUG,
1170 		  "audio_alsa_out: Resume call failed. (err=%d:%s)\n",err, snd_strerror(err));
1171           this->has_pause_resume = 0;
1172         } else {
1173           this->is_paused = 0;
1174 	}
1175       }
1176     }
1177     break;
1178 
1179   case AO_CTRL_FLUSH_BUFFERS:
1180     if (this->audio_fd) {
1181       if ((err=snd_pcm_drop(this->audio_fd)) < 0) {
1182         xprintf(this->class->xine, XINE_VERBOSITY_DEBUG,
1183 		"audio_alsa_out: Drop call failed. (err=%d:%s)\n",err, snd_strerror(err));
1184       }
1185       if ((err=snd_pcm_prepare(this->audio_fd)) < 0) {
1186         xprintf(this->class->xine, XINE_VERBOSITY_DEBUG,
1187 		"audio_alsa_out: Prepare call failed. (err=%d:%s)\n",err, snd_strerror(err));
1188       }
1189     }
1190     break;
1191   }
1192 
1193   return 0;
1194 }
1195 
1196 /*
1197  * Initialize mixer
1198  */
ao_alsa_mixer_init(ao_driver_t * this_gen)1199 static void ao_alsa_mixer_init(ao_driver_t *this_gen) {
1200   alsa_driver_t        *this = (alsa_driver_t *) this_gen;
1201   config_values_t      *config = this->class->xine->config;
1202   const char           *pcm_device;
1203   snd_ctl_t            *ctl_handle;
1204   int                   err;
1205   void                 *mixer_sid;
1206   snd_mixer_elem_t     *elem;
1207   int                   mixer_n_selems = 0;
1208   snd_mixer_selem_id_t *sid;
1209   int                   loop = 0;
1210   int                   found;
1211   int                   swl = 0, swr = 0, send_events;
1212 
1213   this->mixer.elem = 0;
1214   pcm_device = this->devs[0].name;
1215   err = snd_ctl_open (&ctl_handle, pcm_device, 0);
1216   if (err < 0) {
1217     xprintf (this->class->xine, XINE_VERBOSITY_DEBUG, "audio_alsa_out: snd_ctl_open(): %s\n", snd_strerror(err));
1218     return;
1219   }
1220 
1221   if ((err = snd_ctl_card_info (ctl_handle, this->card_info)) < 0) {
1222     xprintf (this->class->xine, XINE_VERBOSITY_DEBUG,
1223 	     "audio_alsa_out: snd_ctl_card_info(): %s\n", snd_strerror(err));
1224     snd_ctl_close(ctl_handle);
1225     return;
1226   }
1227 
1228   snd_ctl_close (ctl_handle);
1229 
1230   /*
1231    * Open mixer device
1232    */
1233   if ((err = snd_mixer_open (&this->mixer.handle, 0)) < 0) {
1234     xprintf (this->class->xine, XINE_VERBOSITY_DEBUG,
1235 	     "audio_alsa_out: snd_mixer_open(): %s\n", snd_strerror(err));
1236     this->mixer.handle=0;
1237     return;
1238   }
1239 
1240   if ((err = snd_mixer_attach (this->mixer.handle, pcm_device)) < 0) {
1241     xprintf (this->class->xine, XINE_VERBOSITY_DEBUG,
1242 	     "audio_alsa_out: snd_mixer_attach(): %s\n", snd_strerror(err));
1243     snd_mixer_close(this->mixer.handle);
1244     this->mixer.handle=0;
1245     return;
1246   }
1247 
1248   if ((err = snd_mixer_selem_register (this->mixer.handle, NULL, NULL)) < 0) {
1249     xprintf (this->class->xine, XINE_VERBOSITY_DEBUG,
1250 	     "audio_alsa_out: snd_mixer_selem_register(): %s\n", snd_strerror(err));
1251     snd_mixer_close(this->mixer.handle);
1252     this->mixer.handle=0;
1253     return;
1254   }
1255 
1256   if ((err = snd_mixer_load (this->mixer.handle)) < 0) {
1257     xprintf (this->class->xine, XINE_VERBOSITY_DEBUG,
1258 	     "audio_alsa_out: snd_mixer_load(): %s\n", snd_strerror(err));
1259     snd_mixer_close(this->mixer.handle);
1260     this->mixer.handle=0;
1261     return;
1262   }
1263 
1264   mixer_sid = calloc (1, snd_mixer_selem_id_sizeof () * snd_mixer_get_count (this->mixer.handle));
1265   if (mixer_sid == NULL) {
1266     xprintf (this->class->xine, XINE_VERBOSITY_DEBUG,
1267       "audio_alsa_out: malloc () failed: %s\n", strerror (errno));
1268     snd_mixer_close(this->mixer.handle);
1269     this->mixer.handle=0;
1270     return;
1271   }
1272 
1273  again:
1274 
1275   found = 0;
1276   mixer_n_selems = 0;
1277   for (elem = snd_mixer_first_elem(this->mixer.handle); elem; elem = snd_mixer_elem_next(elem)) {
1278     sid = (snd_mixer_selem_id_t *)(((char *)mixer_sid) + snd_mixer_selem_id_sizeof() * mixer_n_selems);
1279 
1280     if ((snd_mixer_elem_get_type(elem) != SND_MIXER_ELEM_SIMPLE) ||
1281         !snd_mixer_selem_is_active(elem))
1282       continue;
1283 
1284     snd_mixer_selem_get_id(elem, sid);
1285     mixer_n_selems++;
1286 
1287     if(!strcmp((snd_mixer_selem_get_name(elem)), this->mixer.name)) {
1288       /* printf("found %s\n", snd_mixer_selem_get_name(elem)); */
1289 
1290       this->mixer.elem = elem;
1291 
1292       snd_mixer_selem_get_playback_volume_range(this->mixer.elem,
1293 						&this->mixer.min, &this->mixer.max);
1294       if((err = snd_mixer_selem_get_playback_volume(this->mixer.elem, SND_MIXER_SCHN_FRONT_LEFT,
1295 						    &this->mixer.left_vol)) < 0) {
1296 	xprintf(this->class->xine, XINE_VERBOSITY_DEBUG,
1297 		"audio_alsa_out: snd_mixer_selem_get_playback_volume(): %s\n",  snd_strerror(err));
1298 	this->mixer.elem = NULL;
1299 	continue;
1300       }
1301 
1302       if((err = snd_mixer_selem_get_playback_volume(this->mixer.elem, SND_MIXER_SCHN_FRONT_RIGHT,
1303 						    &this->mixer.right_vol)) < 0) {
1304 	xprintf (this->class->xine, XINE_VERBOSITY_DEBUG,
1305 		 "audio_alsa_out: snd_mixer_selem_get_playback_volume(): %s\n",  snd_strerror(err));
1306 	this->mixer.elem = NULL;
1307 	continue;
1308       }
1309 
1310       /* Channels mute */
1311       this->mixer.mute = 0;
1312       if(snd_mixer_selem_has_playback_switch(this->mixer.elem)) {
1313 	this->mixer.mute |= MIXER_HAS_MUTE_SWITCH;
1314 
1315 	if (snd_mixer_selem_has_playback_switch_joined(this->mixer.elem)) {
1316 	  this->mixer.mute |= MIXER_MASK_STEREO;
1317 	  snd_mixer_selem_get_playback_switch(this->mixer.elem, SND_MIXER_SCHN_FRONT_LEFT, &swl);
1318 	}
1319 	else {
1320 	  this->mixer.mute |= MIXER_MASK_LEFT;
1321 	  snd_mixer_selem_get_playback_switch(this->mixer.elem, SND_MIXER_SCHN_FRONT_LEFT, &swl);
1322 
1323 	  if (SND_MIXER_SCHN_FRONT_RIGHT != SND_MIXER_SCHN_UNKNOWN) {
1324 	    this->mixer.mute |= MIXER_MASK_RIGHT;
1325 	    snd_mixer_selem_get_playback_switch(this->mixer.elem, SND_MIXER_SCHN_FRONT_RIGHT, &swr);
1326 	  }
1327 
1328 	  if(!swl || !swr)
1329 	    this->mixer.mute |= MIXER_MASK_MUTE;
1330 	}
1331 
1332 	this->capabilities |= AO_CAP_MUTE_VOL;
1333       }
1334 
1335       found++;
1336 
1337       goto mixer_found;
1338     }
1339   }
1340 
1341   if(loop)
1342     goto mixer_found; /* Yes, untrue but... ;-) */
1343 
1344   if(!strcmp(this->mixer.name, "PCM")) {
1345     config->update_string(config, "audio.device.alsa_mixer_name", "Master");
1346     loop++;
1347   }
1348   else {
1349     config->update_string(config, "audio.device.alsa_mixer_name", "PCM");
1350   }
1351 
1352   config->free_string(config, &this->mixer.name);
1353   this->mixer.name = config->lookup_string(config, "audio.device.alsa_mixer_name");
1354 
1355   goto again;
1356 
1357  mixer_found:
1358 
1359   free (mixer_sid);
1360 
1361   /*
1362    * Ugly: yes[*]  no[ ]
1363    */
1364   if(found) {
1365     if(!strcmp(this->mixer.name, "Master"))
1366       this->capabilities |= AO_CAP_MIXER_VOL;
1367     else
1368       this->capabilities |= AO_CAP_PCM_VOL;
1369   } else {
1370     if (this->mixer.handle) {
1371       snd_mixer_close(this->mixer.handle);
1372       this->mixer.handle=0;
1373     }
1374     return;
1375   }
1376 
1377   /* Create a thread which wait/handle mixer events */
1378   send_events = config->register_bool(config, "audio.alsa_hw_mixer", 1,
1379 				      _("notify changes to the hardware mixer"),
1380 				      _("When the hardware mixer changes, your application will receive "
1381 				        "a notification so that it can update its graphical representation "
1382 				        "of the mixer settings on the fly."),
1383 				      10, NULL, NULL);
1384 
1385   if (send_events && found) {
1386     pthread_attr_t       pth_attrs;
1387     struct sched_param   pth_params;
1388 
1389     this->mixer.running = 1;
1390 
1391     pthread_attr_init(&pth_attrs);
1392 
1393     pthread_attr_getschedparam(&pth_attrs, &pth_params);
1394     pth_params.sched_priority = sched_get_priority_min(SCHED_OTHER);
1395     pthread_attr_setschedparam(&pth_attrs, &pth_params);
1396     if (pthread_create(&this->mixer.thread, &pth_attrs, ao_alsa_handle_event_thread, (void *) this)) {
1397       xprintf (this->class->xine, XINE_VERBOSITY_LOG, LOG_MODULE ": pthread_create() failed\n");
1398     } else {
1399       this->mixer.thread_created = 1;
1400     }
1401     pthread_attr_destroy(&pth_attrs);
1402   }
1403 }
1404 
alsa_apply_speaker_arrangement(alsa_driver_t * this,int speakers)1405 static void alsa_apply_speaker_arrangement (alsa_driver_t *this, int speakers) {
1406   char logbuf[2048], *q, *logend = logbuf + sizeof (logbuf);
1407 
1408   q = logbuf;
1409   q += strlcpy (q, _("audio_alsa_out : supported modes are"), logend - q);
1410   if (q >= logend)
1411     q = logend;
1412 
1413   if (this->capabilities & AO_CAP_8BITS) {
1414     q += strlcpy (q, this->bits_names[0], logend - q);
1415     if (q >= logend)
1416       q = logend;
1417   }
1418   if (this->capabilities & AO_CAP_16BITS) {
1419     q += strlcpy (q, this->bits_names[1], logend - q);
1420     if (q >= logend)
1421       q = logend;
1422   }
1423   if (this->capabilities & AO_CAP_24BITS) {
1424     q += strlcpy (q, this->bits_names[2], logend - q);
1425     if (q >= logend)
1426       q = logend;
1427   }
1428   if (this->capabilities & AO_CAP_FLOAT32) {
1429     q += strlcpy (q, this->bits_names[3], logend - q);
1430     if (q >= logend)
1431       q = logend;
1432   }
1433 
1434   this->capabilities &= ~(AO_CAP_MODE_MONO |
1435                           AO_CAP_MODE_STEREO |
1436                           AO_CAP_MODE_4CHANNEL |
1437                           AO_CAP_MODE_4_1CHANNEL |
1438                           AO_CAP_MODE_5CHANNEL |
1439                           AO_CAP_MODE_5_1CHANNEL |
1440                           AO_CAP_MODE_A52 |
1441                           AO_CAP_MODE_AC5);
1442 
1443   /* always set these. */
1444   if (this->supported_channels & (1 << 1)) {
1445     this->capabilities |= AO_CAP_MODE_MONO;
1446     q += strlcpy (q, this->devs[0].type, logend - q);
1447     if (q >= logend)
1448       q = logend;
1449   }
1450   if (this->supported_channels & (1 << 2)) {
1451     this->capabilities |= AO_CAP_MODE_STEREO;
1452     q += strlcpy (q, this->devs[1].type, logend - q);
1453     if (q >= logend)
1454       q = logend;
1455   }
1456 
1457   if (this->supported_channels & (1 << 4)) {
1458     const char *t;
1459     if (speakers == SURROUND4) {
1460       this->capabilities |= AO_CAP_MODE_4CHANNEL;
1461       t = this->devs[2].type;
1462     } else {
1463       t = _(" (4-channel not enabled in xine config)");
1464     }
1465     q += strlcpy (q, t, logend - q);
1466     if (q >= logend)
1467       q = logend;
1468   }
1469   if (this->supported_channels & (1 << 6)) {
1470     const char *t;
1471     if (speakers == SURROUND41) {
1472       this->capabilities |= AO_CAP_MODE_4_1CHANNEL;
1473       t = _(" 4.1-channel");
1474     } else {
1475       t = _(" (4.1-channel not enabled in xine config)");
1476     }
1477     q += strlcpy (q, t, logend - q);
1478     if (q >= logend)
1479       q = logend;
1480     if (speakers == SURROUND5) {
1481       this->capabilities |= AO_CAP_MODE_5CHANNEL;
1482       t = _(" 5-channel");
1483     } else {
1484       t = _(" (5-channel not enabled in xine config)");
1485     }
1486     q += strlcpy (q, t, logend - q);
1487     if (q >= logend)
1488       q = logend;
1489     /* NOTE: That ">=" covers both the high channel counts and passthrough mode.
1490      * This is more or less a BUG when a traditional SPDIF link is used.
1491      * However, if alsa_surround51_device refers to the same HDMI port
1492      * as alsa_passthrough_device, then we have a HACK that routes software
1493      * decoded 5.1 where it belongs :-) */
1494     if (speakers >= SURROUND51) {
1495       this->capabilities |= AO_CAP_MODE_5_1CHANNEL;
1496       t = this->devs[3].type;
1497     } else {
1498       t = _(" (5.1-channel not enabled in xine config)");
1499     }
1500     q += strlcpy (q, t, logend - q);
1501     if (q >= logend)
1502       q = logend;
1503   }
1504 
1505   {
1506     const char *t;
1507     if (speakers == A52_PASSTHRU) {
1508       this->capabilities |= AO_CAP_MODE_A52 | AO_CAP_MODE_AC5;
1509       t = this->devs[4].type;
1510     } else {
1511       t = _(" (a/52 and DTS pass-through not enabled in xine config)");
1512     }
1513     q += strlcpy (q, t, logend - q);
1514 /*  if (q >= logend)
1515       q = logend; */
1516   }
1517 
1518   xprintf (this->class->xine, XINE_VERBOSITY_LOG, "%s.\n", logbuf);
1519 }
1520 
_alsa_mmap_cb(void * user_data,xine_cfg_entry_t * entry)1521 static void _alsa_mmap_cb (void *user_data, xine_cfg_entry_t *entry) {
1522   alsa_driver_t *this = (alsa_driver_t *)user_data;
1523   this->mmap = entry->num_value;
1524 }
1525 
_alsa_speaker_arrangement_cb(void * user_data,xine_cfg_entry_t * entry)1526 static void _alsa_speaker_arrangement_cb (void *user_data, xine_cfg_entry_t *entry) {
1527   alsa_driver_t *this = (alsa_driver_t *)user_data;
1528   alsa_apply_speaker_arrangement (this, entry->num_value);
1529 }
1530 
_alsa_safe_strdup(const char * s)1531 static char *_alsa_safe_strdup (const char *s) {
1532   return s ? strdup (s) : NULL;
1533 }
1534 
_alsa_dev_name_cb(void * user_data,xine_cfg_entry_t * entry)1535 static void _alsa_dev_name_cb (void *user_data, xine_cfg_entry_t *entry) {
1536   struct _alsa_dev_info_s *info = (struct _alsa_dev_info_s *)user_data;
1537   free (info->name);
1538   info->name = _alsa_safe_strdup (entry->str_value);
1539 }
1540 
_alsa_query_dev(alsa_driver_t * this,uint32_t index)1541 static int _alsa_query_dev (alsa_driver_t *this, uint32_t index) {
1542   char logbuf[2048], *q = logbuf, *logend = logbuf + sizeof (logbuf);
1543   struct _alsa_dev_info_s *info = &this->devs[index];
1544   const char *name;
1545   uint32_t u;
1546   int err;
1547 
1548   name = info->name ? info->name : "default";
1549   if (1) {
1550     /* skip doubles */
1551     for (u = 0; u < sizeof (this->devs) / sizeof (this->devs[0]); u++) {
1552       if (u != index) {
1553         const char *alias = this->devs[u].name ? this->devs[u].name : "default";
1554         if (!strcmp (name, alias) && this->devs[u].supported_channels) {
1555           info->capabilities = this->devs[u].capabilities;
1556           info->supported_channels = this->devs[u].supported_channels;
1557           xprintf (this->class->xine, XINE_VERBOSITY_DEBUG,
1558             "audio_alsa_out: already probed \"%s\" for%s.\n", name, info->type);
1559           return 2;
1560         }
1561       }
1562     }
1563   }
1564   xprintf (this->class->xine, XINE_VERBOSITY_DEBUG,
1565     "audio_alsa_out: probing \"%s\" for%s ...\n", name, info->type);
1566   q += strlcpy (q, "audio_alsa_out: ", logend - q);
1567   if (q > logend)
1568     q = logend;
1569   q += strlcpy (q, name, logend - q);
1570   if (q > logend)
1571     q = logend;
1572   q += strlcpy (q, ": ", logend - q);
1573   if (q > logend)
1574     q = logend;
1575 
1576   err = snd_pcm_open (&this->audio_fd, name, SND_PCM_STREAM_PLAYBACK, 1); /* NON-BLOCK mode */
1577   if (err < 0) {
1578     xine_log (this->class->xine, XINE_LOG_MSG,
1579       _("snd_pcm_open() failed:%d:%s\n"), err, snd_strerror (err));
1580     xine_log (this->class->xine, XINE_LOG_MSG,
1581       _(">>> Check if another program already uses PCM <<<\n"));
1582     return 0;
1583   }
1584 
1585   err = snd_pcm_hw_params_any (this->audio_fd, this->hw_params);
1586   if (err < 0) {
1587     xprintf (this->class->xine, XINE_VERBOSITY_DEBUG,
1588       "audio_alsa_out: broken configuration for this PCM: no configurations available.\n");
1589     snd_pcm_close (this->audio_fd);
1590     this->audio_fd = NULL;
1591     return 0;
1592   }
1593 
1594   info->capabilities &= ~(AO_CAP_8BITS | AO_CAP_16BITS | AO_CAP_24BITS | AO_CAP_FLOAT32);
1595   if (!(snd_pcm_hw_params_test_format (this->audio_fd, this->hw_params, SND_PCM_FORMAT_U8))) {
1596     info->capabilities |= AO_CAP_8BITS;
1597     q += strlcpy (q, this->bits_names[0], logend - q);
1598     if (q > logend)
1599       q = logend;
1600   }
1601   if (!(snd_pcm_hw_params_test_format (this->audio_fd, this->hw_params, SND_PCM_FORMAT_S16))) {
1602     info->capabilities |= AO_CAP_16BITS;
1603     q += strlcpy (q, this->bits_names[1], logend - q);
1604     if (q > logend)
1605       q = logend;
1606   }
1607   if (!(snd_pcm_hw_params_test_format (this->audio_fd, this->hw_params, SND_PCM_FORMAT_S24))) {
1608     info->capabilities |= AO_CAP_24BITS;
1609     q += strlcpy (q, this->bits_names[2], logend - q);
1610     if (q > logend)
1611       q = logend;
1612   }
1613   if (!(snd_pcm_hw_params_test_format (this->audio_fd, this->hw_params, SND_PCM_FORMAT_FLOAT))) {
1614     info->capabilities |= AO_CAP_FLOAT32;
1615     q += strlcpy (q, this->bits_names[3], logend - q);
1616     if (q > logend)
1617       q = logend;
1618   }
1619   if (0 == (info->capabilities & (AO_CAP_FLOAT32 | AO_CAP_24BITS | AO_CAP_16BITS | AO_CAP_8BITS))) {
1620     xprintf (this->class->xine, XINE_VERBOSITY_DEBUG, "audio_alsa_out: no supported PCM format found.\n");
1621     snd_pcm_close (this->audio_fd);
1622     this->audio_fd = NULL;
1623     return 0;
1624   }
1625 
1626   info->supported_channels = 0;
1627   if (!(snd_pcm_hw_params_test_channels (this->audio_fd, this->hw_params, 1))) {
1628     info->supported_channels |= 1 << 1;
1629     q += strlcpy (q, this->devs[0].type, logend - q);
1630     if (q > logend)
1631       q = logend;
1632   }
1633   if (!(snd_pcm_hw_params_test_channels (this->audio_fd, this->hw_params, 2))) {
1634     info->supported_channels |= 1 << 2;
1635     q += strlcpy (q, this->devs[1].type, logend - q);
1636     if (q > logend)
1637       q = logend;
1638   }
1639   if (!(snd_pcm_hw_params_test_channels (this->audio_fd, this->hw_params, 4))) {
1640     info->supported_channels |= 1 << 4;
1641     q += strlcpy (q, this->devs[2].type, logend - q);
1642     if (q > logend)
1643       q = logend;
1644   }
1645   if (!(snd_pcm_hw_params_test_channels (this->audio_fd, this->hw_params, 6))) {
1646     info->supported_channels |= 1 << 6;
1647     q += strlcpy (q, this->devs[3].type, logend - q);
1648     if (q > logend)
1649       q = logend;
1650   }
1651 
1652   err = snd_pcm_hw_params_set_access (this->audio_fd, this->hw_params, SND_PCM_ACCESS_RW_INTERLEAVED);
1653   if (err < 0) {
1654     xprintf (this->class->xine, XINE_VERBOSITY_DEBUG,
1655       "audio_alsa_out: interleaved access not available.");
1656     snd_pcm_close (this->audio_fd);
1657     this->audio_fd = NULL;
1658     return 0;
1659   }
1660 
1661   if (index == 4) {
1662     info->capabilities |= AO_CAP_MODE_A52 | AO_CAP_MODE_AC5;
1663     q += strlcpy (q, this->devs[4].type, logend - q);
1664     if (q > logend)
1665       q = logend;
1666   }
1667 
1668   xprintf (this->class->xine, XINE_VERBOSITY_DEBUG, "%s.\n", logbuf);
1669 
1670   this->supported_channels = 0;
1671   for (u = 0; u < sizeof (this->devs) / sizeof (this->devs[0]); u++) {
1672     this->supported_channels |= this->devs[u].supported_channels;
1673     if (u != index) {
1674       const char *alias = this->devs[u].name ? this->devs[u].name : "default";
1675       if (!strcmp (name, alias)) {
1676         this->devs[u].capabilities = info->capabilities;
1677         this->devs[u].supported_channels = info->supported_channels;
1678       }
1679     }
1680   }
1681 
1682   snd_pcm_close (this->audio_fd);
1683   this->audio_fd = NULL;
1684   return 1;
1685 }
1686 
1687 /*
1688  * Initialize plugin
1689  */
1690 
open_plugin(audio_driver_class_t * class_gen,const void * data)1691 static ao_driver_t *open_plugin (audio_driver_class_t *class_gen, const void *data) {
1692   alsa_class_t        *class = (alsa_class_t *) class_gen;
1693   config_values_t     *config = class->xine->config;
1694   alsa_driver_t       *this;
1695 
1696   (void)data;
1697   {
1698     uint32_t s_this      = (sizeof (*this) + 15) & ~15u;
1699     uint32_t s_hw_params = (snd_pcm_hw_params_sizeof () + 15) & ~15u;
1700     uint32_t s_sw_params = (snd_pcm_sw_params_sizeof () + 15) & ~15u;
1701     uint32_t s_ac_mask   = (snd_pcm_access_mask_sizeof () + 15) & ~15u;
1702     uint32_t s_card_info = (snd_ctl_card_info_sizeof () + 15) & ~15u;
1703     uint32_t s_status    = (snd_pcm_status_sizeof () + 15) & ~15u;
1704     uint8_t *m = calloc (1, s_this + s_hw_params + s_sw_params + s_ac_mask + s_card_info + s_status);
1705     if (!m)
1706       return NULL;
1707     this = (alsa_driver_t *)m;
1708     m += s_this;
1709     this->hw_params  = (snd_pcm_hw_params_t *)m;
1710     m += s_hw_params;
1711     this->sw_params  = (snd_pcm_sw_params_t *)m;
1712     m += s_sw_params;
1713     this->ac_mask    = (snd_pcm_access_mask_t *)m;
1714     m += s_ac_mask;
1715     this->card_info  = (snd_ctl_card_info_t *)m;
1716     m += s_card_info;
1717     this->pcm_status = (snd_pcm_status_t *)m;
1718   }
1719 #ifndef HAVE_ZERO_SAFE_MEM
1720   this->devs[0].supported_channels = 0;
1721   this->devs[0].capabilities       = 0;
1722   this->devs[1].supported_channels = 0;
1723   this->devs[1].capabilities       = 0;
1724   this->devs[2].supported_channels = 0;
1725   this->devs[2].capabilities       = 0;
1726   this->devs[3].supported_channels = 0;
1727   this->devs[3].capabilities       = 0;
1728   this->devs[4].supported_channels = 0;
1729   this->devs[4].capabilities       = 0;
1730   this->capabilities               = 0;
1731   this->has_pause_resume           = 0; /* This is checked at open time instead */
1732   this->is_paused                  = 0;
1733   this->output_sample_rate         = 0;
1734 #endif
1735 
1736   this->class = class;
1737 
1738   this->bits_names[0] = _(" 8bit");
1739   this->bits_names[1] = _(" 16bit");
1740   this->bits_names[2] = _(" 24bit");
1741   this->bits_names[3] = _(" 32bit");
1742 
1743   this->mmap = config->register_bool (config, "audio.device.alsa_mmap_enable", 0,
1744     _("sound card can do mmap"),
1745     _("Enable this, if your sound card and alsa driver support memory mapped IO.\n"
1746       "You can try enabling it and check, if everything works. If it does, this "
1747       "will increase performance."),
1748     10, _alsa_mmap_cb, this);
1749 
1750   this->devs[0].this = this;
1751   this->devs[0].type = _(" mono");
1752   this->devs[0].config_key = "audio.device.alsa_default_device";
1753   this->devs[0].name = _alsa_safe_strdup (config->register_string (config,
1754     this->devs[0].config_key,
1755     "default",
1756     _("device used for mono output"),
1757     _("xine will use this alsa device to output mono sound.\n"
1758       "See the alsa documentation for information on alsa devices."),
1759     10, _alsa_dev_name_cb, &this->devs[0]));
1760 
1761   this->devs[1].this = this;
1762   this->devs[1].type = _(" stereo");
1763   this->devs[1].config_key = "audio.device.alsa_front_device";
1764   this->devs[1].name = _alsa_safe_strdup (config->register_string (config,
1765     this->devs[1].config_key,
1766     "plug:front:default",
1767     _("device used for stereo output"),
1768     _("xine will use this alsa device to output stereo sound.\n"
1769       "See the alsa documentation for information on alsa devices."),
1770     10, _alsa_dev_name_cb, &this->devs[1]));
1771 
1772   this->devs[2].this = this;
1773   this->devs[2].type = _(" 4-channel");
1774   this->devs[2].config_key = "audio.device.alsa_surround40_device";
1775   this->devs[2].name = _alsa_safe_strdup (config->register_string (config,
1776     this->devs[2].config_key,
1777     "plug:surround40:0",
1778     _("device used for 4-channel output"),
1779     _("xine will use this alsa device to output 4 channel (4.0) surround sound.\n"
1780       "See the alsa documentation for information on alsa devices."),
1781     10, _alsa_dev_name_cb, &this->devs[2]));
1782 
1783   this->devs[3].this = this;
1784   this->devs[3].type = _(" 5.1-channel");
1785   this->devs[3].config_key = "audio.device.alsa_surround51_device";
1786   this->devs[3].name = _alsa_safe_strdup (config->register_string (config,
1787     this->devs[3].config_key,
1788     "plug:surround51:0",
1789     _("device used for 5.1-channel output"),
1790     _("xine will use this alsa device to output 5 channel plus LFE (5.1) surround sound.\n"
1791       "See the alsa documentation for information on alsa devices."),
1792     10, _alsa_dev_name_cb, &this->devs[3]));
1793 
1794   this->devs[4].this = this;
1795   this->devs[4].type = _(" a/52 and DTS pass-through");
1796   this->devs[4].config_key = "audio.device.alsa_passthrough_device";
1797   this->devs[4].name = _alsa_safe_strdup (config->register_string (config,
1798     this->devs[4].config_key,
1799     "iec958:AES0=0x6,AES1=0x82,AES2=0x0,AES3=0x2",
1800     _("device used for a/52 and DTS pass-through"),
1801     _("xine will use this alsa device to output undecoded digital surround sound. "
1802       "This can be used be external surround decoders.\n"
1803       "See the alsa documentation for information on alsa devices."),
1804     10, _alsa_dev_name_cb, &this->devs[4]));
1805 
1806   {
1807     int err = snd_lib_error_set_handler (error_callback);
1808     if (err < 0)
1809       xine_log (this->class->xine, XINE_LOG_MSG, _("snd_lib_error_set_handler() failed: %d"), err);
1810   }
1811 
1812   {
1813     AUDIO_DEVICE_SPEAKER_ARRANGEMENT_TYPES;
1814     int speakers;
1815 
1816     /* for usability reasons, keep this in sync with audio_oss_out.c */
1817     speakers = config->register_enum (config,
1818       "audio.output.speaker_arrangement",
1819       STEREO,
1820       (char **)speaker_arrangement,
1821       AUDIO_DEVICE_SPEAKER_ARRANGEMENT_HELP,
1822       0, _alsa_speaker_arrangement_cb, this);
1823 
1824     /* query the devices we might need, and stop at stereo. */
1825     switch (speakers) {
1826       case A52_PASSTHRU:
1827         if (_alsa_query_dev (this, 4))
1828           this->capabilities |= this->devs[4].capabilities;
1829         /* fall through */
1830       case SURROUND71:
1831       case SURROUND61:
1832       case SURROUND6:
1833       case SURROUND51:
1834       case SURROUND5:
1835       case SURROUND41:
1836         if (_alsa_query_dev (this, 3)) {
1837           this->capabilities |= this->devs[3].capabilities;
1838           break;
1839         }
1840         /* fall through */
1841       case SURROUND4:
1842         if (_alsa_query_dev (this, 2))
1843           this->capabilities |= this->devs[2].capabilities;
1844         break;
1845       default: ;
1846     }
1847     if (_alsa_query_dev (this, 0))
1848       this->capabilities |= this->devs[0].capabilities;
1849     if (_alsa_query_dev (this, 1)) {
1850       this->capabilities |= this->devs[1].capabilities;
1851     } else {
1852       /* Fallback to "default" if device "front" does not exist.
1853        * Needed for some very basic sound cards. */
1854       config->update_string (config, this->devs[1].config_key, "default");
1855       if (_alsa_query_dev (this, 1))
1856         this->capabilities |= this->devs[1].capabilities;
1857     }
1858 
1859     alsa_apply_speaker_arrangement (this, speakers);
1860   }
1861 
1862   do {
1863     /* printf("audio_alsa_out: capabilities 0x%X\n",this->capabilities); */
1864     if (!this->capabilities)
1865       break;
1866 
1867     config->register_string (config,
1868       "audio.device.alsa_mixer_name",
1869       "PCM",
1870       _("alsa mixer device"),
1871       _("xine will use this alsa mixer device to change the volume.\n"
1872         "See the alsa documentation for information on alsa devices."),
1873       10, NULL, NULL);
1874     this->mixer.name = config->lookup_string(config, "audio.device.alsa_mixer_name");
1875     if (!this->mixer.name)
1876       break;
1877 
1878     pthread_mutex_init (&this->mixer.mutex, NULL);
1879     ao_alsa_mixer_init (&this->ao_driver);
1880 
1881     this->ao_driver.get_capabilities    = ao_alsa_get_capabilities;
1882     this->ao_driver.get_property        = ao_alsa_get_property;
1883     this->ao_driver.set_property        = ao_alsa_set_property;
1884     this->ao_driver.open                = ao_alsa_open;
1885     this->ao_driver.num_channels        = ao_alsa_num_channels;
1886     this->ao_driver.bytes_per_frame     = ao_alsa_bytes_per_frame;
1887     this->ao_driver.delay               = ao_alsa_delay;
1888     this->ao_driver.write               = ao_alsa_write;
1889     this->ao_driver.close               = ao_alsa_close;
1890     this->ao_driver.exit                = ao_alsa_exit;
1891     this->ao_driver.get_gap_tolerance   = ao_alsa_get_gap_tolerance;
1892     this->ao_driver.control             = ao_alsa_ctrl;
1893 
1894     return &this->ao_driver;
1895   } while (0);
1896 
1897   config->unregister_callbacks (config, NULL, NULL, this, sizeof (*this));
1898   {
1899     uint32_t u;
1900     for (u = 0; u < sizeof (this->devs) / sizeof (this->devs[0]); u++) {
1901       _x_freep (&this->devs[u].name);
1902     }
1903   }
1904   free (this);
1905   return NULL;
1906 }
1907 
1908 
1909 
1910 /*
1911  * class functions
1912  */
init_class(xine_t * xine,const void * data)1913 static void *init_class (xine_t *xine, const void *data) {
1914   alsa_class_t *this;
1915 
1916   (void)data;
1917   this = calloc(1, sizeof (alsa_class_t));
1918   if (!this)
1919     return NULL;
1920 
1921   this->driver_class.open_plugin     = open_plugin;
1922   this->driver_class.identifier      = "alsa";
1923   this->driver_class.description     = N_("xine audio output plugin using alsa-compliant audio devices/drivers");
1924   this->driver_class.dispose         = default_audio_driver_class_dispose;
1925 
1926 /*  this->config = xine->config; */
1927   this->xine = xine;
1928   return this;
1929  }
1930 
1931 static ao_info_t ao_info_alsa = {
1932   .priority = 10,
1933 };
1934 
1935 /*
1936  * exported plugin catalog entry
1937  */
1938 
1939 const plugin_info_t xine_plugin_info[] EXPORTED = {
1940   /* type, API, "name", version, special_info, init_function */
1941   { PLUGIN_AUDIO_OUT, AO_OUT_ALSA_IFACE_VERSION, "alsa", XINE_VERSION_CODE, &ao_info_alsa, init_class },
1942   { PLUGIN_NONE, 0, NULL, 0, NULL, NULL }
1943 };
1944