~ubuntu-branches/debian/stretch/clalsadrv/stretch

« back to all changes in this revision

Viewing changes to libs/clalsadrv.cc

  • Committer: Bazaar Package Importer
  • Author(s): Alessio Treglia
  • Date: 2010-04-17 12:25:13 UTC
  • mfrom: (1.1.4 upstream) (2.1.4 experimental)
  • Revision ID: james.westby@ubuntu.com-20100417122513-vsy32s4vwo8vgzvs
Tags: 2.0.0-2
Upload to unstable.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
    Copyright (C) 2003-2010 Fons Adriaensen <fons@kokkinizita.net>
 
3
    
 
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.
 
8
 
 
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.
 
13
 
 
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.
 
17
*/
 
18
 
 
19
 
 
20
#include <sys/time.h>
 
21
#include "clalsadrv.h"
 
22
 
 
23
 
 
24
// Public members ----------------------------------------------------------------------
 
25
 
 
26
 
 
27
Alsa_driver::~Alsa_driver (void)
 
28
{
 
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);
 
33
 
 
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); 
 
37
}
 
38
 
 
39
 
 
40
Alsa_driver::Alsa_driver (const char        *play_name,
 
41
                          const char        *capt_name,
 
42
                          const char        *ctrl_name,
 
43
                          unsigned int       rate,
 
44
                          snd_pcm_uframes_t  frsize,
 
45
                          unsigned int       nfrags) :
 
46
    _rate (rate),
 
47
    _frsize (frsize),
 
48
    _nfrags (nfrags),   
 
49
    _play_handle (0),
 
50
    _capt_handle (0),
 
51
    _ctrl_handle (0),
 
52
    _play_hwpar (0),
 
53
    _play_swpar (0),
 
54
    _capt_hwpar (0),
 
55
    _capt_swpar (0),
 
56
    _play_nchan (0),
 
57
    _capt_nchan (0),
 
58
    _play_npfd (0),
 
59
    _capt_npfd (0),
 
60
    _synced (false),
 
61
    _stat (-1)
 
62
{
 
63
    initialise (play_name, capt_name, ctrl_name, rate, frsize, nfrags);
 
64
}
 
65
 
 
66
 
 
67
Alsa_driver::Alsa_driver (const char        *name,
 
68
                          unsigned int       rate,
 
69
                          snd_pcm_uframes_t  frsize,
 
70
                          unsigned int       nfrags,
 
71
                          bool               play,
 
72
                          bool               capt,
 
73
                          bool               ctrl) :
 
74
    _rate (rate),
 
75
    _frsize (frsize),
 
76
    _nfrags (nfrags),   
 
77
    _play_handle (0),
 
78
    _capt_handle (0),
 
79
    _ctrl_handle (0),
 
80
    _play_hwpar (0),
 
81
    _play_swpar (0),
 
82
    _capt_hwpar (0),
 
83
    _capt_swpar (0),
 
84
    _play_nchan (0),
 
85
    _capt_nchan (0),
 
86
    _play_npfd (0),
 
87
    _capt_npfd (0),
 
88
    _synced (false),
 
89
    _stat (-1)
 
90
{
 
91
    initialise (play ? name : 0, capt ? name : 0, ctrl ? name : 0, rate, frsize, nfrags);
 
92
}
 
93
 
 
94
 
 
95
int Alsa_driver::pcm_start (void)
 
96
{
 
97
    unsigned int i, j, n;
 
98
    int          err;
 
99
 
 
100
    if (_play_handle)
 
101
    {
 
102
        n = snd_pcm_avail_update (_play_handle);
 
103
        if (n != _frsize * _nfrags)
 
104
        {
 
105
            fprintf  (stderr, "Alsa_driver: full buffer not available at start.\n");
 
106
            return -1;
 
107
        }
 
108
 
 
109
        for (i = 0; i < _nfrags; i++)
 
110
        {     
 
111
            play_init (_frsize);
 
112
            for (j = 0; j < _play_nchan; j++) clear_chan (j, _frsize);
 
113
            play_done (_frsize);
 
114
        }
 
115
                
 
116
        if ((err = snd_pcm_start (_play_handle)) < 0)
 
117
        {
 
118
            fprintf (stderr, "Alsa_driver: pcm_start(play): %s.\n", snd_strerror (err));
 
119
            return -1;
 
120
        }
 
121
    }
 
122
 
 
123
    if (_capt_handle && !_synced && ((err = snd_pcm_start (_capt_handle)) < 0))
 
124
    {
 
125
        fprintf (stderr, "Alsa_driver: pcm_start(capt): %s.\n", snd_strerror (err));
 
126
        return -1;
 
127
    }
 
128
 
 
129
    return 0;
 
130
}
 
131
 
 
132
 
 
133
int Alsa_driver::pcm_stop (void)
 
134
{
 
135
    int err;
 
136
 
 
137
    if (_play_handle && ((err = snd_pcm_drop (_play_handle)) < 0))
 
138
    {
 
139
        fprintf (stderr, "Alsa_driver: pcm_drop(play): %s.\n", snd_strerror (err));
 
140
        return -1;
 
141
    }
 
142
 
 
143
    if (_capt_handle && !_synced && ((err = snd_pcm_drop (_capt_handle)) < 0))
 
144
    {
 
145
        fprintf (stderr, "Alsa_driver: pcm_drop(capt): %s.\n", snd_strerror (err));
 
146
        return -1;
 
147
    }
 
148
 
 
149
    return 0;
 
150
}
 
151
 
 
152
 
 
153
snd_pcm_sframes_t Alsa_driver::pcm_wait (void)
 
154
{
 
155
    bool              need_capt;
 
156
    bool              need_play;
 
157
    snd_pcm_sframes_t capt_av;
 
158
    snd_pcm_sframes_t play_av;
 
159
    unsigned short    rev;
 
160
    int               i, r, n1, n2;
 
161
 
 
162
    _stat = 0;
 
163
    need_capt = _capt_handle ? true : false;
 
164
    need_play = _play_handle ? true : false;
 
165
 
 
166
    while (need_play || need_capt)
 
167
    {
 
168
        n1 = 0;
 
169
        if (need_play)
 
170
        {
 
171
            snd_pcm_poll_descriptors (_play_handle, _pfd, _play_npfd);
 
172
            n1 += _play_npfd;
 
173
        }
 
174
        n2 = n1;
 
175
        if (need_capt)
 
176
        {
 
177
            snd_pcm_poll_descriptors (_capt_handle, _pfd + n1, _capt_npfd);
 
178
            n2 += _capt_npfd;
 
179
        }
 
180
 
 
181
        for (i = 0; i < n2; i++) _pfd [i].events |= POLLERR;
 
182
 
 
183
        r = poll (_pfd, n2, 1000);
 
184
        if (r < 0)
 
185
        {
 
186
            if (errno == EINTR)
 
187
            {
 
188
                _stat = -1;
 
189
                return 0;
 
190
            }
 
191
            fprintf (stderr, "Alsa_driver: poll(): %s\n.", strerror (errno));
 
192
            _stat = -2;
 
193
            return 0;
 
194
        }
 
195
        if (r == 0)
 
196
        { 
 
197
            fprintf (stderr, "Alsa_driver: poll timed out\n.");
 
198
            _stat = -3;
 
199
            return 0;
 
200
        }               
 
201
 
 
202
        if (need_play)
 
203
        {
 
204
            snd_pcm_poll_descriptors_revents (_play_handle, _pfd, n1, &rev);
 
205
            if (rev & POLLERR)
 
206
            {
 
207
                fprintf (stderr, "Alsa_driver: error on playback pollfd.\n");
 
208
                _stat = -4;
 
209
                recover ();
 
210
                return 0;
 
211
            }
 
212
            if (rev & POLLOUT) need_play = false;
 
213
        }
 
214
        if (need_capt)
 
215
        {
 
216
            snd_pcm_poll_descriptors_revents (_capt_handle, _pfd + n1, n2 - n1, &rev);
 
217
            if (rev & POLLERR)
 
218
            {
 
219
                fprintf (stderr, "Alsa_driver: error on capture pollfd.\n");
 
220
                _stat = -4;
 
221
                recover ();
 
222
                return 0;
 
223
            }
 
224
            if (rev & POLLIN) need_capt = false;
 
225
        }
 
226
    }
 
227
 
 
228
    play_av = 999999;
 
229
    if (_play_handle && (play_av = snd_pcm_avail_update (_play_handle)) < 0)
 
230
    {
 
231
        _stat = -5;
 
232
        recover ();
 
233
        return 0;
 
234
    }
 
235
 
 
236
    capt_av = 999999;
 
237
    if (_capt_handle && (capt_av = snd_pcm_avail_update (_capt_handle)) < 0)
 
238
    {
 
239
        _stat = -6;
 
240
        recover ();
 
241
        return 0;
 
242
    }
 
243
 
 
244
    return (capt_av < play_av) ? capt_av : play_av;
 
245
}
 
246
 
 
247
 
 
248
int Alsa_driver::pcm_idle (snd_pcm_uframes_t len)
 
249
{
 
250
    unsigned int       i;
 
251
    snd_pcm_uframes_t  n, k;
 
252
 
 
253
    if (_capt_handle)
 
254
    {
 
255
        n = len;
 
256
        while (n)  
 
257
        {
 
258
            k = capt_init (n);
 
259
            capt_done (k);
 
260
            n -= k;
 
261
        }
 
262
    }
 
263
 
 
264
    if (_play_handle)
 
265
    {
 
266
        n = len;
 
267
        while (n)
 
268
        {
 
269
            k = play_init (n);
 
270
            for (i = 0; i < _play_nchan; i++) clear_chan (i, k);
 
271
            play_done (k);
 
272
            n -= k;
 
273
        }
 
274
    }
 
275
 
 
276
    return 0;
 
277
}
 
278
 
 
279
 
 
280
int Alsa_driver::play_init (snd_pcm_uframes_t len)
 
281
{
 
282
    unsigned int                   i;
 
283
    const snd_pcm_channel_area_t   *a;
 
284
    int                            err;
 
285
 
 
286
    if ((err = snd_pcm_mmap_begin (_play_handle, &a, &_play_offs, &len)) < 0)
 
287
    {
 
288
        fprintf (stderr, "Alsa_driver: snd_pcm_mmap_begin(play): %s.\n", snd_strerror (err)); 
 
289
        return -1;
 
290
    }
 
291
 
 
292
    _play_step = (a->step) >> 3;
 
293
    for (i = 0; i < _play_nchan; i++, a++)
 
294
    {
 
295
        _play_ptr [i] = (char *) a->addr + ((a->first + a->step * _play_offs) >> 3);
 
296
    } 
 
297
   
 
298
    return len;
 
299
}
 
300
 
 
301
 
 
302
int Alsa_driver::capt_init (snd_pcm_uframes_t len)
 
303
{
 
304
    unsigned int                  i;
 
305
    const snd_pcm_channel_area_t  *a;
 
306
    int                           err;
 
307
 
 
308
    if ((err = snd_pcm_mmap_begin (_capt_handle, &a, &_capt_offs, &len)) < 0)
 
309
    {
 
310
        fprintf (stderr, "Alsa_driver: snd_pcm_mmap_begin(capt): %s.\n", snd_strerror (err)); 
 
311
        return -1;
 
312
    }
 
313
 
 
314
    _capt_step = (a->step) >> 3;
 
315
    for (i = 0; i < _capt_nchan; i++, a++)
 
316
    {
 
317
        _capt_ptr [i] = (char *) a->addr + ((a->first + a->step * _capt_offs) >> 3);
 
318
    } 
 
319
   
 
320
    return len;
 
321
}
 
322
 
 
323
 
 
324
void Alsa_driver::printinfo (void)
 
325
{
 
326
    fprintf (stderr, "playback :");
 
327
    if (_play_handle)
 
328
    {
 
329
        fprintf (stderr, "\n  nchan  : %d\n", _play_nchan);
 
330
        fprintf (stderr, "  rate   : %d\n", _rate);
 
331
        fprintf (stderr, "  frsize : %ld\n", _frsize);
 
332
        fprintf (stderr, "  nfrags : %d\n", _nfrags);
 
333
        fprintf (stderr, "  format : %s\n", snd_pcm_format_name (_play_format));
 
334
    }
 
335
    else fprintf (stderr, " not enabled\n");
 
336
    fprintf (stderr, "capture  :");
 
337
    if (_capt_handle)
 
338
    {
 
339
        fprintf (stderr, "\n  nchan  : %d\n", _capt_nchan);
 
340
        fprintf (stderr, "  rate   : %d\n", _rate);
 
341
        fprintf (stderr, "  frsize : %ld\n", _frsize);
 
342
        fprintf (stderr, "  nfrags : %d\n", _nfrags);
 
343
        fprintf (stderr, "  format : %s\n", snd_pcm_format_name (_capt_format));
 
344
        if (_play_handle) fprintf (stderr, "%s\n", _synced ? "synced" : "not synced");
 
345
    }
 
346
    else fprintf (stderr, " not enabled\n");
 
347
}
 
348
 
 
349
 
 
350
// Private members ---------------------------------------------------------------------
 
351
 
 
352
 
 
353
void Alsa_driver::initialise (const char        *play_name,
 
354
                              const char        *capt_name,
 
355
                              const char        *ctrl_name,
 
356
                              unsigned int       rate,
 
357
                              snd_pcm_uframes_t  frsize,
 
358
                              unsigned int       nfrags)
 
359
{
 
360
    int                  err, dir;
 
361
    snd_ctl_card_info_t *card;
 
362
 
 
363
    if (play_name)
 
364
    {
 
365
        if (snd_pcm_open (&_play_handle, play_name, SND_PCM_STREAM_PLAYBACK, 0) < 0)
 
366
        {
 
367
            _play_handle = 0;
 
368
            fprintf (stderr, "Alsa_driver: Cannot open PCM device %s for playback.\n", play_name);
 
369
        }
 
370
    }
 
371
    
 
372
    if (capt_name)
 
373
    {
 
374
        if (snd_pcm_open (&_capt_handle, capt_name, SND_PCM_STREAM_CAPTURE, 0) < 0)
 
375
        {
 
376
            _capt_handle = 0;
 
377
            fprintf (stderr, "Alsa_driver: Cannot open PCM device %s for capture.\n", capt_name);
 
378
        }
 
379
    }
 
380
 
 
381
    if (! _play_handle && ! _capt_handle) return;
 
382
 
 
383
    if (ctrl_name)
 
384
    {
 
385
        snd_ctl_card_info_alloca (&card);
 
386
 
 
387
        if ((err = snd_ctl_open (&_ctrl_handle, ctrl_name, 0)) < 0)
 
388
        {
 
389
            fprintf  (stderr, "Alse_driver: ctl_open(): %s\n", snd_strerror (err));
 
390
            return;
 
391
        }
 
392
        
 
393
        if ((err = snd_ctl_card_info (_ctrl_handle, card)) < 0)
 
394
        {
 
395
            fprintf  (stderr, "Alsa_driver: ctl_card_info(): %s\n", snd_strerror (err));
 
396
            return;
 
397
        }
 
398
    }
 
399
 
 
400
    // check capabilities here
 
401
 
 
402
    if (_play_handle)
 
403
    {
 
404
        if (snd_pcm_hw_params_malloc (&_play_hwpar) < 0)
 
405
        {
 
406
            fprintf (stderr, "Alsa_driver: can't allocate playback hw params\n");
 
407
            return;
 
408
        }
 
409
 
 
410
        if (snd_pcm_sw_params_malloc (&_play_swpar) < 0)
 
411
        {
 
412
            fprintf (stderr, "Alsa_driver: can't allocate playback sw params\n");
 
413
            return;
 
414
        }
 
415
 
 
416
        if (set_hwpar (_play_handle, _play_hwpar, "playback", &_play_nchan) < 0) return;
 
417
 
 
418
        if (_play_nchan > MAXPLAY)
 
419
        {
 
420
            fprintf (stderr, "Alsa_driver: detected %d playback channels, reset to %d.\n", _play_nchan, MAXPLAY);
 
421
            _play_nchan = MAXPLAY;     
 
422
        }
 
423
 
 
424
        if (set_swpar (_play_handle, _play_swpar, "playback") < 0) return;
 
425
    }
 
426
        
 
427
    if (_capt_handle)
 
428
    {
 
429
        if (snd_pcm_hw_params_malloc (&_capt_hwpar) < 0)
 
430
        {
 
431
            fprintf (stderr, "Alsa_driver: can't allocate capture hw params\n");
 
432
            return;
 
433
        }
 
434
 
 
435
        if (snd_pcm_sw_params_malloc (&_capt_swpar) < 0)
 
436
        {
 
437
            fprintf (stderr, "Alsa_driver: can't allocate capture sw params\n");
 
438
            return;
 
439
        }
 
440
 
 
441
        if (set_hwpar (_capt_handle, _capt_hwpar, "capture", &_capt_nchan) < 0) return;
 
442
 
 
443
        if (_capt_nchan > MAXCAPT)
 
444
        {
 
445
            fprintf (stderr, "Alsa_driver: detected %d capture channels, reset to %d\n", _capt_nchan, MAXCAPT);
 
446
            _capt_nchan = MAXCAPT;     
 
447
        }
 
448
 
 
449
        if (set_swpar (_capt_handle, _capt_swpar, "capture") < 0) return;
 
450
    }
 
451
 
 
452
    if (_play_handle)
 
453
    {
 
454
        if (snd_pcm_hw_params_get_rate (_play_hwpar, &rate, &dir) || (rate != _rate) || dir)
 
455
        {
 
456
            fprintf (stderr, "Alsa_driver: can't get requested sample rate for playback.\n"); 
 
457
            return;
 
458
        }
 
459
 
 
460
        if (snd_pcm_hw_params_get_period_size (_play_hwpar, &frsize, &dir) || (frsize != _frsize) || dir)
 
461
        {
 
462
            fprintf (stderr, "Alsa_driver: can't get requested period size for playback.\n"); 
 
463
            return;
 
464
        }
 
465
 
 
466
        if (snd_pcm_hw_params_get_periods (_play_hwpar, &nfrags, &dir) || (nfrags != _nfrags) || dir)
 
467
        {
 
468
            fprintf (stderr, "Alsa_driver: can't get requested number of periods for playback.\n"); 
 
469
            return;
 
470
        }
 
471
 
 
472
        snd_pcm_hw_params_get_format (_play_hwpar, &_play_format);
 
473
        snd_pcm_hw_params_get_access (_play_hwpar, &_play_access);
 
474
 
 
475
        switch (_play_format)
 
476
        {
 
477
        case SND_PCM_FORMAT_S32_LE:
 
478
            _clear_func = clear_32le;     
 
479
            _play_func  = play_32le;     
 
480
            break;
 
481
 
 
482
        case SND_PCM_FORMAT_S24_3LE:
 
483
            _clear_func = clear_24le;     
 
484
            _play_func  = play_24le;     
 
485
            break;
 
486
 
 
487
        case SND_PCM_FORMAT_S16_LE:
 
488
            _clear_func = clear_16le;     
 
489
            _play_func  = play_16le;     
 
490
            break;
 
491
 
 
492
        default:
 
493
            fprintf (stderr, "Alsa_driver: can't handle playback sample format.\n"); 
 
494
            return;
 
495
        }
 
496
 
 
497
       _play_npfd = snd_pcm_poll_descriptors_count (_play_handle);
 
498
    }
 
499
 
 
500
    if (_capt_handle)
 
501
    {
 
502
        if (snd_pcm_hw_params_get_rate (_capt_hwpar, &rate, &dir) || (rate != _rate) || dir)
 
503
        {
 
504
            fprintf (stderr, "Alsa_driver: can't get requested sample rate for capture.\n"); 
 
505
            return;
 
506
        }
 
507
 
 
508
        if (snd_pcm_hw_params_get_period_size (_capt_hwpar, &frsize, &dir) || (frsize != _frsize) || dir)
 
509
        {
 
510
            fprintf (stderr, "Alsa_driver: can't get requested period size for capture.\n"); 
 
511
            return;
 
512
        }
 
513
 
 
514
        if (snd_pcm_hw_params_get_periods (_capt_hwpar, &nfrags, &dir) || (nfrags != _nfrags) || dir)
 
515
        {
 
516
            fprintf (stderr, "Alsa_driver: can't get requested number of periods for capture.\n"); 
 
517
            return;
 
518
        }
 
519
 
 
520
        if (_play_handle) _synced = ! snd_pcm_link (_play_handle, _capt_handle);
 
521
 
 
522
        snd_pcm_hw_params_get_format (_capt_hwpar, &_capt_format);
 
523
        snd_pcm_hw_params_get_access (_capt_hwpar, &_capt_access);
 
524
 
 
525
        switch (_capt_format)
 
526
        {
 
527
        case SND_PCM_FORMAT_S32_LE:
 
528
            _capt_func  = capt_32le;     
 
529
            break;
 
530
 
 
531
        case SND_PCM_FORMAT_S24_3LE:
 
532
            _capt_func  = capt_24le;     
 
533
            break;
 
534
 
 
535
        case SND_PCM_FORMAT_S16_LE:
 
536
            _capt_func  = capt_16le;     
 
537
            break;
 
538
 
 
539
        default:
 
540
            fprintf (stderr, "Alsa_driver: can't handle capture sample format.\n"); 
 
541
            return;
 
542
        }
 
543
 
 
544
        _capt_npfd = snd_pcm_poll_descriptors_count (_capt_handle);
 
545
    }
 
546
 
 
547
    if (_play_npfd + _capt_npfd > MAXPFD)
 
548
    {
 
549
        fprintf (stderr, "Alsa_driver: interface requires more than %d pollfd\n", MAXPFD);
 
550
        return;
 
551
    }      
 
552
 
 
553
    _stat = 0;
 
554
}       
 
555
 
 
556
 
 
557
int Alsa_driver::set_hwpar (snd_pcm_t *handle,  snd_pcm_hw_params_t *hwpar, const char *sname, unsigned int *nchan)
 
558
{
 
559
    int           err;
 
560
    unsigned int  n;
 
561
 
 
562
    if ((err = snd_pcm_hw_params_any (handle, hwpar)) < 0)
 
563
    {
 
564
        fprintf (stderr, "Alsa_driver: no %s hw configurations available: %s.\n", sname, snd_strerror (err));
 
565
        return -1;
 
566
    }
 
567
 
 
568
    if ((err = snd_pcm_hw_params_set_periods_integer (handle, hwpar)) < 0)
 
569
    {
 
570
        fprintf (stderr, "Alsa_driver: can't set %s period size to integral value.\n", sname);
 
571
        return -1;
 
572
    }
 
573
 
 
574
    if (   ((err = snd_pcm_hw_params_set_access (handle, hwpar, SND_PCM_ACCESS_MMAP_NONINTERLEAVED)) < 0)
 
575
        && ((err = snd_pcm_hw_params_set_access (handle, hwpar, SND_PCM_ACCESS_MMAP_INTERLEAVED)) < 0)
 
576
        && ((err = snd_pcm_hw_params_set_access (handle, hwpar, SND_PCM_ACCESS_MMAP_COMPLEX)) < 0))
 
577
    {
 
578
        fprintf (stderr, "Alsa_driver: the %s interface doesn't support mmap-based access.\n", sname);
 
579
        return -1;
 
580
    }
 
581
 
 
582
    if (   ((err = snd_pcm_hw_params_set_format (handle, hwpar, SND_PCM_FORMAT_S32_LE)) < 0)
 
583
        && ((err = snd_pcm_hw_params_set_format (handle, hwpar, SND_PCM_FORMAT_S24_3LE)) < 0)
 
584
        && ((err = snd_pcm_hw_params_set_format (handle, hwpar, SND_PCM_FORMAT_S16_LE)) < 0))
 
585
    {
 
586
        fprintf (stderr, "Alsa_driver: the %s interface doesn't support 32, 24 or 16 bit access.\n.", sname);
 
587
        return -1;
 
588
    }
 
589
 
 
590
    if ((err = snd_pcm_hw_params_set_rate (handle, hwpar, _rate, 0)) < 0)
 
591
    {
 
592
        fprintf (stderr, "Alsa_driver: can't set %s sample rate to %u.\n", sname, _rate);
 
593
        return -1;
 
594
    }
 
595
 
 
596
    snd_pcm_hw_params_get_channels_max (hwpar, nchan);
 
597
 
 
598
    if (*nchan > 1024)
 
599
    { 
 
600
       fprintf (stderr, "Alsa_driver: detected more than 1024 %s channnels, reset to 2.\n", sname);
 
601
       *nchan = 2;     
 
602
    }                           
 
603
 
 
604
    if ((err = snd_pcm_hw_params_set_channels (handle, hwpar, *nchan)) < 0)
 
605
    {
 
606
        fprintf (stderr, "Alsa_driver: can't set %s channel count to %u.\n", sname, *nchan);
 
607
        return -1;
 
608
    }
 
609
 
 
610
 
 
611
    if ((err = snd_pcm_hw_params_set_period_size (handle, hwpar, _frsize, 0)) < 0)
 
612
    {
 
613
        fprintf (stderr, "Alsa_driver: can't set %s period size to %lu.\n", sname, _frsize);
 
614
        return -1;
 
615
    }
 
616
 
 
617
    // This is to handle recent ALSA releases creating a default device with
 
618
    // a large number of periods...
 
619
    n = _nfrags; 
 
620
    snd_pcm_hw_params_set_periods_min (handle, hwpar, &n, NULL);
 
621
    if (_nfrags < n) _nfrags = n; 
 
622
 
 
623
    if ((err = snd_pcm_hw_params_set_periods_near (handle, hwpar, &_nfrags, 0)) < 0)
 
624
    {
 
625
        fprintf (stderr, "Alsa_driver: can't set %s periods to %u.\n", sname, _nfrags);
 
626
        return -1;
 
627
    }
 
628
        
 
629
    if ((err = snd_pcm_hw_params_set_buffer_size (handle, hwpar, _frsize * _nfrags)) < 0)
 
630
    {
 
631
        fprintf (stderr, "Alsa_driver: can't set %s buffer length to %lu.\n", sname, _frsize * _nfrags);
 
632
        return -1;
 
633
    }
 
634
 
 
635
    if ((err = snd_pcm_hw_params (handle, hwpar)) < 0)
 
636
    {
 
637
        fprintf (stderr, "Alsa_driver: can't set %s hardware parameters.\n", sname);
 
638
        return -1;
 
639
    }
 
640
 
 
641
    return 0;
 
642
}
 
643
 
 
644
 
 
645
int Alsa_driver::set_swpar (snd_pcm_t *handle, snd_pcm_sw_params_t *swpar, const char *sname) 
 
646
{
 
647
    int err;
 
648
 
 
649
    snd_pcm_sw_params_current (handle, swpar);
 
650
 
 
651
    if ((err = snd_pcm_sw_params_set_tstamp_mode (handle, swpar, SND_PCM_TSTAMP_MMAP)) < 0)
 
652
    {
 
653
        fprintf (stderr, "Alsa_driver: can't set %s timestamp mode to %u.\n", sname, SND_PCM_TSTAMP_MMAP);
 
654
        return -1;
 
655
    }
 
656
 
 
657
    if ((err = snd_pcm_sw_params_set_avail_min (handle, swpar, _frsize)) < 0)
 
658
    {
 
659
        fprintf (stderr, "Alsa_driver: can't set %s availmin to %lu.\n", sname, _frsize);
 
660
        return -1;
 
661
    }
 
662
 
 
663
    if ((err = snd_pcm_sw_params (handle, swpar)) < 0)
 
664
    {
 
665
        fprintf (stderr, "Alsa_driver: can't set %s software parameters.\n", sname);
 
666
        return -1;
 
667
    }
 
668
 
 
669
    return 0;
 
670
}
 
671
 
 
672
 
 
673
int Alsa_driver::recover (void)
 
674
{
 
675
    int                err; 
 
676
    snd_pcm_status_t  *stat;
 
677
 
 
678
    snd_pcm_status_alloca (&stat);
 
679
 
 
680
    if ((err = snd_pcm_status (_play_handle ? _play_handle : _capt_handle, stat)) < 0)
 
681
    {
 
682
        fprintf (stderr, "Alsa_driver: pcm_status(): %s\n",  snd_strerror (err));
 
683
    }
 
684
    else if (snd_pcm_status_get_state (stat) == SND_PCM_STATE_XRUN)
 
685
    {
 
686
        struct timeval tnow, trig;
 
687
 
 
688
        gettimeofday (&tnow, 0);
 
689
        snd_pcm_status_get_trigger_tstamp (stat, &trig);
 
690
        fprintf (stderr, "Alsa_driver: stat = %02x, xrun of at least %8.3lf ms\n", _stat,
 
691
                 1e3 * tnow.tv_sec - 1e3 * trig.tv_sec + 1e-3 * tnow.tv_usec - 1e-3 * trig.tv_usec);
 
692
    }
 
693
 
 
694
    if (pcm_stop ()) return -1;
 
695
 
 
696
    if (_play_handle && ((err = snd_pcm_prepare (_play_handle)) < 0))
 
697
    {
 
698
        fprintf (stderr, "Alsa_driver: pcm_prepare(play): %s\n", snd_strerror (err));
 
699
        return -1;
 
700
    }
 
701
 
 
702
    if (_capt_handle && !_synced && ((err = snd_pcm_prepare (_capt_handle)) < 0))
 
703
    {
 
704
        fprintf (stderr, "Alsa_driver: pcm_prepare(capt): %s\n", snd_strerror (err));
 
705
        return -1;
 
706
    }
 
707
 
 
708
    if (pcm_start ()) return -1;
 
709
 
 
710
    return 0;
 
711
}       
 
712
 
 
713
 
 
714
// Static members ----------------------------------------------------------------------
 
715
 
 
716
 
 
717
char *Alsa_driver::clear_16le (char *dst, int step, int nfrm)
 
718
{
 
719
    while (nfrm--)
 
720
    {
 
721
        *((short int *) dst) = 0;
 
722
        dst += step;
 
723
    }  
 
724
    return dst;
 
725
}
 
726
 
 
727
char *Alsa_driver::play_16le (const float *src, char *dst, int step, int nfrm)
 
728
{
 
729
    float     s;
 
730
    short int d;
 
731
 
 
732
    while (nfrm--)
 
733
    {
 
734
        s = *src++;
 
735
        if      (s >  1) d = 0x7fff;
 
736
        else if (s < -1) d = 0x8001;
 
737
        else d = (short int)(0x7fff * s); 
 
738
        *((short int *) dst) = d;
 
739
        dst += step;
 
740
    } 
 
741
    return dst; 
 
742
}
 
743
 
 
744
const char *Alsa_driver::capt_16le (const char *src, float *dst, int step, int nfrm )
 
745
{
 
746
    float     d;
 
747
    short int s;
 
748
 
 
749
    while (nfrm--)
 
750
    {
 
751
        s = *((short int *) src);
 
752
        d = (float) s / 0x7fff;  
 
753
        *dst++ = d;  
 
754
        src += step;
 
755
    }  
 
756
    return src;
 
757
}
 
758
 
 
759
char *Alsa_driver::clear_24le (char *dst, int step, int nfrm)
 
760
{
 
761
    while (nfrm--)
 
762
    {
 
763
        dst [0] = 0;
 
764
        dst [1] = 0;
 
765
        dst [2] = 0;
 
766
        dst += step;
 
767
    }
 
768
    return dst;  
 
769
}
 
770
 
 
771
char *Alsa_driver::play_24le (const float *src, char *dst, int step, int nfrm)
 
772
{
 
773
    float   s;
 
774
    int     d;
 
775
 
 
776
    while (nfrm--)
 
777
    {
 
778
        s = *src++;
 
779
        if      (s >  1) d = 0x007fffff;
 
780
        else if (s < -1) d = 0x00800001;  
 
781
        else d = (int)(0x007fffff * s); 
 
782
        dst [0] = d;
 
783
        dst [1] = d >> 8;
 
784
        dst [2] = d >> 16;
 
785
        dst += step;
 
786
    }  
 
787
    return dst;
 
788
}
 
789
 
 
790
const char *Alsa_driver::capt_24le (const char *src, float *dst, int step, int nfrm)
 
791
{
 
792
    float   d;
 
793
    int     s;
 
794
 
 
795
    while (nfrm--)
 
796
    {
 
797
        s  =  src [0] & 0xFF;
 
798
        s += (src [1] & 0xFF) << 8;  
 
799
        s += (src [2] & 0xFF) << 16;
 
800
        if (s & 0x00800000) s-= 0x01000000;  
 
801
        d = (float) s / 0x007fffff;  
 
802
        *dst++ = d;  
 
803
        src += step;
 
804
    } 
 
805
    return src;
 
806
}
 
807
 
 
808
 
 
809
char *Alsa_driver::clear_32le (char *dst, int step, int nfrm)
 
810
{
 
811
    while (nfrm--)
 
812
    {
 
813
        *((int *) dst) = 0;
 
814
        dst += step;
 
815
    }
 
816
    return dst;  
 
817
}
 
818
 
 
819
char *Alsa_driver::play_32le (const float *src, char *dst, int step, int nfrm)
 
820
{
 
821
    float   s;
 
822
    int     d;
 
823
 
 
824
    while (nfrm--)
 
825
    {
 
826
        s = *src++;
 
827
        if      (s >  1) d = 0x007fffff;
 
828
        else if (s < -1) d = 0x00800001;  
 
829
        else d = (int)(0x007fffff * s); 
 
830
        *((int *) dst) = d << 8;
 
831
        dst += step;
 
832
    }  
 
833
    return dst;
 
834
}
 
835
 
 
836
const char *Alsa_driver::capt_32le (const char *src, float *dst, int step, int nfrm)
 
837
{
 
838
    float   d;
 
839
    int     s;
 
840
 
 
841
    while (nfrm--)
 
842
    {
 
843
        s = *((int *) src);
 
844
        d = (float) s / 0x7fffff00;  
 
845
        *dst++ = d;  
 
846
        src += step;
 
847
    }  
 
848
    return src;
 
849
}
 
850
 
 
851