2
Copyright (C) 2003-2006 Fons Adriaensen <fons.adriaensen@skynet.be>
4
This program is free software; you can redistribute it and/or modify
5
it under the terms of the GNU General Public License as published by
6
the Free Software Foundation; either version 2 of the License, or
7
(at your option) any later version.
9
This program is distributed in the hope that it will be useful,
10
but WITHOUT ANY WARRANTY; without even the implied warranty of
11
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12
GNU General Public License for more details.
14
You should have received a copy of the GNU General Public License
15
along with this program; if not, write to the Free Software
16
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21
#include "clalsadrv.h"
24
// Public members ----------------------------------------------------------------------
27
Alsa_driver::~Alsa_driver (void)
29
snd_pcm_sw_params_free (_capt_swpar);
30
snd_pcm_hw_params_free (_capt_hwpar);
31
snd_pcm_sw_params_free (_play_swpar);
32
snd_pcm_hw_params_free (_play_hwpar);
34
if (_play_handle) snd_pcm_close (_play_handle);
35
if (_capt_handle) snd_pcm_close (_capt_handle);
36
if (_ctrl_handle) snd_ctl_close (_ctrl_handle);
40
Alsa_driver::Alsa_driver (const char *name,
42
snd_pcm_uframes_t frsize,
65
snd_ctl_card_info_t *card;
69
if (snd_pcm_open (&_play_handle, name, SND_PCM_STREAM_PLAYBACK, 0) < 0)
72
fprintf (stderr, "Alsa_driver: Cannot open PCM device %s for playback.\n", name);
78
if (snd_pcm_open (&_capt_handle, name, SND_PCM_STREAM_CAPTURE, 0) < 0)
81
fprintf (stderr, "Alsa_driver: Cannot open PCM device %s for capture.\n", name);
85
if (! _play_handle && ! _capt_handle) return;
89
snd_ctl_card_info_alloca (&card);
91
if ((err = snd_ctl_open (&_ctrl_handle, name, 0)) < 0)
93
fprintf (stderr, "Alse_driver: ctl_open(): %s\n", snd_strerror (err));
97
if ((err = snd_ctl_card_info (_ctrl_handle, card)) < 0)
99
fprintf (stderr, "Alsa_driver: ctl_card_info(): %s\n", snd_strerror (err));
104
// check capabilities here
108
if (snd_pcm_hw_params_malloc (&_play_hwpar) < 0)
110
fprintf (stderr, "Alsa_driver: can't allocate playback hw params\n");
114
if (snd_pcm_sw_params_malloc (&_play_swpar) < 0)
116
fprintf (stderr, "Alsa_driver: can't allocate playback sw params\n");
120
if (set_hwpar (_play_handle, _play_hwpar, "playback", &_play_nchan) < 0) return;
122
if (_play_nchan > MAXPLAY)
124
fprintf (stderr, "Alsa_driver: detected %d playback channels, reset to %d.\n", _play_nchan, MAXPLAY);
125
_play_nchan = MAXPLAY;
128
if (set_swpar (_play_handle, _play_swpar, "playback") < 0) return;
133
if (snd_pcm_hw_params_malloc (&_capt_hwpar) < 0)
135
fprintf (stderr, "Alsa_driver: can't allocate capture hw params\n");
139
if (snd_pcm_sw_params_malloc (&_capt_swpar) < 0)
141
fprintf (stderr, "Alsa_driver: can't allocate capture sw params\n");
145
if (set_hwpar (_capt_handle, _capt_hwpar, "capture", &_capt_nchan) < 0) return;
147
if (_capt_nchan > MAXCAPT)
149
fprintf (stderr, "Alsa_driver: detected %d capture channels, reset to %d\n", _capt_nchan, MAXCAPT);
150
_capt_nchan = MAXCAPT;
153
if (set_swpar (_capt_handle, _capt_swpar, "capture") < 0) return;
158
if (snd_pcm_hw_params_get_rate (_play_hwpar, &rate, &dir) || (rate != rate) || dir)
160
fprintf (stderr, "Alsa_driver: can't get requested sample rate for playback.\n");
164
if (snd_pcm_hw_params_get_period_size (_play_hwpar, &frsize, &dir) || (frsize != _frsize) || dir)
166
fprintf (stderr, "Alsa_driver: can't get requested period size for playback.\n");
170
if (snd_pcm_hw_params_get_periods (_play_hwpar, &nfrags, &dir) || (nfrags != _nfrags) || dir)
172
fprintf (stderr, "Alsa_driver: can't get requested number of periods for playback.\n");
176
snd_pcm_hw_params_get_format (_play_hwpar, &_play_format);
177
snd_pcm_hw_params_get_access (_play_hwpar, &_play_access);
179
switch (_play_format)
181
case SND_PCM_FORMAT_S32_LE:
182
_clear_func = clear_32le;
183
_play_func = play_32le;
186
case SND_PCM_FORMAT_S24_3LE:
187
_clear_func = clear_24le;
188
_play_func = play_24le;
191
case SND_PCM_FORMAT_S16_LE:
192
_clear_func = clear_16le;
193
_play_func = play_16le;
197
fprintf (stderr, "Alsa_driver: can't handle playback sample format.\n");
201
_play_npfd = snd_pcm_poll_descriptors_count (_play_handle);
206
if (snd_pcm_hw_params_get_rate (_capt_hwpar, &rate, &dir) || (rate != _rate) || dir)
208
fprintf (stderr, "Alsa_driver: can't get requested sample rate for capture.\n");
212
if (snd_pcm_hw_params_get_period_size (_capt_hwpar, &frsize, &dir) || (frsize != _frsize) || dir)
214
fprintf (stderr, "Alsa_driver: can't get requested period size for capture.\n");
218
if (snd_pcm_hw_params_get_periods (_capt_hwpar, &nfrags, &dir) || (nfrags != _nfrags) || dir)
220
fprintf (stderr, "Alsa_driver: can't get requested number of periods for capture.\n");
224
if (_play_handle) _synced = ! snd_pcm_link (_play_handle, _capt_handle);
226
snd_pcm_hw_params_get_format (_capt_hwpar, &_capt_format);
227
snd_pcm_hw_params_get_access (_capt_hwpar, &_capt_access);
229
switch (_capt_format)
231
case SND_PCM_FORMAT_S32_LE:
232
_capt_func = capt_32le;
235
case SND_PCM_FORMAT_S24_3LE:
236
_capt_func = capt_24le;
239
case SND_PCM_FORMAT_S16_LE:
240
_capt_func = capt_16le;
244
fprintf (stderr, "Alsa_driver: can't handle capture sample format.\n");
248
_capt_npfd = snd_pcm_poll_descriptors_count (_capt_handle);
251
if (_play_npfd + _capt_npfd > MAXPFD)
253
fprintf (stderr, "Alsa_driver: interface requires more than %d pollfd\n", MAXPFD);
261
int Alsa_driver::pcm_start (void)
263
unsigned int i, j, n;
268
n = snd_pcm_avail_update (_play_handle);
269
if (n != _frsize * _nfrags)
271
fprintf (stderr, "Alsa_driver: full buffer not available at start.\n");
275
for (i = 0; i < _nfrags; i++)
278
for (j = 0; j < _play_nchan; j++) clear_chan (j, _frsize);
282
if ((err = snd_pcm_start (_play_handle)) < 0)
284
fprintf (stderr, "Alsa_driver: pcm_start(play): %s.\n", snd_strerror (err));
289
if (_capt_handle && !_synced && ((err = snd_pcm_start (_capt_handle)) < 0))
291
fprintf (stderr, "Alsa_driver: pcm_start(capt): %s.\n", snd_strerror (err));
299
int Alsa_driver::pcm_stop (void)
303
if (_play_handle && ((err = snd_pcm_drop (_play_handle)) < 0))
305
fprintf (stderr, "Alsa_driver: pcm_drop(play): %s.\n", snd_strerror (err));
309
if (_capt_handle && !_synced && ((err = snd_pcm_drop (_capt_handle)) < 0))
311
fprintf (stderr, "Alsa_driver: pcm_drop(capt): %s.\n", snd_strerror (err));
319
snd_pcm_sframes_t Alsa_driver::pcm_wait (void)
323
snd_pcm_sframes_t capt_av;
324
snd_pcm_sframes_t play_av;
329
need_capt = _capt_handle ? true : false;
330
need_play = _play_handle ? true : false;
332
while (need_play || need_capt)
337
snd_pcm_poll_descriptors (_play_handle, _pfd, _play_npfd);
343
snd_pcm_poll_descriptors (_capt_handle, _pfd + n1, _capt_npfd);
347
for (i = 0; i < n2; i++) _pfd [i].events |= POLLERR;
349
r = poll (_pfd, n2, 1000);
357
fprintf (stderr, "Alsa_driver: poll(): %s\n.", strerror (errno));
363
fprintf (stderr, "Alsa_driver: poll timed out\n.");
370
snd_pcm_poll_descriptors_revents (_play_handle, _pfd, n1, &rev);
373
fprintf (stderr, "Alsa_driver: error on playback pollfd.\n");
378
if (rev & POLLOUT) need_play = false;
382
snd_pcm_poll_descriptors_revents (_capt_handle, _pfd + n1, n2 - n1, &rev);
385
fprintf (stderr, "Alsa_driver: error on capture pollfd.\n");
390
if (rev & POLLIN) need_capt = false;
395
if (_play_handle && (play_av = snd_pcm_avail_update (_play_handle)) < 0)
403
if (_capt_handle && (capt_av = snd_pcm_avail_update (_capt_handle)) < 0)
410
return (capt_av < play_av) ? capt_av : play_av;
414
int Alsa_driver::pcm_idle (snd_pcm_uframes_t len)
417
snd_pcm_uframes_t n, k;
436
for (i = 0; i < _play_nchan; i++) clear_chan (i, k);
446
int Alsa_driver::play_init (snd_pcm_uframes_t len)
449
const snd_pcm_channel_area_t *a;
452
if ((err = snd_pcm_mmap_begin (_play_handle, &a, &_play_offs, &len)) < 0)
454
fprintf (stderr, "Alsa_driver: snd_pcm_mmap_begin(play): %s.\n", snd_strerror (err));
458
_play_step = (a->step) >> 3;
459
for (i = 0; i < _play_nchan; i++, a++)
461
_play_ptr [i] = (char *) a->addr + ((a->first + a->step * _play_offs) >> 3);
468
int Alsa_driver::capt_init (snd_pcm_uframes_t len)
471
const snd_pcm_channel_area_t *a;
474
if ((err = snd_pcm_mmap_begin (_capt_handle, &a, &_capt_offs, &len)) < 0)
476
fprintf (stderr, "Alsa_driver: snd_pcm_mmap_begin(capt): %s.\n", snd_strerror (err));
480
_capt_step = (a->step) >> 3;
481
for (i = 0; i < _capt_nchan; i++, a++)
483
_capt_ptr [i] = (char *) a->addr + ((a->first + a->step * _capt_offs) >> 3);
490
void Alsa_driver::printinfo (void)
492
fprintf (stderr, "playback :");
495
fprintf (stderr, "\n nchan : %d\n", _play_nchan);
496
fprintf (stderr, " rate : %d\n", _rate);
497
fprintf (stderr, " frsize : %ld\n", _frsize);
498
fprintf (stderr, " nfrags : %d\n", _nfrags);
499
fprintf (stderr, " format : %s\n", snd_pcm_format_name (_play_format));
501
else fprintf (stderr, " not enabled\n");
502
fprintf (stderr, "capture :");
505
fprintf (stderr, "\n nchan : %d\n", _capt_nchan);
506
fprintf (stderr, " rate : %d\n", _rate);
507
fprintf (stderr, " frsize : %ld\n", _frsize);
508
fprintf (stderr, " nfrags : %d\n", _nfrags);
509
fprintf (stderr, " format : %s\n", snd_pcm_format_name (_capt_format));
510
if (_play_handle) fprintf (stderr, "%s\n", _synced ? "synced" : "not synced");
512
else fprintf (stderr, " not enabled\n");
516
// Private members ---------------------------------------------------------------------
519
int Alsa_driver::set_hwpar (snd_pcm_t *handle, snd_pcm_hw_params_t *hwpar, const char *sname, unsigned int *nchan)
524
if ((err = snd_pcm_hw_params_any (handle, hwpar)) < 0)
526
fprintf (stderr, "Alsa_driver: no %s hw configurations available: %s.\n", sname, snd_strerror (err));
530
if ((err = snd_pcm_hw_params_set_periods_integer (handle, hwpar)) < 0)
532
fprintf (stderr, "Alsa_driver: can't set %s period size to integral value.\n", sname);
536
if ( ((err = snd_pcm_hw_params_set_access (handle, hwpar, SND_PCM_ACCESS_MMAP_NONINTERLEAVED)) < 0)
537
&& ((err = snd_pcm_hw_params_set_access (handle, hwpar, SND_PCM_ACCESS_MMAP_INTERLEAVED)) < 0))
539
fprintf (stderr, "Alsa_driver: the %s interface doesn't support mmap-based access.\n", sname);
543
if ( ((err = snd_pcm_hw_params_set_format (handle, hwpar, SND_PCM_FORMAT_S32)) < 0)
544
&& ((err = snd_pcm_hw_params_set_format (handle, hwpar, SND_PCM_FORMAT_S24_3LE)) < 0)
545
&& ((err = snd_pcm_hw_params_set_format (handle, hwpar, SND_PCM_FORMAT_S16)) < 0))
547
fprintf (stderr, "Alsa_driver: the %s interface doesn't support 32, 24 or 16 bit access.\n.", sname);
551
if ((err = snd_pcm_hw_params_set_rate (handle, hwpar, _rate, 0)) < 0)
553
fprintf (stderr, "Alsa_driver: can't set %s sample rate to %u.\n", sname, _rate);
557
snd_pcm_hw_params_get_channels_max (hwpar, nchan);
561
fprintf (stderr, "Alsa_driver: detected more than 1024 %s channnels, reset to 2.\n", sname);
565
if ((err = snd_pcm_hw_params_set_channels (handle, hwpar, *nchan)) < 0)
567
fprintf (stderr, "Alsa_driver: can't set %s channel count to %u.\n", sname, *nchan);
572
if ((err = snd_pcm_hw_params_set_period_size (handle, hwpar, _frsize, 0)) < 0)
574
fprintf (stderr, "Alsa_driver: can't set %s period size to %lu.\n", sname, _frsize);
578
// This is to handle recent ALSA releases creating a default device with
579
// a large number of periods...
581
snd_pcm_hw_params_set_periods_min (handle, hwpar, &n, NULL);
582
if (_nfrags < n) _nfrags = n;
584
if ((err = snd_pcm_hw_params_set_periods_near (handle, hwpar, &_nfrags, 0)) < 0)
586
fprintf (stderr, "Alsa_driver: can't set %s periods to %u.\n", sname, _nfrags);
590
if ((err = snd_pcm_hw_params_set_buffer_size (handle, hwpar, _frsize * _nfrags)) < 0)
592
fprintf (stderr, "Alsa_driver: can't set %s buffer length to %lu.\n", sname, _frsize * _nfrags);
596
if ((err = snd_pcm_hw_params (handle, hwpar)) < 0)
598
fprintf (stderr, "Alsa_driver: can't set %s hardware parameters.\n", sname);
606
int Alsa_driver::set_swpar (snd_pcm_t *handle, snd_pcm_sw_params_t *swpar, const char *sname)
610
snd_pcm_sw_params_current (handle, swpar);
612
if ((err = snd_pcm_sw_params_set_tstamp_mode (handle, swpar, SND_PCM_TSTAMP_MMAP)) < 0)
614
fprintf (stderr, "Alsa_driver: can't set %s timestamp mode to %u.\n", sname, SND_PCM_TSTAMP_MMAP);
618
if ((err = snd_pcm_sw_params_set_avail_min (handle, swpar, _frsize)) < 0)
620
fprintf (stderr, "Alsa_driver: can't set %s availmin to %lu.\n", sname, _frsize);
624
if ((err = snd_pcm_sw_params (handle, swpar)) < 0)
626
fprintf (stderr, "Alsa_driver: can't set %s software parameters.\n", sname);
634
int Alsa_driver::recover (void)
637
snd_pcm_status_t *stat;
639
snd_pcm_status_alloca (&stat);
641
if ((err = snd_pcm_status (_play_handle ? _play_handle : _capt_handle, stat)) < 0)
643
fprintf (stderr, "Alsa_driver: pcm_status(): %s\n", snd_strerror (err));
645
else if (snd_pcm_status_get_state (stat) == SND_PCM_STATE_XRUN)
647
struct timeval tnow, trig;
649
gettimeofday (&tnow, 0);
650
snd_pcm_status_get_trigger_tstamp (stat, &trig);
651
fprintf (stderr, "Alsa_driver: stat = %02x, xrun of at least %8.3lf ms\n", _stat,
652
1e3 * tnow.tv_sec - 1e3 * trig.tv_sec + 1e-3 * tnow.tv_usec - 1e-3 * trig.tv_usec);
655
if (pcm_stop ()) return -1;
657
if (_play_handle && ((err = snd_pcm_prepare (_play_handle)) < 0))
659
fprintf (stderr, "Alsa_driver: pcm_prepare(play): %s\n", snd_strerror (err));
663
if (_capt_handle && !_synced && ((err = snd_pcm_prepare (_capt_handle)) < 0))
665
fprintf (stderr, "Alsa_driver: pcm_prepare(capt): %s\n", snd_strerror (err));
669
if (pcm_start ()) return -1;
675
// Static members ----------------------------------------------------------------------
678
char *Alsa_driver::clear_16le (char *dst, int step, int nfrm)
682
*((short int *) dst) = 0;
688
char *Alsa_driver::play_16le (const float *src, char *dst, int step, int nfrm)
696
if (s > 1) d = 0x7fff;
697
else if (s < -1) d = 0x8001;
698
else d = (short int)(0x7fff * s);
699
*((short int *) dst) = d;
705
const char *Alsa_driver::capt_16le (const char *src, float *dst, int step, int nfrm )
712
s = *((short int *) src);
713
d = (float) s / 0x7fff;
720
char *Alsa_driver::clear_24le (char *dst, int step, int nfrm)
732
char *Alsa_driver::play_24le (const float *src, char *dst, int step, int nfrm)
740
if (s > 1) d = 0x007fffff;
741
else if (s < -1) d = 0x00800001;
742
else d = (int)(0x007fffff * s);
751
const char *Alsa_driver::capt_24le (const char *src, float *dst, int step, int nfrm)
759
s += (src [1] & 0xFF) << 8;
760
s += (src [2] & 0xFF) << 16;
761
if (s & 0x00800000) s-= 0x01000000;
762
d = (float) s / 0x007fffff;
770
char *Alsa_driver::clear_32le (char *dst, int step, int nfrm)
780
char *Alsa_driver::play_32le (const float *src, char *dst, int step, int nfrm)
788
if (s > 1) d = 0x007fffff;
789
else if (s < -1) d = 0x00800001;
790
else d = (int)(0x007fffff * s);
791
*((int *) dst) = d << 8;
797
const char *Alsa_driver::capt_32le (const char *src, float *dst, int step, int nfrm)
805
d = (float) s / 0x7fffff00;