1 /* libSoX device driver: ALSA   (c) 2006-2012 SoX contributors
2  *
3  * This library is free software; you can redistribute it and/or modify it
4  * under the terms of the GNU Lesser General Public License as published by
5  * the Free Software Foundation; either version 2.1 of the License, or (at
6  * your option) any later version.
7  *
8  * This library is distributed in the hope that it will be useful, but
9  * WITHOUT ANY WARRANTY; without even the implied warranty of
10  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser
11  * General Public License for more details.
12  *
13  * You should have received a copy of the GNU Lesser General Public License
14  * along with this library; if not, write to the Free Software Foundation,
15  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
16  */
17 
18 #include "sox_i.h"
19 #include <alsa/asoundlib.h>
20 
21 typedef struct {
22   snd_pcm_uframes_t  buf_len, period;
23   snd_pcm_t          * pcm;
24   char               * buf;
25   unsigned int       format;
26 } priv_t;
27 
28 static const
29   struct {
30     unsigned int bits;
31     enum _snd_pcm_format alsa_fmt;
32     unsigned int bytes; /* occupied in the buffer per sample */
33     sox_encoding_t enc;
34   } formats[] = {
35     /* order by # of bits; within that, preferred first */
36     {  8, SND_PCM_FORMAT_S8, 1, SOX_ENCODING_SIGN2 },
37     {  8, SND_PCM_FORMAT_U8, 1, SOX_ENCODING_UNSIGNED },
38     { 16, SND_PCM_FORMAT_S16, 2, SOX_ENCODING_SIGN2 },
39     { 16, SND_PCM_FORMAT_U16, 2, SOX_ENCODING_UNSIGNED },
40     { 24, SND_PCM_FORMAT_S24, 4, SOX_ENCODING_SIGN2 },
41     { 24, SND_PCM_FORMAT_U24, 4, SOX_ENCODING_UNSIGNED },
42     { 24, SND_PCM_FORMAT_S24_3LE, 3, SOX_ENCODING_SIGN2 },
43     { 32, SND_PCM_FORMAT_S32, 4, SOX_ENCODING_SIGN2 },
44     { 32, SND_PCM_FORMAT_U32, 4, SOX_ENCODING_UNSIGNED },
45     {  0, 0, 0, SOX_ENCODING_UNKNOWN } /* end of list */
46   };
47 
select_format(sox_encoding_t * encoding_,unsigned * nbits_,snd_pcm_format_mask_t const * mask,unsigned int * format)48 static int select_format(
49     sox_encoding_t              * encoding_,
50     unsigned                    * nbits_,
51     snd_pcm_format_mask_t const * mask,
52     unsigned int                * format)
53 {
54   unsigned int from = 0, to; /* NB: "to" actually points one after the last */
55   int cand = -1;
56 
57   while (formats[from].bits < *nbits_ && formats[from].bits != 0)
58     from++;  /* find the first entry with at least *nbits_ bits */
59   for (to = from; formats[to].bits != 0; to++) ;  /* find end of list */
60 
61   while (to > 0) {
62     unsigned int i, bits_next = 0;
63     for (i = from; i < to; i++) {
64       lsx_debug_most("select_format: trying #%u", i);
65       if (snd_pcm_format_mask_test(mask, formats[i].alsa_fmt)) {
66         if (formats[i].enc == *encoding_) {
67           cand = i;
68           break; /* found a match */
69         } else if (cand == -1) /* don't overwrite a candidate that
70                                        was earlier in the list */
71           cand = i; /* will work, but encoding differs */
72       }
73     }
74     if (cand != -1)
75       break;
76     /* no candidate found yet; now try formats with less bits: */
77     to = from;
78     if (from > 0)
79       bits_next = formats[from-1].bits;
80     while (from && formats[from-1].bits == bits_next)
81       from--; /* go back to the first entry with bits_next bits */
82   }
83 
84   if (cand == -1) {
85     lsx_debug("select_format: no suitable ALSA format found");
86     return -1;
87   }
88 
89   if (*nbits_ != formats[cand].bits || *encoding_ != formats[cand].enc) {
90     lsx_warn("can't encode %u-bit %s", *nbits_,
91         sox_encodings_info[*encoding_].desc);
92     *nbits_ = formats[cand].bits;
93     *encoding_ = formats[cand].enc;
94   }
95   lsx_debug("selecting format %d: %s (%s)", cand,
96       snd_pcm_format_name(formats[cand].alsa_fmt),
97       snd_pcm_format_description(formats[cand].alsa_fmt));
98   *format = cand;
99   return 0;
100 }
101 
102 #define _(x,y) do {if ((err = x y) < 0) {lsx_fail_errno(ft, SOX_EPERM, #x " error: %s", snd_strerror(err)); goto error;} } while (0)
setup(sox_format_t * ft)103 static int setup(sox_format_t * ft)
104 {
105   priv_t                 * p = (priv_t *)ft->priv;
106   snd_pcm_hw_params_t    * params = NULL;
107   snd_pcm_format_mask_t  * mask = NULL;
108   snd_pcm_uframes_t      min, max;
109   unsigned               n;
110   int                    err;
111 
112   _(snd_pcm_open, (&p->pcm, ft->filename, ft->mode == 'r'? SND_PCM_STREAM_CAPTURE : SND_PCM_STREAM_PLAYBACK, 0));
113   _(snd_pcm_hw_params_malloc, (&params));
114   _(snd_pcm_hw_params_any, (p->pcm, params));
115 #if SND_LIB_VERSION >= 0x010009               /* Disable alsa-lib resampling: */
116   _(snd_pcm_hw_params_set_rate_resample, (p->pcm, params, 0));
117 #endif
118   _(snd_pcm_hw_params_set_access, (p->pcm, params, SND_PCM_ACCESS_RW_INTERLEAVED));
119 
120   _(snd_pcm_format_mask_malloc, (&mask));           /* Set format: */
121   snd_pcm_hw_params_get_format_mask(params, mask);
122   _(select_format, (&ft->encoding.encoding, &ft->encoding.bits_per_sample, mask, &p->format));
123   _(snd_pcm_hw_params_set_format, (p->pcm, params, formats[p->format].alsa_fmt));
124   snd_pcm_format_mask_free(mask), mask = NULL;
125 
126   n = ft->signal.rate;                              /* Set rate: */
127   _(snd_pcm_hw_params_set_rate_near, (p->pcm, params, &n, 0));
128   ft->signal.rate = n;
129 
130   n = ft->signal.channels;                          /* Set channels: */
131   _(snd_pcm_hw_params_set_channels_near, (p->pcm, params, &n));
132   ft->signal.channels = n;
133 
134   /* Get number of significant bits: */
135   if ((err = snd_pcm_hw_params_get_sbits(params)) > 0)
136     ft->signal.precision = min(err, SOX_SAMPLE_PRECISION);
137   else lsx_debug("snd_pcm_hw_params_get_sbits can't tell precision: %s",
138            snd_strerror(err));
139 
140   /* Set buf_len > > sox_globals.bufsiz for no underrun: */
141   p->buf_len = sox_globals.bufsiz * 8 / formats[p->format].bytes /
142       ft->signal.channels;
143   _(snd_pcm_hw_params_get_buffer_size_min, (params, &min));
144   _(snd_pcm_hw_params_get_buffer_size_max, (params, &max));
145   p->period = range_limit(p->buf_len, min, max) / 8;
146   p->buf_len = p->period * 8;
147   _(snd_pcm_hw_params_set_period_size_near, (p->pcm, params, &p->period, 0));
148   _(snd_pcm_hw_params_set_buffer_size_near, (p->pcm, params, &p->buf_len));
149   if (p->period * 2 > p->buf_len) {
150     lsx_fail_errno(ft, SOX_EPERM, "buffer too small");
151     goto error;
152   }
153 
154   _(snd_pcm_hw_params, (p->pcm, params));           /* Configure ALSA */
155   snd_pcm_hw_params_free(params), params = NULL;
156   _(snd_pcm_prepare, (p->pcm));
157   p->buf_len *= ft->signal.channels;                /* No longer in `frames' */
158   p->buf = lsx_malloc(p->buf_len * formats[p->format].bytes);
159   return SOX_SUCCESS;
160 
161 error:
162   if (mask) snd_pcm_format_mask_free(mask);
163   if (params) snd_pcm_hw_params_free(params);
164   return SOX_EOF;
165 }
166 
recover(sox_format_t * ft,snd_pcm_t * pcm,int err)167 static int recover(sox_format_t * ft, snd_pcm_t * pcm, int err)
168 {
169   if (err == -EPIPE)
170     lsx_warn("%s-run", ft->mode == 'r'? "over" : "under");
171   else if (err != -ESTRPIPE)
172     lsx_warn("%s", snd_strerror(err));
173   else while ((err = snd_pcm_resume(pcm)) == -EAGAIN) {
174     lsx_report("suspended");
175     sleep(1);                  /* Wait until the suspend flag is released */
176   }
177   if (err < 0 && (err = snd_pcm_prepare(pcm)) < 0)
178     lsx_fail_errno(ft, SOX_EPERM, "%s", snd_strerror(err));
179   return err;
180 }
181 
read_(sox_format_t * ft,sox_sample_t * buf,size_t len)182 static size_t read_(sox_format_t * ft, sox_sample_t * buf, size_t len)
183 {
184   priv_t             * p = (priv_t *)ft->priv;
185   snd_pcm_sframes_t  i, n;
186   size_t             done;
187 
188   len = min(len, p->buf_len);
189   for (done = 0; done < len; done += n) {
190     do {
191       n = snd_pcm_readi(p->pcm, p->buf, (len - done) / ft->signal.channels);
192       if (n < 0 && recover(ft, p->pcm, (int)n) < 0)
193         return 0;
194     } while (n <= 0);
195 
196     i = n *= ft->signal.channels;
197     switch (formats[p->format].alsa_fmt) {
198       case SND_PCM_FORMAT_S8: {
199         int8_t * buf1 = (int8_t *)p->buf;
200         while (i--) *buf++ = SOX_SIGNED_8BIT_TO_SAMPLE(*buf1++,);
201         break;
202       }
203       case SND_PCM_FORMAT_U8: {
204         uint8_t * buf1 = (uint8_t *)p->buf;
205         while (i--) *buf++ = SOX_UNSIGNED_8BIT_TO_SAMPLE(*buf1++,);
206         break;
207       }
208       case SND_PCM_FORMAT_S16: {
209         int16_t * buf1 = (int16_t *)p->buf;
210         if (ft->encoding.reverse_bytes) while (i--)
211           *buf++ = SOX_SIGNED_16BIT_TO_SAMPLE(lsx_swapw(*buf1++),);
212         else
213           while (i--) *buf++ = SOX_SIGNED_16BIT_TO_SAMPLE(*buf1++,);
214         break;
215       }
216       case SND_PCM_FORMAT_U16: {
217         uint16_t * buf1 = (uint16_t *)p->buf;
218         if (ft->encoding.reverse_bytes) while (i--)
219           *buf++ = SOX_UNSIGNED_16BIT_TO_SAMPLE(lsx_swapw(*buf1++),);
220         else
221           while (i--) *buf++ = SOX_UNSIGNED_16BIT_TO_SAMPLE(*buf1++,);
222         break;
223       }
224       case SND_PCM_FORMAT_S24: {
225         sox_int24_t * buf1 = (sox_int24_t *)p->buf;
226         while (i--) *buf++ = SOX_SIGNED_24BIT_TO_SAMPLE(*buf1++,);
227         break;
228       }
229       case SND_PCM_FORMAT_S24_3LE: {
230         unsigned char *buf1 = (unsigned char *)p->buf;
231         while (i--) {
232           uint32_t temp;
233           temp  = *buf1++;
234           temp |= *buf1++ << 8;
235           temp |= *buf1++ << 16;
236           *buf++ = SOX_SIGNED_24BIT_TO_SAMPLE((sox_int24_t)temp,);
237         }
238         break;
239       }
240       case SND_PCM_FORMAT_U24: {
241         sox_uint24_t * buf1 = (sox_uint24_t *)p->buf;
242         while (i--) *buf++ = SOX_UNSIGNED_24BIT_TO_SAMPLE(*buf1++,);
243         break;
244       }
245       case SND_PCM_FORMAT_S32: {
246         int32_t * buf1 = (int32_t *)p->buf;
247         while (i--) *buf++ = SOX_SIGNED_32BIT_TO_SAMPLE(*buf1++,);
248         break;
249       }
250       case SND_PCM_FORMAT_U32: {
251         uint32_t * buf1 = (uint32_t *)p->buf;
252         while (i--) *buf++ = SOX_UNSIGNED_32BIT_TO_SAMPLE(*buf1++,);
253         break;
254       }
255       default: lsx_fail_errno(ft, SOX_EFMT, "invalid format");
256         return 0;
257     }
258   }
259   return len;
260 }
261 
write_(sox_format_t * ft,sox_sample_t const * buf,size_t len)262 static size_t write_(sox_format_t * ft, sox_sample_t const * buf, size_t len)
263 {
264   priv_t             * p = (priv_t *)ft->priv;
265   size_t             done, i, n;
266   snd_pcm_sframes_t  actual;
267   SOX_SAMPLE_LOCALS;
268 
269   for (done = 0; done < len; done += n) {
270     i = n = min(len - done, p->buf_len);
271     switch (formats[p->format].alsa_fmt) {
272       case SND_PCM_FORMAT_S8: {
273         int8_t * buf1 = (int8_t *)p->buf;
274         while (i--) *buf1++ = SOX_SAMPLE_TO_SIGNED_8BIT(*buf++, ft->clips);
275         break;
276       }
277       case SND_PCM_FORMAT_U8: {
278         uint8_t * buf1 = (uint8_t *)p->buf;
279         while (i--) *buf1++ = SOX_SAMPLE_TO_UNSIGNED_8BIT(*buf++, ft->clips);
280         break;
281       }
282       case SND_PCM_FORMAT_S16: {
283         int16_t * buf1 = (int16_t *)p->buf;
284         if (ft->encoding.reverse_bytes) while (i--)
285           *buf1++ = lsx_swapw(SOX_SAMPLE_TO_SIGNED_16BIT(*buf++, ft->clips));
286         else
287           while (i--) *buf1++ = SOX_SAMPLE_TO_SIGNED_16BIT(*buf++, ft->clips);
288         break;
289       }
290       case SND_PCM_FORMAT_U16: {
291         uint16_t * buf1 = (uint16_t *)p->buf;
292         if (ft->encoding.reverse_bytes) while (i--)
293           *buf1++ = lsx_swapw(SOX_SAMPLE_TO_UNSIGNED_16BIT(*buf++, ft->clips));
294         else
295           while (i--) *buf1++ = SOX_SAMPLE_TO_UNSIGNED_16BIT(*buf++, ft->clips);
296         break;
297       }
298       case SND_PCM_FORMAT_S24: {
299         sox_int24_t * buf1 = (sox_int24_t *)p->buf;
300         while (i--) *buf1++ = SOX_SAMPLE_TO_SIGNED_24BIT(*buf++, ft->clips);
301         break;
302       }
303       case SND_PCM_FORMAT_S24_3LE: {
304         unsigned char *buf1 = (unsigned char *)p->buf;
305         while (i--) {
306           uint32_t temp = (uint32_t)SOX_SAMPLE_TO_SIGNED_24BIT(*buf++, ft->clips);
307           *buf1++ = (temp & 0x000000FF);
308           *buf1++ = (temp & 0x0000FF00) >> 8;
309           *buf1++ = (temp & 0x00FF0000) >> 16;
310         }
311         break;
312       }
313       case SND_PCM_FORMAT_U24: {
314         sox_uint24_t * buf1 = (sox_uint24_t *)p->buf;
315         while (i--) *buf1++ = SOX_SAMPLE_TO_UNSIGNED_24BIT(*buf++, ft->clips);
316         break;
317       }
318       case SND_PCM_FORMAT_S32: {
319         int32_t * buf1 = (int32_t *)p->buf;
320         while (i--) *buf1++ = SOX_SAMPLE_TO_SIGNED_32BIT(*buf++, ft->clips);
321         break;
322       }
323       case SND_PCM_FORMAT_U32: {
324         uint32_t * buf1 = (uint32_t *)p->buf;
325         while (i--) *buf1++ = SOX_SAMPLE_TO_UNSIGNED_32BIT(*buf++, ft->clips);
326         break;
327       }
328       default: lsx_fail_errno(ft, SOX_EFMT, "invalid format");
329         return 0;
330     }
331     for (i = 0; i < n; i += actual * ft->signal.channels) do {
332       actual = snd_pcm_writei(p->pcm,
333           p->buf + i * formats[p->format].bytes,
334           (n - i) / ft->signal.channels);
335       if (errno == EAGAIN)     /* Happens naturally; don't report it: */
336         errno = 0;
337       if (actual < 0 && recover(ft, p->pcm, (int)actual) < 0)
338         return 0;
339     } while (actual < 0);
340   }
341   return len;
342 }
343 
stop(sox_format_t * ft)344 static int stop(sox_format_t * ft)
345 {
346   priv_t * p = (priv_t *)ft->priv;
347   snd_pcm_close(p->pcm);
348   free(p->buf);
349   return SOX_SUCCESS;
350 }
351 
stop_write(sox_format_t * ft)352 static int stop_write(sox_format_t * ft)
353 {
354   priv_t * p = (priv_t *)ft->priv;
355   size_t n = ft->signal.channels * p->period, npad = n - (ft->olength % n);
356   sox_sample_t * buf = lsx_calloc(npad, sizeof(*buf)); /* silent samples */
357 
358   if (npad != n)                      /* pad to hardware period: */
359     write_(ft, buf, npad);
360   free(buf);
361   snd_pcm_drain(p->pcm);
362   return stop(ft);
363 }
364 
LSX_FORMAT_HANDLER(alsa)365 LSX_FORMAT_HANDLER(alsa)
366 {
367   static char const * const names[] = {"alsa", NULL};
368   static unsigned const write_encodings[] = {
369     SOX_ENCODING_SIGN2   , 32, 24, 16, 8, 0,
370     SOX_ENCODING_UNSIGNED, 32, 24, 16, 8, 0,
371     0};
372   static sox_format_handler_t const handler = {SOX_LIB_VERSION_CODE,
373     "Advanced Linux Sound Architecture device driver",
374     names, SOX_FILE_DEVICE | SOX_FILE_NOSTDIO,
375     setup, read_, stop, setup, write_, stop_write,
376     NULL, write_encodings, NULL, sizeof(priv_t)
377   };
378   return &handler;
379 }
380