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