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