NetBSD ships with <sys/endian.h> not <endian.h>
[ardour.git] / libs / backends / alsa / zita-alsa-pcmi.cc
1 // ----------------------------------------------------------------------------
2 //
3 //  Copyright (C) 2006-2012 Fons Adriaensen <fons@linuxaudio.org>
4 //
5 //  This program is free software; you can redistribute it and/or modify
6 //  it under the terms of the GNU General Public License as published by
7 //  the Free Software Foundation; either version 3 of the License, or
8 //  (at your option) any later version.
9 //
10 //  This program is distributed in the hope that it will be useful,
11 //  but WITHOUT ANY WARRANTY; without even the implied warranty of
12 //  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 //  GNU General Public License for more details.
14 //
15 //  You should have received a copy of the GNU General Public License
16 //  along with this program.  If not, see <http://www.gnu.org/licenses/>.
17 //
18 // ----------------------------------------------------------------------------
19
20 #if defined(__NetBSD__)
21 #include <sys/endian.h>
22 #else
23 #include <endian.h>
24 #endif
25 #include <sys/time.h>
26 #include "zita-alsa-pcmi.h"
27
28
29 // Public members ----------------------------------------------------------------------
30
31
32 int zita_alsa_pcmi_major_version (void)
33 {
34         return ZITA_ALSA_PCMI_MAJOR_VERSION;
35 }
36
37
38 int zita_alsa_pcmi_minor_version (void)
39 {
40         return ZITA_ALSA_PCMI_MINOR_VERSION;
41 }
42
43
44 Alsa_pcmi::Alsa_pcmi (
45                 const char        *play_name,
46                 const char        *capt_name,
47                 const char        *ctrl_name,
48                 unsigned int       fsamp,
49                 unsigned int       fsize,
50                 unsigned int       play_nfrag,
51                 unsigned int       capt_nfrag,
52                 unsigned int       debug)
53         : _fsamp (fsamp)
54         , _fsize (fsize)
55         , _play_nfrag (play_nfrag)
56         , _capt_nfrag (capt_nfrag)
57         , _debug (debug)
58         , _state (-1)
59         , _play_handle (0)
60         , _capt_handle (0)
61         , _ctrl_handle (0)
62         , _play_hwpar (0)
63         , _play_swpar (0)
64         , _capt_hwpar (0)
65         , _capt_swpar (0)
66         , _play_nchan (0)
67         , _capt_nchan (0)
68         , _play_xrun (0)
69         , _capt_xrun (0)
70         , _synced (false)
71         , _play_npfd (0)
72         , _capt_npfd (0)
73 {
74         const char *p;
75
76         p = getenv ("ZITA_ALSA_PCMI_DEBUG");
77         if (p && *p) _debug = atoi (p);
78         initialise (play_name, capt_name, ctrl_name);
79 }
80
81
82 Alsa_pcmi::~Alsa_pcmi (void)
83 {
84         if (_play_handle) snd_pcm_close (_play_handle);
85         if (_capt_handle) snd_pcm_close (_capt_handle);
86         if (_ctrl_handle) snd_ctl_close (_ctrl_handle);
87
88         snd_pcm_sw_params_free (_capt_swpar);
89         snd_pcm_hw_params_free (_capt_hwpar);
90         snd_pcm_sw_params_free (_play_swpar);
91         snd_pcm_hw_params_free (_play_hwpar);
92 }
93
94
95 int Alsa_pcmi::pcm_start (void)
96 {
97         unsigned int i, j, n;
98         int          err;
99
100         if (_play_handle)
101         {
102                 n = snd_pcm_avail_update (_play_handle);
103                 if (n != _fsize * _play_nfrag)
104                 {
105                         if (_debug & DEBUG_STAT) fprintf  (stderr, "Alsa_pcmi: full buffer not available at start.\n");
106                         return -1;
107                 }
108                 for (i = 0; i < _play_nfrag; i++)
109                 {
110                         play_init (_fsize);
111                         for (j = 0; j < _play_nchan; j++) clear_chan (j, _fsize);
112                         play_done (_fsize);
113                 }
114                 if ((err = snd_pcm_start (_play_handle)) < 0)
115                 {
116                         if (_debug & DEBUG_STAT) fprintf (stderr, "Alsa_pcmi: pcm_start(play): %s.\n", snd_strerror (err));
117                         return -1;
118                 }
119         }
120         if (_capt_handle && !_synced && ((err = snd_pcm_start (_capt_handle)) < 0))
121         {
122                 if (_debug & DEBUG_STAT) fprintf (stderr, "Alsa_pcmi: pcm_start(capt): %s.\n", snd_strerror (err));
123                 return -1;
124         }
125
126         return 0;
127 }
128
129
130 int Alsa_pcmi::pcm_stop (void)
131 {
132         int err;
133
134         if (_play_handle && ((err = snd_pcm_drop (_play_handle)) < 0))
135         {
136                 if (_debug & DEBUG_STAT) fprintf (stderr, "Alsa_pcmi: pcm_drop(play): %s.\n", snd_strerror (err));
137                 return -1;
138         }
139         if (_capt_handle && !_synced && ((err = snd_pcm_drop (_capt_handle)) < 0))
140         {
141                 if (_debug & DEBUG_STAT) fprintf (stderr, "Alsa_pcmi: pcm_drop(capt): %s.\n", snd_strerror (err));
142                 return -1;
143         }
144
145         return 0;
146 }
147
148
149 snd_pcm_sframes_t Alsa_pcmi::pcm_wait (void)
150 {
151         bool              need_capt;
152         bool              need_play;
153         snd_pcm_sframes_t capt_av;
154         snd_pcm_sframes_t play_av;
155         unsigned short    rev;
156         int               i, r, n1, n2;
157
158         _state = 0;
159         need_capt = _capt_handle ? true : false;
160         need_play = _play_handle ? true : false;
161
162         while (need_play || need_capt)
163         {
164                 n1 = 0;
165                 if (need_play)
166                 {
167                         snd_pcm_poll_descriptors (_play_handle, _poll_fd, _play_npfd);
168                         n1 += _play_npfd;
169                 }
170                 n2 = n1;
171                 if (need_capt)
172                 {
173                         snd_pcm_poll_descriptors (_capt_handle, _poll_fd + n1, _capt_npfd);
174                         n2 += _capt_npfd;
175                 }
176                 for (i = 0; i < n2; i++) _poll_fd [i].events |= POLLERR;
177
178                 timespec timeout;
179                 timeout.tv_sec = 1;
180                 timeout.tv_nsec = 0;
181                 r = ppoll (_poll_fd, n2, &timeout, NULL);
182
183                 if (r < 0)
184                 {
185                         if (errno == EINTR) return 0;
186                         if (_debug & DEBUG_WAIT) fprintf (stderr, "Alsa_pcmi: poll(): %s\n.", strerror (errno));
187                         _state = -1;
188                         return 0;
189                 }
190                 if (r == 0)
191                 {
192                         if (_debug & DEBUG_WAIT) fprintf (stderr, "Alsa_pcmi: poll timed out.\n");
193                         _state = -1;
194                         return 0;
195                 }
196
197                 if (need_play)
198                 {
199                         snd_pcm_poll_descriptors_revents (_play_handle, _poll_fd, n1, &rev);
200                         if (rev & POLLERR)
201                         {
202                                 if (_debug & DEBUG_WAIT) fprintf (stderr, "Alsa_pcmi: error on playback pollfd.\n");
203                                 _state = 1;
204                                 recover ();
205                                 return 0;
206                         }
207                         if (rev & POLLOUT) need_play = false;
208                 }
209                 if (need_capt)
210                 {
211                         snd_pcm_poll_descriptors_revents (_capt_handle, _poll_fd + n1, n2 - n1, &rev);
212                         if (rev & POLLERR)
213                         {
214                                 if (_debug & DEBUG_WAIT) fprintf (stderr, "Alsa_pcmi: error on capture pollfd.\n");
215                                 _state = 1;
216                                 recover ();
217                                 return 0;
218                         }
219                         if (rev & POLLIN) need_capt = false;
220                 }
221         }
222
223         play_av = 999999999;
224         if (_play_handle && (play_av = snd_pcm_avail_update (_play_handle)) < 0)
225         {
226                 _state = -1;
227                 recover ();
228                 return 0;
229         }
230         capt_av = 999999999;
231         if (_capt_handle && (capt_av = snd_pcm_avail_update (_capt_handle)) < 0)
232         {
233                 _state = -1;
234                 recover ();
235                 return 0;
236         }
237
238         return (capt_av < play_av) ? capt_av : play_av;
239 }
240
241
242 int Alsa_pcmi::pcm_idle (int len)
243 {
244         unsigned int       i;
245         snd_pcm_uframes_t  n, k;
246
247         if (_capt_handle)
248         {
249                 n = len;
250                 while (n)
251                 {
252                         k = capt_init (n);
253                         capt_done (k);
254                         n -= k;
255                 }
256         }
257         if (_play_handle)
258         {
259                 n = len;
260                 while (n)
261                 {
262                         k = play_init (n);
263                         for (i = 0; i < _play_nchan; i++) clear_chan (i, k);
264                         play_done (k);
265                         n -= k;
266                 }
267         }
268         return 0;
269 }
270
271
272 int Alsa_pcmi::play_init (snd_pcm_uframes_t len)
273 {
274         unsigned int                   i;
275         const snd_pcm_channel_area_t   *a;
276         int                            err;
277
278         if (!_play_handle) {
279                 return 0;
280         }
281         if ((err = snd_pcm_mmap_begin (_play_handle, &a, &_play_offs, &len)) < 0)
282         {
283                 if (_debug & DEBUG_DATA) fprintf (stderr, "Alsa_pcmi: snd_pcm_mmap_begin(play): %s.\n", snd_strerror (err));
284                 return -1;
285         }
286         _play_step = (a->step) >> 3;
287         for (i = 0; i < _play_nchan; i++, a++)
288         {
289                 _play_ptr [i] = (char *) a->addr + ((a->first + a->step * _play_offs) >> 3);
290         }
291
292         return len;
293 }
294
295
296 int Alsa_pcmi::capt_init (snd_pcm_uframes_t len)
297 {
298         unsigned int                  i;
299         const snd_pcm_channel_area_t  *a;
300         int                           err;
301
302         if (!_capt_handle) {
303                 return 0;
304         }
305
306         if ((err = snd_pcm_mmap_begin (_capt_handle, &a, &_capt_offs, &len)) < 0)
307         {
308                 if (_debug & DEBUG_DATA) fprintf (stderr, "Alsa_pcmi: snd_pcm_mmap_begin(capt): %s.\n", snd_strerror (err));
309                 return -1;
310         }
311         _capt_step = (a->step) >> 3;
312         for (i = 0; i < _capt_nchan; i++, a++)
313         {
314                 _capt_ptr [i] = (char *) a->addr + ((a->first + a->step * _capt_offs) >> 3);
315         }
316
317         return len;
318 }
319
320
321 void Alsa_pcmi::clear_chan (int chan, int len)
322 {
323         _play_ptr [chan] = (this->*Alsa_pcmi::_clear_func)(_play_ptr [chan], len);
324 }
325
326
327 void Alsa_pcmi::play_chan (int chan, const float *src, int len, int step)
328 {
329         _play_ptr [chan] = (this->*Alsa_pcmi::_play_func)(src, _play_ptr [chan], len, step);
330 }
331
332
333 void Alsa_pcmi::capt_chan  (int chan, float *dst, int len, int step)
334 {
335         _capt_ptr [chan] = (this->*Alsa_pcmi::_capt_func)(_capt_ptr [chan], dst, len, step);
336 }
337
338
339 int Alsa_pcmi::play_done (int len)
340 {
341         if (!_play_handle) return 0;
342         return snd_pcm_mmap_commit (_play_handle, _play_offs, len);
343 }
344
345
346 int Alsa_pcmi::capt_done (int len)
347 {
348         if (!_capt_handle) return 0;
349         return snd_pcm_mmap_commit (_capt_handle, _capt_offs, len);
350 }
351
352
353 void Alsa_pcmi::printinfo (void)
354 {
355         fprintf (stdout, "playback :");
356         if (_play_handle)
357         {
358                 fprintf (stdout, "\n  nchan  : %d\n", _play_nchan);
359                 fprintf (stdout, "  fsamp  : %d\n", _fsamp);
360                 fprintf (stdout, "  fsize  : %ld\n", _fsize);
361                 fprintf (stdout, "  nfrag  : %d\n", _play_nfrag);
362                 fprintf (stdout, "  format : %s\n", snd_pcm_format_name (_play_format));
363         }
364         else fprintf (stdout, " not enabled\n");
365         fprintf (stdout, "capture  :");
366         if (_capt_handle)
367         {
368                 fprintf (stdout, "\n  nchan  : %d\n", _capt_nchan);
369                 fprintf (stdout, "  fsamp  : %d\n", _fsamp);
370                 fprintf (stdout, "  fsize  : %ld\n", _fsize);
371                 fprintf (stdout, "  nfrag  : %d\n", _capt_nfrag);
372                 fprintf (stdout, "  format : %s\n", snd_pcm_format_name (_capt_format));
373                 if (_play_handle) fprintf (stdout, "%s\n", _synced ? "synced" : "not synced");
374         }
375         else fprintf (stdout, " not enabled\n");
376 }
377
378
379 // Private members ---------------------------------------------------------------------
380
381
382 void Alsa_pcmi::initialise (const char *play_name, const char *capt_name, const char *ctrl_name)
383 {
384         unsigned int          fsamp;
385         snd_pcm_uframes_t     fsize;
386         unsigned int          nfrag;
387         int                   err;
388         int                   dir;
389         snd_ctl_card_info_t  *card;
390
391         if (play_name)
392         {
393                 if (snd_pcm_open (&_play_handle, play_name, SND_PCM_STREAM_PLAYBACK, 0) < 0)
394                 {
395                         _play_handle = 0;
396                         if (_debug & DEBUG_INIT) fprintf (stderr, "Alsa_pcmi: Cannot open PCM device %s for playback.\n",
397                                         play_name);
398                 }
399         }
400
401         if (capt_name)
402         {
403                 if (snd_pcm_open (&_capt_handle, capt_name, SND_PCM_STREAM_CAPTURE, 0) < 0)
404                 {
405                         _capt_handle = 0;
406                         if (_debug & DEBUG_INIT) fprintf (stderr, "Alsa_pcmi: Cannot open PCM device %s for capture.\n",
407                                         capt_name);
408                 }
409         }
410
411         if (! _play_handle && ! _capt_handle) return;
412
413         if (ctrl_name)
414         {
415                 snd_ctl_card_info_alloca (&card);
416
417                 if ((err = snd_ctl_open (&_ctrl_handle, ctrl_name, 0)) < 0)
418                 {
419                         if (_debug & DEBUG_INIT) fprintf  (stderr, "Alse_driver: ctl_open(): %s\n",
420                                         snd_strerror (err));
421                         return;
422                 }
423                 if ((err = snd_ctl_card_info (_ctrl_handle, card)) < 0)
424                 {
425                         if (_debug & DEBUG_INIT) fprintf  (stderr, "Alsa_pcmi: ctl_card_info(): %s\n",
426                                         snd_strerror (err));
427                         return;
428                 }
429         }
430
431         _state = -2;
432         if (_play_handle)
433         {
434                 if (snd_pcm_hw_params_malloc (&_play_hwpar) < 0)
435                 {
436                         if (_debug & DEBUG_INIT) fprintf (stderr, "Alsa_pcmi: can't allocate playback hw params\n");
437                         return;
438                 }
439                 if (snd_pcm_sw_params_malloc (&_play_swpar) < 0)
440                 {
441                         if (_debug & DEBUG_INIT) fprintf (stderr, "Alsa_pcmi: can't allocate playback sw params\n");
442                         return;
443                 }
444                 if (set_hwpar (_play_handle, _play_hwpar, "playback", _play_nfrag, &_play_nchan) < 0) return;
445                 if (set_swpar (_play_handle, _play_swpar, "playback") < 0) return;
446         }
447
448         if (_capt_handle)
449         {
450                 if (snd_pcm_hw_params_malloc (&_capt_hwpar) < 0)
451                 {
452                         if (_debug & DEBUG_INIT) fprintf (stderr, "Alsa_pcmi: can't allocate capture hw params\n");
453                         return;
454                 }
455                 if (snd_pcm_sw_params_malloc (&_capt_swpar) < 0)
456                 {
457                         if (_debug & DEBUG_INIT) fprintf (stderr, "Alsa_pcmi: can't allocate capture sw params\n");
458                         return;
459                 }
460                 if (set_hwpar (_capt_handle, _capt_hwpar, "capture", _capt_nfrag, &_capt_nchan) < 0) return;
461                 if (set_swpar (_capt_handle, _capt_swpar, "capture") < 0) return;
462         }
463
464         if (_play_handle)
465         {
466                 if (snd_pcm_hw_params_get_rate (_play_hwpar, &fsamp, &dir) || (fsamp != _fsamp) || dir)
467                 {
468                         if (_debug & DEBUG_INIT) fprintf (stderr, "Alsa_pcmi: can't get requested sample rate for playback.\n");
469                         _state = -3;
470                         return;
471                 }
472                 if (snd_pcm_hw_params_get_period_size (_play_hwpar, &fsize, &dir) || (fsize != _fsize) || dir)
473                 {
474                         if (_debug & DEBUG_INIT) fprintf (stderr, "Alsa_pcmi: can't get requested period size for playback.\n");
475                         _state = -4;
476                         return;
477                 }
478                 if (snd_pcm_hw_params_get_periods (_play_hwpar, &nfrag, &dir) || (nfrag != _play_nfrag) || dir)
479                 {
480                         if (_debug & DEBUG_INIT) fprintf (stderr, "Alsa_pcmi: can't get requested number of periods for playback.\n");
481                         _state = -5;
482                         return;
483                 }
484
485                 snd_pcm_hw_params_get_format (_play_hwpar, &_play_format);
486                 snd_pcm_hw_params_get_access (_play_hwpar, &_play_access);
487
488 #if __BYTE_ORDER == __LITTLE_ENDIAN
489                 switch (_play_format)
490                 {
491                         case SND_PCM_FORMAT_FLOAT_LE:
492                                 _clear_func = &Alsa_pcmi::clear_32;
493                                 _play_func  = &Alsa_pcmi::play_float;
494                                 break;
495
496                         case SND_PCM_FORMAT_S32_LE:
497                                 _clear_func = &Alsa_pcmi::clear_32;
498                                 _play_func  = &Alsa_pcmi::play_32;
499                                 break;
500
501                         case SND_PCM_FORMAT_S32_BE:
502                                 _clear_func = &Alsa_pcmi::clear_32;
503                                 _play_func  = &Alsa_pcmi::play_32swap;
504                                 break;
505
506                         case SND_PCM_FORMAT_S24_3LE:
507                                 _clear_func = &Alsa_pcmi::clear_24;
508                                 _play_func  = &Alsa_pcmi::play_24;
509                                 break;
510
511                         case SND_PCM_FORMAT_S24_3BE:
512                                 _clear_func = &Alsa_pcmi::clear_24;
513                                 _play_func  = &Alsa_pcmi::play_24swap;
514                                 break;
515
516                         case SND_PCM_FORMAT_S16_LE:
517                                 _clear_func = &Alsa_pcmi::clear_16;
518                                 _play_func  = &Alsa_pcmi::play_16;
519                                 break;
520
521                         case SND_PCM_FORMAT_S16_BE:
522                                 _clear_func = &Alsa_pcmi::clear_16;
523                                 _play_func  = &Alsa_pcmi::play_16swap;
524                                 break;
525
526                         default:
527                                 if (_debug & DEBUG_INIT) fprintf (stderr, "Alsa_pcmi: can't handle playback sample format.\n");
528                                 _state = -6;
529                                 return;
530                 }
531 #elif __BYTE_ORDER == __BIG_ENDIAN
532                 switch (_play_format)
533                 {
534                         case SND_PCM_FORMAT_S32_LE:
535                                 _clear_func = &Alsa_pcmi::clear_32;
536                                 _play_func  = &Alsa_pcmi::play_32swap;
537                                 break;
538
539                         case SND_PCM_FORMAT_S32_BE:
540                                 _clear_func = &Alsa_pcmi::clear_32;
541                                 _play_func  = &Alsa_pcmi::play_32;
542                                 break;
543
544                         case SND_PCM_FORMAT_S24_3LE:
545                                 _clear_func = &Alsa_pcmi::clear_24;
546                                 _play_func  = &Alsa_pcmi::play_24swap;
547                                 break;
548
549                         case SND_PCM_FORMAT_S24_3BE:
550                                 _clear_func = &Alsa_pcmi::clear_24;
551                                 _play_func  = &Alsa_pcmi::play_24;
552                                 break;
553
554                         case SND_PCM_FORMAT_S16_LE:
555                                 _clear_func = &Alsa_pcmi::clear_16;
556                                 _play_func  = &Alsa_pcmi::play_16swap;
557                                 break;
558
559                         case SND_PCM_FORMAT_S16_BE:
560                                 _clear_func = &Alsa_pcmi::clear_16;
561                                 _play_func  = &Alsa_pcmi::play_16;
562                                 break;
563
564                         default:
565                                 if (_debug & DEBUG_INIT) fprintf (stderr, "Alsa_pcmi: can't handle playback sample format.\n");
566                                 _state = -6;
567                                 return;
568                 }
569 #else
570 #error "System byte order is undefined or not supported"
571 #endif
572
573                 _play_npfd = snd_pcm_poll_descriptors_count (_play_handle);
574         }
575
576         if (_capt_handle)
577         {
578                 if (snd_pcm_hw_params_get_rate (_capt_hwpar, &fsamp, &dir) || (fsamp != _fsamp) || dir)
579                 {
580                         if (_debug & DEBUG_INIT) fprintf (stderr, "Alsa_pcmi: can't get requested sample rate for capture.\n");
581                         _state = -3;
582                         return;
583                 }
584                 if (snd_pcm_hw_params_get_period_size (_capt_hwpar, &fsize, &dir) || (fsize != _fsize) || dir)
585                 {
586                         if (_debug & DEBUG_INIT) fprintf (stderr, "Alsa_pcmi: can't get requested period size for capture.\n");
587                         _state = -4;
588                         return;
589                 }
590                 if (snd_pcm_hw_params_get_periods (_capt_hwpar, &nfrag, &dir) || (nfrag != _capt_nfrag) || dir)
591                 {
592                         if (_debug & DEBUG_INIT) fprintf (stderr, "Alsa_pcmi: can't get requested number of periods for capture.\n");
593                         _state = -5;
594                         return;
595                 }
596
597                 if (_play_handle) _synced = ! snd_pcm_link (_play_handle, _capt_handle);
598
599                 snd_pcm_hw_params_get_format (_capt_hwpar, &_capt_format);
600                 snd_pcm_hw_params_get_access (_capt_hwpar, &_capt_access);
601
602 #if __BYTE_ORDER == __LITTLE_ENDIAN
603                 switch (_capt_format)
604                 {
605                         case SND_PCM_FORMAT_FLOAT_LE:
606                                 _capt_func  = &Alsa_pcmi::capt_float;
607                                 break;
608
609                         case SND_PCM_FORMAT_S32_LE:
610                                 _capt_func  = &Alsa_pcmi::capt_32;
611                                 break;
612
613                         case SND_PCM_FORMAT_S32_BE:
614                                 _capt_func  = &Alsa_pcmi::capt_32swap;
615                                 break;
616
617                         case SND_PCM_FORMAT_S24_3LE:
618                                 _capt_func  = &Alsa_pcmi::capt_24;
619                                 break;
620
621                         case SND_PCM_FORMAT_S24_3BE:
622                                 _capt_func  = &Alsa_pcmi::capt_24swap;
623                                 break;
624
625                         case SND_PCM_FORMAT_S16_LE:
626                                 _capt_func  = &Alsa_pcmi::capt_16;
627                                 break;
628
629                         case SND_PCM_FORMAT_S16_BE:
630                                 _capt_func  = &Alsa_pcmi::capt_16swap;
631                                 break;
632
633                         default:
634                                 if (_debug & DEBUG_INIT) fprintf (stderr, "Alsa_pcmi: can't handle capture sample format.\n");
635                                 _state = -6;
636                                 return;
637                 }
638 #elif __BYTE_ORDER == __BIG_ENDIAN
639                 switch (_capt_format)
640                 {
641                         case SND_PCM_FORMAT_S32_LE:
642                                 _capt_func  = &Alsa_pcmi::capt_32swap;
643                                 break;
644
645                         case SND_PCM_FORMAT_S32_BE:
646                                 _capt_func  = &Alsa_pcmi::capt_32;
647                                 break;
648
649                         case SND_PCM_FORMAT_S24_3LE:
650                                 _capt_func  = &Alsa_pcmi::capt_24swap;
651                                 break;
652
653                         case SND_PCM_FORMAT_S24_3BE:
654                                 _capt_func  = &Alsa_pcmi::capt_24;
655                                 break;
656
657                         case SND_PCM_FORMAT_S16_LE:
658                                 _capt_func  = &Alsa_pcmi::capt_16swap;
659                                 break;
660
661                         case SND_PCM_FORMAT_S16_BE:
662                                 _capt_func  = &Alsa_pcmi::capt_16;
663                                 break;
664
665                         default:
666                                 if (_debug & DEBUG_INIT) fprintf (stderr, "Alsa_pcmi: can't handle capture sample format.\n");
667                                 _state = -6;
668                                 return;
669                 }
670 #else
671 #error "System byte order is undefined or not supported"
672 #endif
673
674                 _capt_npfd = snd_pcm_poll_descriptors_count (_capt_handle);
675         }
676
677         if (_play_npfd + _capt_npfd > MAXPFD)
678         {
679                 if (_debug & DEBUG_INIT) fprintf (stderr, "Alsa_pcmi: interface requires more than %d pollfd\n", MAXPFD);
680                 return;
681         }
682
683         _state = 0;
684 }
685
686
687 int Alsa_pcmi::set_hwpar (snd_pcm_t *handle,  snd_pcm_hw_params_t *hwpar, const char *sname, unsigned int nfrag, unsigned int *nchan)
688 {
689         bool err;
690
691         if (snd_pcm_hw_params_any (handle, hwpar) < 0)
692         {
693                 if (_debug & DEBUG_INIT) fprintf (stderr, "Alsa_pcmi: no %s hw configurations available.\n",
694                                 sname);
695                 return -1;
696         }
697         if (snd_pcm_hw_params_set_periods_integer (handle, hwpar) < 0)
698         {
699                 if (_debug & DEBUG_INIT) fprintf (stderr, "Alsa_pcmi: can't set %s period size to integral value.\n",
700                                 sname);
701                 return -1;
702         }
703         if (   (snd_pcm_hw_params_set_access (handle, hwpar, SND_PCM_ACCESS_MMAP_NONINTERLEAVED) < 0)
704                         && (snd_pcm_hw_params_set_access (handle, hwpar, SND_PCM_ACCESS_MMAP_INTERLEAVED) < 0)
705                         && (snd_pcm_hw_params_set_access (handle, hwpar, SND_PCM_ACCESS_MMAP_COMPLEX) < 0))
706         {
707                 if (_debug & DEBUG_INIT) fprintf (stderr, "Alsa_pcmi: the %s interface doesn't support mmap-based access.\n",
708                                 sname);
709                 return -1;
710         }
711         if (_debug & FORCE_16B)
712         {
713                 err =    (snd_pcm_hw_params_set_format (handle, hwpar, SND_PCM_FORMAT_S16_LE) < 0)
714                         && (snd_pcm_hw_params_set_format (handle, hwpar, SND_PCM_FORMAT_S16_BE) < 0);
715         }
716         else
717         {
718                 err =    (snd_pcm_hw_params_set_format (handle, hwpar, SND_PCM_FORMAT_FLOAT_LE) < 0)
719                         && (snd_pcm_hw_params_set_format (handle, hwpar, SND_PCM_FORMAT_S32_LE) < 0)
720                         && (snd_pcm_hw_params_set_format (handle, hwpar, SND_PCM_FORMAT_S32_BE) < 0)
721                         && (snd_pcm_hw_params_set_format (handle, hwpar, SND_PCM_FORMAT_S24_3LE) < 0)
722                         && (snd_pcm_hw_params_set_format (handle, hwpar, SND_PCM_FORMAT_S24_3BE) < 0)
723                         && (snd_pcm_hw_params_set_format (handle, hwpar, SND_PCM_FORMAT_S16_LE) < 0)
724                         && (snd_pcm_hw_params_set_format (handle, hwpar, SND_PCM_FORMAT_S16_BE) < 0);
725         }
726         if (err)
727         {
728                 if (_debug & DEBUG_INIT) fprintf (stderr, "Alsa_pcmi: no supported sample format on %s interface.\n.",
729                                 sname);
730                 return -1;
731         }
732         if (snd_pcm_hw_params_set_rate (handle, hwpar, _fsamp, 0) < 0)
733         {
734                 if (_debug & DEBUG_INIT) fprintf (stderr, "Alsa_pcmi: can't set %s sample rate to %u.\n",
735                                 sname, _fsamp);
736                 return -3;
737         }
738         snd_pcm_hw_params_get_channels_max (hwpar, nchan);
739         if (*nchan > 1024)
740         {
741                 if (_debug & DEBUG_INIT) fprintf (stderr, "Alsa_pcmi: detected more than 1024 %s channnels, reset to 2.\n",
742                                 sname);
743                 *nchan = 2;
744         }
745         if (_debug & FORCE_2CH)
746         {
747                 *nchan = 2;
748         }
749         if (*nchan > MAXCHAN)
750         {
751                 if (_debug & DEBUG_INIT) fprintf (stderr, "Alsa_pcmi: number of %s channels reduced to %d.\n",
752                                 sname, MAXCHAN);
753                 *nchan = MAXCHAN;
754         }
755
756         if (snd_pcm_hw_params_set_channels (handle, hwpar, *nchan) < 0)
757         {
758                 if (_debug & DEBUG_INIT) fprintf (stderr, "Alsa_pcmi: can't set %s channel count to %u.\n",
759                                 sname, *nchan);
760                 return -1;
761         }
762         if (snd_pcm_hw_params_set_period_size (handle, hwpar, _fsize, 0) < 0)
763         {
764                 if (_debug & DEBUG_INIT) fprintf (stderr, "Alsa_pcmi: can't set %s period size to %lu.\n",
765                                 sname, _fsize);
766                 return -4;
767         }
768         if (snd_pcm_hw_params_set_periods (handle, hwpar, nfrag, 0) < 0)
769         {
770                 if (_debug & DEBUG_INIT) fprintf (stderr, "Alsa_pcmi: can't set %s periods to %u.\n",
771                                 sname, nfrag);
772                 return -5;
773         }
774         if (snd_pcm_hw_params_set_buffer_size (handle, hwpar, _fsize * nfrag) < 0)
775         {
776                 if (_debug & DEBUG_INIT) fprintf (stderr, "Alsa_pcmi: can't set %s buffer length to %lu.\n",
777                                 sname, _fsize * nfrag);
778                 return -4;
779         }
780         if (snd_pcm_hw_params (handle, hwpar) < 0)
781         {
782                 if (_debug & DEBUG_INIT) fprintf (stderr, "Alsa_pcmi: can't set %s hardware parameters.\n",
783                                 sname);
784                 return -1;
785         }
786
787         return 0;
788 }
789
790
791 int Alsa_pcmi::set_swpar (snd_pcm_t *handle, snd_pcm_sw_params_t *swpar, const char *sname)
792 {
793         int err;
794
795         snd_pcm_sw_params_current (handle, swpar);
796
797         if ((err = snd_pcm_sw_params_set_tstamp_mode (handle, swpar, SND_PCM_TSTAMP_MMAP)) < 0)
798         {
799                 if (_debug & DEBUG_INIT) fprintf (stderr, "Alsa_pcmi: can't set %s timestamp mode to %u.\n",
800                                 sname, SND_PCM_TSTAMP_MMAP);
801                 return -1;
802         }
803         if ((err = snd_pcm_sw_params_set_avail_min (handle, swpar, _fsize)) < 0)
804         {
805                 if (_debug & DEBUG_INIT) fprintf (stderr, "Alsa_pcmi: can't set %s avail_min to %lu.\n",
806                                 sname, _fsize);
807                 return -1;
808         }
809         if ((err = snd_pcm_sw_params (handle, swpar)) < 0)
810         {
811                 if (_debug & DEBUG_INIT) fprintf (stderr, "Alsa_pcmi: can't set %s software parameters.\n",
812                                 sname);
813                 return -1;
814         }
815
816         return 0;
817 }
818
819
820 int Alsa_pcmi::recover (void)
821 {
822         int                err;
823         snd_pcm_status_t   *stat;
824
825         snd_pcm_status_alloca (&stat);
826
827         if (_play_handle)
828         {
829                 if ((err = snd_pcm_status (_play_handle, stat)) < 0)
830                 {
831                         if (_debug & DEBUG_STAT) fprintf (stderr, "Alsa_pcmi: pcm_status(play): %s\n",
832                                         snd_strerror (err));
833                 }
834                 _play_xrun = xruncheck (stat);
835         }
836         if (_capt_handle)
837         {
838                 if ((err = snd_pcm_status (_capt_handle, stat)) < 0)
839                 {
840                         if (_debug & DEBUG_STAT) fprintf (stderr, "Alsa_pcmi: pcm_status(capt): %s\n",
841                                         snd_strerror (err));
842                 }
843                 _capt_xrun = xruncheck (stat);
844         }
845
846         if (pcm_stop ()) return -1;
847         if (_play_handle && ((err = snd_pcm_prepare (_play_handle)) < 0))
848         {
849                 if (_debug & DEBUG_STAT) fprintf (stderr, "Alsa_pcmi: pcm_prepare(play): %s\n",
850                                 snd_strerror (err));
851                 return -1;
852         }
853         if (_capt_handle && !_synced && ((err = snd_pcm_prepare (_capt_handle)) < 0))
854         {
855                 if (_debug & DEBUG_INIT) fprintf (stderr, "Alsa_pcmi: pcm_prepare(capt): %s\n",
856                                 snd_strerror (err));
857                 return -1;
858         }
859         if (pcm_start ()) return -1;
860
861         return 0;
862 }
863
864
865 float Alsa_pcmi::xruncheck (snd_pcm_status_t *stat)
866 {
867         struct timeval   tupd, trig;
868         int              ds, du;
869
870         if (snd_pcm_status_get_state (stat) == SND_PCM_STATE_XRUN)
871         {
872                 snd_pcm_status_get_tstamp (stat, &tupd);
873                 snd_pcm_status_get_trigger_tstamp (stat, &trig);
874                 ds = tupd.tv_sec - trig.tv_sec;
875                 du = tupd.tv_usec - trig.tv_usec;
876                 if (du < 0)
877                 {
878                         du += 1000000;
879                         ds -= 1;
880                 }
881                 return ds + 1e-6f * du;
882         }
883         return 0.0f;
884 }
885
886
887 char *Alsa_pcmi::clear_16 (char *dst, int nfrm)
888 {
889         while (nfrm--)
890         {
891                 *((short int *) dst) = 0;
892                 dst += _play_step;
893         }
894         return dst;
895 }
896
897 char *Alsa_pcmi::clear_24 (char *dst, int nfrm)
898 {
899         while (nfrm--)
900         {
901                 dst [0] = 0;
902                 dst [1] = 0;
903                 dst [2] = 0;
904                 dst += _play_step;
905         }
906         return dst;
907 }
908
909 char *Alsa_pcmi::clear_32 (char *dst, int nfrm)
910 {
911         while (nfrm--)
912         {
913                 *((int *) dst) = 0;
914                 dst += _play_step;
915         }
916         return dst;
917 }
918
919
920 char *Alsa_pcmi::play_16 (const float *src, char *dst, int nfrm, int step)
921 {
922         float     s;
923         short int d;
924
925         while (nfrm--)
926         {
927                 s = *src;
928                 if      (s >  1) d = 0x7fff;
929                 else if (s < -1) d = 0x8001;
930                 else d = (short int)((float) 0x7fff * s);
931                 *((short int *) dst) = d;
932                 dst += _play_step;
933                 src += step;
934         }
935         return dst;
936 }
937
938 char *Alsa_pcmi::play_16swap (const float *src, char *dst, int nfrm, int step)
939 {
940         float     s;
941         short int d;
942
943         while (nfrm--)
944         {
945                 s = *src;
946                 if      (s >  1) d = 0x7fff;
947                 else if (s < -1) d = 0x8001;
948                 else d = (short int)((float) 0x7fff * s);
949                 dst [0] = d >> 8;
950                 dst [1] = d;
951                 dst += _play_step;
952                 src += step;
953         }
954         return dst;
955 }
956
957 char *Alsa_pcmi::play_24 (const float *src, char *dst, int nfrm, int step)
958 {
959         float   s;
960         int     d;
961
962         while (nfrm--)
963         {
964                 s = *src;
965                 if      (s >  1) d = 0x007fffff;
966                 else if (s < -1) d = 0x00800001;
967                 else d = (int)((float) 0x007fffff * s);
968                 dst [0] = d;
969                 dst [1] = d >> 8;
970                 dst [2] = d >> 16;
971                 dst += _play_step;
972                 src += step;
973         }
974         return dst;
975 }
976
977 char *Alsa_pcmi::play_24swap (const float *src, char *dst, int nfrm, int step)
978 {
979         float   s;
980         int     d;
981
982         while (nfrm--)
983         {
984                 s = *src;
985                 if      (s >  1) d = 0x007fffff;
986                 else if (s < -1) d = 0x00800001;
987                 else d = (int)((float) 0x007fffff * s);
988                 dst [0] = d >> 16;
989                 dst [1] = d >> 8;
990                 dst [2] = d;
991                 dst += _play_step;
992                 src += step;
993         }
994         return dst;
995 }
996
997 char *Alsa_pcmi::play_32 (const float *src, char *dst, int nfrm, int step)
998 {
999         float   s;
1000         int     d;
1001
1002         while (nfrm--)
1003         {
1004                 s = *src;
1005                 if      (s >  1) d = 0x007fffff;
1006                 else if (s < -1) d = 0x00800001;
1007                 else d = (int)((float) 0x007fffff * s);
1008                 *((int *) dst) = d << 8;
1009                 dst += _play_step;
1010                 src += step;
1011         }
1012         return dst;
1013 }
1014
1015 char *Alsa_pcmi::play_32swap (const float *src, char *dst, int nfrm, int step)
1016 {
1017         float   s;
1018         int     d;
1019
1020         while (nfrm--)
1021         {
1022                 s = *src;
1023                 if      (s >  1) d = 0x007fffff;
1024                 else if (s < -1) d = 0x00800001;
1025                 else d = (int)((float) 0x007fffff * s);
1026                 dst [0] = d >> 16;
1027                 dst [1] = d >> 8;
1028                 dst [2] = d;
1029                 dst [3] = 0;
1030                 dst += _play_step;
1031                 src += step;
1032         }
1033         return dst;
1034 }
1035
1036 char *Alsa_pcmi::play_float (const float *src, char *dst, int nfrm, int step)
1037 {
1038         while (nfrm--)
1039         {
1040                 *((float *) dst) = *src;
1041                 dst += _play_step;
1042                 src += step;
1043         }
1044         return dst;
1045 }
1046
1047
1048 const char *Alsa_pcmi::capt_16 (const char *src, float *dst, int nfrm, int step)
1049 {
1050         while (nfrm--)
1051         {
1052                 const short int s = *((short int const *) src);
1053                 const float d = (float) s / (float) 0x7fff;
1054                 *dst = d;
1055                 dst += step;
1056                 src += _capt_step;
1057         }
1058         return src;
1059 }
1060
1061 const char *Alsa_pcmi::capt_16swap (const char *src, float *dst, int nfrm, int step)
1062 {
1063         float     d;
1064         short int s;
1065
1066         while (nfrm--)
1067         {
1068                 s =  (src [0] & 0xFF) << 8;
1069                 s += (src [1] & 0xFF);
1070                 d = (float) s / (float) 0x7fff;
1071                 *dst = d;
1072                 dst += step;
1073                 src += _capt_step;
1074         }
1075         return src;
1076 }
1077
1078 const char *Alsa_pcmi::capt_24 (const char *src, float *dst, int nfrm, int step)
1079 {
1080         float   d;
1081         int     s;
1082
1083         while (nfrm--)
1084         {
1085                 s  = (src [0] & 0xFF);
1086                 s += (src [1] & 0xFF) << 8;
1087                 s += (src [2] & 0xFF) << 16;
1088                 if (s & 0x00800000) s-= 0x01000000;
1089                 d = (float) s / (float) 0x007fffff;
1090                 *dst = d;
1091                 dst += step;
1092                 src += _capt_step;
1093         }
1094         return src;
1095 }
1096
1097 const char *Alsa_pcmi::capt_24swap (const char *src, float *dst, int nfrm, int step)
1098 {
1099         float   d;
1100         int     s;
1101
1102         while (nfrm--)
1103         {
1104                 s  = (src [0] & 0xFF) << 16;
1105                 s += (src [1] & 0xFF) << 8;
1106                 s += (src [2] & 0xFF);
1107                 if (s & 0x00800000) s-= 0x01000000;
1108                 d = (float) s / (float) 0x007fffff;
1109                 *dst = d;
1110                 dst += step;
1111                 src += _capt_step;
1112         }
1113         return src;
1114 }
1115
1116 const char *Alsa_pcmi::capt_32 (const char *src, float *dst, int nfrm, int step)
1117 {
1118         while (nfrm--)
1119         {
1120                 const int s = *((int const *) src);
1121                 const float d = (float) s / (float) 0x7fffff00;
1122                 *dst = d;
1123                 dst += step;
1124                 src += _capt_step;
1125         }
1126         return src;
1127 }
1128
1129 const char *Alsa_pcmi::capt_32swap (const char *src, float *dst, int nfrm, int step)
1130 {
1131         float   d;
1132         int     s;
1133
1134         while (nfrm--)
1135         {
1136                 s  = (src [0] & 0xFF) << 24;
1137                 s += (src [1] & 0xFF) << 16;
1138                 s += (src [2] & 0xFF) << 8;
1139                 d = (float) s / (float) 0x7fffff00;
1140                 *dst = d;
1141                 dst += step;
1142                 src += _capt_step;
1143         }
1144         return src;
1145 }
1146
1147 const char *Alsa_pcmi::capt_float (const char *src, float *dst, int nfrm, int step)
1148 {
1149         while (nfrm--)
1150         {
1151                 *dst = *((float const *) src);
1152                 dst += step;
1153                 src += _capt_step;
1154         }
1155         return src;
1156 }