alsalayer.cpp 23.6 KB
Newer Older
1
/*
2
 *  Copyright (C) 2008 2009 Savoir-Faire Linux inc.
3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
 *  Author: Emmanuel Milou <emmanuel.milou@savoirfairelinux.com>
 *
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; either version 3 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program; if not, write to the Free Software
 *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 */

#include "alsalayer.h"

22 23
#include "managerimpl.h"

24 25
int framesPerBufferAlsa = 2048;

26
// Constructor
27 28 29 30 31 32 33 34 35
AlsaLayer::AlsaLayer (ManagerImpl* manager)
        : AudioLayer (manager , ALSA)
        , _PlaybackHandle (NULL)
        , _CaptureHandle (NULL)
        , _periodSize()
        , _audioPlugin()
        , IDSoundCards()
        , _is_prepared_playback (false)
        , _is_prepared_capture (false)
36
        , _is_running_playback (false)
37
        , _is_running_capture (false)
38
        , _is_open_playback (false)
39 40
        , _is_open_capture (false)
        , _trigger_request (false)
41
	, _converterSamplingRate(0)
42

43
{
44
    _debug (" Constructor of AlsaLayer called\n");
45 46
    /* Instanciate the audio thread */
    _audioThread = new AudioThread (this);
47 48

    _urgentRingBuffer.createReadPointer();
49 50 51
}

// Destructor
52 53 54
AlsaLayer::~AlsaLayer (void)
{
    _debug ("Destructor of AlsaLayer called\n");
55
    closeLayer();
Alexandre Savard's avatar
Alexandre Savard committed
56

57 58 59
    if(_converter) {
	delete _converter; _converter = NULL;
    }
60 61
}

62
bool
63 64
AlsaLayer::closeLayer()
{
65 66
    _debugAlsa ("Close ALSA streams\n");

Emmanuel Milou's avatar
Emmanuel Milou committed
67
    try {
68 69 70 71
        /* Stop the audio thread first */
        if (_audioThread) {
            delete _audioThread;
            _audioThread=NULL;
Emmanuel Milou's avatar
Emmanuel Milou committed
72
        }
73 74
    } catch (...) {
        _debugException ("! ARTP Exception: when stopping audiortp\n");
Emmanuel Milou's avatar
Emmanuel Milou committed
75 76
        throw;
    }
77

Emmanuel Milou's avatar
Emmanuel Milou committed
78
    /* Then close the audio devices */
79
    closeCaptureStream();
80

81
    closePlaybackStream();
82

Emmanuel Milou's avatar
Emmanuel Milou committed
83
    _CaptureHandle = 0;
84

Emmanuel Milou's avatar
Emmanuel Milou committed
85
    _PlaybackHandle = 0;
86 87

    return true;
88
}
89

90 91
bool
AlsaLayer::openDevice (int indexIn, int indexOut, int sampleRate, int frameSize, int stream , std::string plugin)
92
{
93 94
    /* Close the devices before open it */
    if (stream == SFL_PCM_BOTH && is_capture_open() == true && is_playback_open() == true) {
Emmanuel Milou's avatar
Emmanuel Milou committed
95 96
        closeCaptureStream();
        closePlaybackStream();
97
    } else if ( (stream == SFL_PCM_CAPTURE || stream == SFL_PCM_BOTH) && is_capture_open() == true)
Emmanuel Milou's avatar
Emmanuel Milou committed
98
        closeCaptureStream ();
99
    else if ( (stream == SFL_PCM_PLAYBACK || stream == SFL_PCM_BOTH) && is_playback_open () == true)
Emmanuel Milou's avatar
Emmanuel Milou committed
100 101
        closePlaybackStream ();

102

103
    _indexIn = indexIn;
104

105
    _indexOut = indexOut;
106

107
    _audioSampleRate = sampleRate;
108 109 110

    _frameSize = frameSize;

111 112
    _audioPlugin = plugin;

113
    _debugAlsa (" Setting AlsaLayer: device     in=%2d, out=%2d\n", _indexIn, _indexOut);
114

115
    _debugAlsa ("                   : alsa plugin=%s\n", _audioPlugin.c_str());
116

117 118
    _debugAlsa ("                   : nb channel in=%2d, out=%2d\n", _inChannel, _outChannel);

119
    _debugAlsa ("                   : sample rate=%5d, format=%s\n", _audioSampleRate, SFLDataFormatString);
120 121 122

    ost::MutexLock lock (_mutex);

123
    std::string pcmp = buildDeviceTopo (plugin, indexOut, 0);
124

125
    std::string pcmc = buildDeviceTopo (PCM_PLUGHW, indexIn, 0);
126

127
    _converter = new SamplerateConverter (_audioSampleRate, _frameSize);
Alexandre Savard's avatar
Alexandre Savard committed
128

129
    return open_device (pcmp, pcmc, stream);
130 131
}

132 133
void
AlsaLayer::startStream (void)
134
{
Emmanuel Milou's avatar
Emmanuel Milou committed
135 136 137 138
    _debug ("Start ALSA streams\n");
    prepareCaptureStream ();
    startCaptureStream ();
    startPlaybackStream ();
Emmanuel Milou's avatar
Emmanuel Milou committed
139

140 141 142 143
    _urgentRingBuffer.flush();
    _mainBuffer.flush();
    _mainBuffer.flushDefault();

144
}
145

146 147
void
AlsaLayer::stopStream (void)
148
{
Alexandre Savard's avatar
Alexandre Savard committed
149
    _debug ("AlsaLayer::stopStream :: Stop ALSA streams\n");
Emmanuel Milou's avatar
Emmanuel Milou committed
150 151
    stopCaptureStream ();
    //stopPlaybackStream ();
152

Emmanuel Milou's avatar
Emmanuel Milou committed
153
    /* Flush the ring buffers */
Emmanuel Milou's avatar
Emmanuel Milou committed
154 155 156
    flushUrgent ();
    flushMain ();
    flushMic ();
157 158
}

159
int
160
AlsaLayer::canGetMic()
161
{
162

163
    /*
164 165 166 167 168 169 170
    int avail;

    if (!_CaptureHandle)
        return 0;

    avail = snd_pcm_avail_update (_CaptureHandle);

171
    if (avail == -EPIPE) {
172 173
        stop_capture ();
        return 0;
174 175
    } else
        return ( (avail<0) ?0:avail);
176

177
    if(_CaptureHandle)
178

Emmanuel Milou's avatar
Emmanuel Milou committed
179
        return _micRingBuffer.AvailForGet();
180
    else
181
        return 0;*/
182 183

    return 0;
184 185
}

186 187
int
AlsaLayer::getMic (void *buffer, int toCopy)
188
{
189
    /*
Emmanuel Milou's avatar
Emmanuel Milou committed
190 191
    if( _CaptureHandle ){
        return _micRingBuffer.Get(buffer, toCopy,100);
192
    }
Emmanuel Milou's avatar
Emmanuel Milou committed
193
    else
194
        return 0;
195 196 197 198 199 200 201
    int res = 0;

    if (_CaptureHandle) {
        res = read (buffer, toCopy);
        adjustVolume (buffer, toCopy, SFL_PCM_CAPTURE);
    }

202 203
    return res;*/

204
    return 0;
Emmanuel Milou's avatar
Emmanuel Milou committed
205 206
}

207 208 209 210 211 212
bool AlsaLayer::isCaptureActive (void)
{
    ost::MutexLock guard (_mutex);

    if (_CaptureHandle)
        return (snd_pcm_state (_CaptureHandle) == SND_PCM_STATE_RUNNING ? true : false);
Emmanuel Milou's avatar
Emmanuel Milou committed
213 214
    else
        return false;
215 216 217 218 219
}

//////////////////////////////////////////////////////////////////////////////////////////////
/////////////////   ALSA PRIVATE FUNCTIONS   ////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////
220

Emmanuel Milou's avatar
Emmanuel Milou committed
221 222
void AlsaLayer::stopCaptureStream (void)
{
223
    int err;
Alexandre Savard's avatar
Alexandre Savard committed
224

225
    if (_CaptureHandle) {
Alexandre Savard's avatar
Alexandre Savard committed
226
        err = snd_pcm_drop (_CaptureHandle);
227

Emmanuel Milou's avatar
Emmanuel Milou committed
228
        stop_capture ();
229

Emmanuel Milou's avatar
Emmanuel Milou committed
230 231
    }
}
232

Emmanuel Milou's avatar
Emmanuel Milou committed
233 234
void AlsaLayer::closeCaptureStream (void)
{
235
    if (is_capture_prepared() == true && is_capture_running() == true)
Emmanuel Milou's avatar
Emmanuel Milou committed
236
        stopCaptureStream ();
237

Emmanuel Milou's avatar
Emmanuel Milou committed
238 239 240 241
    if (is_capture_open())
        snd_pcm_close (_CaptureHandle);

    close_capture ();
242 243
}

Emmanuel Milou's avatar
Emmanuel Milou committed
244 245
void AlsaLayer::startCaptureStream (void)
{
246 247
    if (_CaptureHandle) {
        _debug ("Start the capture\n");
Emmanuel Milou's avatar
Emmanuel Milou committed
248 249 250 251 252 253 254
        snd_pcm_start (_CaptureHandle);
        start_capture();
    }
}

void AlsaLayer::prepareCaptureStream (void)
{
255 256 257
    if (is_capture_open()) {
        if (snd_pcm_prepare (_CaptureHandle) < 0)
            _debug ("");
258 259
        else
            prepare_capture ();
260
    }
Emmanuel Milou's avatar
Emmanuel Milou committed
261 262 263 264
}

void AlsaLayer::stopPlaybackStream (void)
{
265
    if (_PlaybackHandle) {
Emmanuel Milou's avatar
Emmanuel Milou committed
266 267 268 269 270 271 272 273
        snd_pcm_drop (_PlaybackHandle);
        stop_playback ();
    }
}


void AlsaLayer::closePlaybackStream (void)
{
274
    if (is_playback_prepared() == true && is_playback_running() == true)
Emmanuel Milou's avatar
Emmanuel Milou committed
275
        stopPlaybackStream ();
276 277

    if (is_playback_open())
Emmanuel Milou's avatar
Emmanuel Milou committed
278 279 280 281 282 283 284
        snd_pcm_close (_PlaybackHandle);

    close_playback ();
}

void AlsaLayer::startPlaybackStream (void)
{
285
    if (_PlaybackHandle) {
Emmanuel Milou's avatar
Emmanuel Milou committed
286 287 288 289 290 291 292
        snd_pcm_start (_PlaybackHandle);
        start_playback();
    }
}

void AlsaLayer::preparePlaybackStream (void)
{
293 294 295
    if (is_playback_open()) {
        if (snd_pcm_prepare (_PlaybackHandle) < 0)  _debug ("Error preparing the device\n");

296 297
        prepare_playback ();
    }
298 299
}

300 301
bool AlsaLayer::alsa_set_params (snd_pcm_t *pcm_handle, int type, int rate)
{
302

303 304 305 306 307 308 309 310 311 312 313
    snd_pcm_hw_params_t *hwparams = NULL;
    snd_pcm_sw_params_t *swparams = NULL;
    unsigned int exact_ivalue;
    unsigned long exact_lvalue;
    int dir;
    int err;
    int format;
    int periods = 4;
    int periodsize = 1024;

    /* Allocate the snd_pcm_hw_params_t struct */
314
    snd_pcm_hw_params_malloc (&hwparams);
315

Yun Liu's avatar
Yun Liu committed
316
    _periodSize = 940;
317
    /* Full configuration space */
318 319 320

    if ( (err = snd_pcm_hw_params_any (pcm_handle, hwparams)) < 0) {
        _debugAlsa (" Cannot initialize hardware parameter structure (%s)\n", snd_strerror (err));
321 322 323
        return false;
    }

324 325
    if ( (err = snd_pcm_hw_params_set_access (pcm_handle, hwparams, SND_PCM_ACCESS_RW_INTERLEAVED)) < 0) {
        _debugAlsa (" Cannot set access type (%s)\n", snd_strerror (err));
326 327 328 329 330
        return false;
    }

    /* Set sample format */
    format = SND_PCM_FORMAT_S16_LE;
331 332 333

    if ( (err = snd_pcm_hw_params_set_format (pcm_handle, hwparams, (snd_pcm_format_t) format)) < 0) {
        _debugAlsa (" Cannot set sample format (%s)\n", snd_strerror (err));
334 335
        return false;
    }
336

337 338
    /* Set sample rate. If we can't set to the desired exact value, we set to the nearest acceptable */
    dir=0;
339

340
    rate = getSampleRate();
341

342
    exact_ivalue = rate;
343 344 345

    if ( (err = snd_pcm_hw_params_set_rate_near (pcm_handle, hwparams, &exact_ivalue, &dir) < 0)) {
        _debugAlsa (" Cannot set sample rate (%s)\n", snd_strerror (err));
346 347
        return false;
    }
348 349 350

    if (dir!= 0) {
        _debugAlsa (" (%i) The choosen rate %d Hz is not supported by your hardware.\nUsing %d Hz instead.\n ",type ,rate, exact_ivalue);
351
    }
352

353
    /* Set the number of channels */
354 355
    if ( (err = snd_pcm_hw_params_set_channels (pcm_handle, hwparams, 1)) < 0) {
        _debugAlsa (" Cannot set channel count (%s)\n", snd_strerror (err));
356 357
        return false;
    }
358

359 360
    /* Set the buffer size in frames */
    exact_lvalue = periodsize;
361

362
    dir=0;
363 364 365

    if ( (err = snd_pcm_hw_params_set_period_size_near (pcm_handle, hwparams, &exact_lvalue , &dir)) < 0) {
        _debugAlsa (" Cannot set period time (%s)\n", snd_strerror (err));
366 367
        return false;
    }
368 369 370

    if (dir!=0) {
        _debugAlsa ("(%i) The choosen period size %d bytes is not supported by your hardware.\nUsing %d instead.\n ", type, (int) periodsize, (int) exact_lvalue);
371
    }
372

Yun Liu's avatar
Yun Liu committed
373
    periodsize = exact_lvalue;
374

375
    _periodSize = exact_lvalue;
376 377 378
    /* Set the number of fragments */
    exact_ivalue = periods;
    dir=0;
379 380 381

    if ( (err = snd_pcm_hw_params_set_periods_near (pcm_handle, hwparams, &exact_ivalue, &dir)) < 0) {
        _debugAlsa (" Cannot set periods number (%s)\n", snd_strerror (err));
382
        return false;
383
    }
384 385 386

    if (dir!=0) {
        _debugAlsa (" The choosen period number %i bytes is not supported by your hardware.\nUsing %i instead.\n ", periods, exact_ivalue);
387
    }
388

389
    periods=exact_ivalue;
390

391
    /* Set the hw parameters */
392 393 394

    if ( (err = snd_pcm_hw_params (pcm_handle, hwparams)) < 0) {
        _debugAlsa (" Cannot set hw parameters (%s)\n", snd_strerror (err));
395 396
        return false;
    }
397

398
    snd_pcm_hw_params_free (hwparams);
399

400
    /* Set the sw parameters */
401 402
    snd_pcm_sw_params_malloc (&swparams);
    snd_pcm_sw_params_current (pcm_handle, swparams);
403

404
    /* Set the start threshold */
405 406 407

    if ( (err = snd_pcm_sw_params_set_start_threshold (pcm_handle, swparams, 2700 /*periodsize*2*/)) < 0) {
        _debugAlsa (" Cannot set start threshold (%s)\n", snd_strerror (err));
408 409
        return false;
    }
410 411 412

    if ( (err = snd_pcm_sw_params (pcm_handle, swparams)) < 0) {
        _debugAlsa (" Cannot set sw parameters (%s)\n", snd_strerror (err));
413 414
        return false;
    }
415

416

417
    snd_pcm_sw_params_free (swparams);
418

419 420 421 422
    return true;
}


423 424
bool
AlsaLayer::open_device (std::string pcm_p, std::string pcm_c, int flag)
425 426 427
{

    int err;
428 429 430 431 432 433

    if (flag == SFL_PCM_BOTH || flag == SFL_PCM_PLAYBACK) {
        // if((err = snd_pcm_open(&_PlaybackHandle, pcm_p.c_str(),  SND_PCM_STREAM_PLAYBACK, 0 )) < 0){
        if ( (err = snd_pcm_open (&_PlaybackHandle, pcm_p.c_str(),  SND_PCM_STREAM_PLAYBACK, 0)) < 0) {
            _debugAlsa ("Error while opening playback device %s\n",  pcm_p.c_str());
            setErrorMessage (ALSA_PLAYBACK_DEVICE);
434
            close_playback ();
435 436
            return false;
        }
437 438 439 440

        if (!alsa_set_params (_PlaybackHandle, 1, getSampleRate())) {
            _debug ("playback failed\n");
            snd_pcm_close (_PlaybackHandle);
441
            close_playback ();
442 443
            return false;
        }
Emmanuel Milou's avatar
Emmanuel Milou committed
444 445

        open_playback ();
446 447
    }

448 449 450 451
    if (flag == SFL_PCM_BOTH || flag == SFL_PCM_CAPTURE) {
        if ( (err = snd_pcm_open (&_CaptureHandle,  pcm_c.c_str(),  SND_PCM_STREAM_CAPTURE, 0)) < 0) {
            _debugAlsa ("Error while opening capture device %s\n",  pcm_c.c_str());
            setErrorMessage (ALSA_CAPTURE_DEVICE);
452
            close_capture ();
453 454
            return false;
        }
455 456 457 458

        if (!alsa_set_params (_CaptureHandle, 0, 8000)) {
            _debug ("capture failed\n");
            snd_pcm_close (_CaptureHandle);
459
            close_capture ();
460 461
            return false;
        }
Emmanuel Milou's avatar
Emmanuel Milou committed
462 463

        open_capture ();
464

Emmanuel Milou's avatar
Emmanuel Milou committed
465
        prepare_capture ();
466 467
    }

468
    /* Start the secondary audio thread for callbacks */
469
    try {
Emmanuel Milou's avatar
Emmanuel Milou committed
470
        _audioThread->start();
471 472
    } catch (...) {
        _debugException ("Fail to start audio thread\n");
Emmanuel Milou's avatar
Emmanuel Milou committed
473
    }
474 475

    return true;
476 477 478
}

//TODO	first frame causes broken pipe (underrun) because not enough data are send --> make the handle wait to be ready
479 480
int
AlsaLayer::write (void* buffer, int length)
481
{
482
    if (_trigger_request == true) {
Emmanuel Milou's avatar
Emmanuel Milou committed
483 484
        _trigger_request = false;
        startPlaybackStream ();
485 486
    }

487 488
    snd_pcm_uframes_t frames = snd_pcm_bytes_to_frames (_PlaybackHandle, length);

Emmanuel Milou's avatar
Emmanuel Milou committed
489
    int err;
490 491 492 493 494 495 496 497 498

    if ( (err=snd_pcm_writei (_PlaybackHandle , buffer , frames)) <0) {
        switch (err) {

            case -EPIPE:

            case -ESTRPIPE:

            case -EIO:
Emmanuel Milou's avatar
Emmanuel Milou committed
499 500
                //_debugAlsa(" XRUN playback ignored (%s)\n", snd_strerror(err));
                handle_xrun_playback();
501 502

                if (snd_pcm_writei (_PlaybackHandle , buffer , frames) <0)
Emmanuel Milou's avatar
Emmanuel Milou committed
503
                    _debugAlsa ("XRUN handling failed\n");
504

Emmanuel Milou's avatar
Emmanuel Milou committed
505
                _trigger_request = true;
506

Emmanuel Milou's avatar
Emmanuel Milou committed
507
                break;
508

Emmanuel Milou's avatar
Emmanuel Milou committed
509
            default:
510
                _debugAlsa ("Write error unknown - dropping frames **********************************: %s\n", snd_strerror(err));
Emmanuel Milou's avatar
Emmanuel Milou committed
511
                stopPlaybackStream ();
512

Emmanuel Milou's avatar
Emmanuel Milou committed
513 514 515
                break;
        }
    }
516

517
    return (err > 0) ? err : 0 ;
518 519
}

520 521
int
AlsaLayer::read (void* buffer, int toCopy)
522
{
Emmanuel Milou's avatar
Emmanuel Milou committed
523
    //ost::MutexLock lock( _mutex );
524

Emmanuel Milou's avatar
Emmanuel Milou committed
525
    int samples;
526

527
    if (snd_pcm_state (_CaptureHandle) == SND_PCM_STATE_XRUN) {
Emmanuel Milou's avatar
Emmanuel Milou committed
528 529
        prepareCaptureStream ();
        startCaptureStream ();
530
    }
531 532 533 534 535 536

    snd_pcm_uframes_t frames = snd_pcm_bytes_to_frames (_CaptureHandle, toCopy);

    if ( (samples = snd_pcm_readi (_CaptureHandle, buffer, frames)) < 0) {
        switch (samples) {

537
            case -EPIPE:
538

Emmanuel Milou's avatar
Emmanuel Milou committed
539
            case -ESTRPIPE:
540

Emmanuel Milou's avatar
Emmanuel Milou committed
541
            case -EIO:
542
                _debugAlsa (" XRUN capture ignored (%s)\n", snd_strerror (samples));
543
                handle_xrun_capture();
Emmanuel Milou's avatar
Emmanuel Milou committed
544 545 546
                //samples = snd_pcm_readi( _CaptureHandle, buffer, frames);
                //if (samples<0)  samples=0;
                break;
547

Emmanuel Milou's avatar
Emmanuel Milou committed
548
            case EPERM:
549
                _debugAlsa (" Capture EPERM (%s)\n", snd_strerror (samples));
Emmanuel Milou's avatar
Emmanuel Milou committed
550 551
                prepareCaptureStream ();
                startCaptureStream ();
Emmanuel Milou's avatar
Emmanuel Milou committed
552
                break;
553

Emmanuel Milou's avatar
Emmanuel Milou committed
554
            default:
Emmanuel Milou's avatar
Emmanuel Milou committed
555
                //_debugAlsa("%s\n", snd_strerror(samples));
556 557
                break;
        }
558

559
        return 0;
560 561
    }

562
    return toCopy;
563

Yun Liu's avatar
Yun Liu committed
564
}
565

566 567
void
AlsaLayer::handle_xrun_capture (void)
568
{
569
    snd_pcm_status_t* status;
570
    snd_pcm_status_alloca (&status);
571

572 573 574 575
    int res = snd_pcm_status (_CaptureHandle, status);

    if (res <= 0) {
        if (snd_pcm_status_get_state (status) == SND_PCM_STATE_XRUN) {
576 577 578
            stopCaptureStream ();
            prepareCaptureStream ();
            startCaptureStream ();
579
        }
580 581
    } else
        _debugAlsa (" Get status failed\n");
582 583
}

584 585
void
AlsaLayer::handle_xrun_playback (void)
586
{
587
    int state;
588
    snd_pcm_status_t* status;
589
    snd_pcm_status_alloca (&status);
590

591 592 593 594 595
    if ( (state = snd_pcm_status (_PlaybackHandle, status)) < 0)   _debugAlsa (" Error: Cannot get playback handle status (%s)\n" , snd_strerror (state));
    else {
        state = snd_pcm_status_get_state (status);

        if (state  == SND_PCM_STATE_XRUN) {
Emmanuel Milou's avatar
Emmanuel Milou committed
596 597 598
            stopPlaybackStream ();
            preparePlaybackStream ();
            _trigger_request = true;
599
        }
600 601 602
    }
}

603 604
std::string
AlsaLayer::buildDeviceTopo (std::string plugin, int card, int subdevice)
605
{
606 607
    std::string pcm = plugin;
    std::stringstream ss,ss1;
608 609

    if (pcm == "default" || pcm == "pulse")
610
        return pcm;
611

612
    ss << card;
613 614 615 616 617 618 619

    pcm.append (":");

    pcm.append (ss.str());

    if (subdevice != 0) {
        pcm.append (",");
620
        ss1 << subdevice;
621
        pcm.append (ss1.str());
622
    }
623

624 625 626
    return pcm;
}

627 628
std::vector<std::string>
AlsaLayer::getSoundCardsInfo (int stream)
629
{
630 631 632 633 634 635
    std::vector<std::string> cards_id;
    HwIDPair p;

    snd_ctl_t* handle;
    snd_ctl_card_info_t *info;
    snd_pcm_info_t* pcminfo;
636 637
    snd_ctl_card_info_alloca (&info);
    snd_pcm_info_alloca (&pcminfo);
638 639 640 641

    int numCard = -1 ;
    std::string description;

642
    if (snd_card_next (&numCard) < 0 || numCard < 0)
643 644
        return cards_id;

645
    while (numCard >= 0) {
646 647 648
        std::stringstream ss;
        ss << numCard;
        std::string name= "hw:";
649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668
        name.append (ss.str());

        if (snd_ctl_open (&handle, name.c_str(), 0) == 0) {
            if (snd_ctl_card_info (handle, info) == 0) {
                snd_pcm_info_set_device (pcminfo , 0);
                snd_pcm_info_set_stream (pcminfo, (stream == SFL_PCM_CAPTURE) ? SND_PCM_STREAM_CAPTURE : SND_PCM_STREAM_PLAYBACK);

                if (snd_ctl_pcm_info (handle ,pcminfo) < 0) _debugAlsa (" Cannot get info\n");
                else {
                    _debugAlsa ("card %i : %s [%s]\n",
                                numCard,
                                snd_ctl_card_info_get_id (info),
                                snd_ctl_card_info_get_name (info));
                    description = snd_ctl_card_info_get_name (info);
                    description.append (" - ");
                    description.append (snd_pcm_info_get_name (pcminfo));
                    cards_id.push_back (description);
                    // The number of the sound card is associated with a string description
                    p = HwIDPair (numCard , description);
                    IDSoundCards.push_back (p);
669 670
                }
            }
671 672

            snd_ctl_close (handle);
673
        }
674 675

        if (snd_card_next (&numCard) < 0) {
676 677 678
            break;
        }
    }
679

680 681 682 683 684
    return cards_id;
}



685 686
bool
AlsaLayer::soundCardIndexExist (int card , int stream)
687
{
688 689
    snd_ctl_t* handle;
    snd_pcm_info_t *pcminfo;
690
    snd_pcm_info_alloca (&pcminfo);
691 692 693
    std::string name = "hw:";
    std::stringstream ss;
    ss << card ;
694 695 696 697 698 699
    name.append (ss.str());

    if (snd_ctl_open (&handle, name.c_str(), 0) == 0) {
        snd_pcm_info_set_stream (pcminfo , (stream == SFL_PCM_PLAYBACK) ? SND_PCM_STREAM_PLAYBACK : SND_PCM_STREAM_CAPTURE);

        if (snd_ctl_pcm_info (handle , pcminfo) < 0) return false;
700 701
        else
            return true;
702
    } else
703
        return false;
704
}
705

706 707
int
AlsaLayer::soundCardGetIndex (std::string description)
708
{
709
    unsigned int i;
710 711

    for (i = 0 ; i < IDSoundCards.size() ; i++) {
712
        HwIDPair p = IDSoundCards[i];
713 714

        if (p.second == description)
715 716
            return  p.first ;
    }
717

718 719
    // else return the default one
    return 0;
720 721
}

722
void AlsaLayer::audioCallback (void)
723
{
724

725
    int toGet, urgentAvailBytes, normalAvailBytes, maxBytes;
726 727 728
    unsigned short spkrVolume, micVolume;
    AudioLoop *tone;

729
    SFLDataFormat *out;
730
    SFLDataFormat *rsmpl_out;
731 732 733

    spkrVolume = _manager->getSpkrVolume();
    micVolume  = _manager->getMicVolume();
734
    
735 736 737

    // AvailForGet tell the number of chars inside the buffer
    // framePerBuffer are the number of data for one channel (left)
738 739
    urgentAvailBytes = _urgentRingBuffer.AvailForGet();
    if (urgentAvailBytes > 0) {
740

741
        // Urgent data (dtmf, incoming call signal) come first.
742
        toGet = (urgentAvailBytes < (int) (framesPerBufferAlsa * sizeof (SFLDataFormat))) ? urgentAvailBytes : framesPerBufferAlsa * sizeof (SFLDataFormat);
743 744
        out = (SFLDataFormat*) malloc (toGet * sizeof (SFLDataFormat));
        _urgentRingBuffer.Get (out, toGet, spkrVolume);
745

746
        /* Play the sound */
747
        write (out, toGet);
748

749 750
        free (out);
        out=0;
751

752
        // Consume the regular one as well (same amount of bytes)
753
        _mainBuffer.discard (toGet);
754

755
    } else {
756

757
        tone = _manager->getTelephoneTone();
758 759 760 761
        toGet = 940  ;
        maxBytes = toGet * sizeof (SFLDataFormat)  ;

        if (tone != 0) {
762

763 764
            out = (SFLDataFormat*) malloc (maxBytes * sizeof (SFLDataFormat));
            tone->getNext (out, toGet, spkrVolume);
765
            write (out , maxBytes);
766

767 768 769
	    free(out);
	    out = 0;

770
        } else if ( (tone=_manager->getTelephoneFile()) != 0) {
771

772 773
            out = (SFLDataFormat*) malloc (maxBytes * sizeof (SFLDataFormat));
            tone->getNext (out, toGet, spkrVolume);
774
            write (out , maxBytes);
775

776 777 778
	    free(out);
	    out = 0;

779
        } else {
780 781 782 783


	    // If nothing urgent, play the regular sound samples
   
784
	    int _mainBufferSampleRate = getMainBuffer()->getInternalSamplingRate();
785 786
	    int maxNbSamplesToGet = 0;
	    int maxNbBytesToGet = 0;
787

788 789
	    // Compute maximal value to get into the ring buffer
	    if (_mainBufferSampleRate && ((int)_audioSampleRate != _mainBufferSampleRate