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