From aaded78641babc6649cd9cfb42747f47cd72cf96 Mon Sep 17 00:00:00 2001
From: Emmanuel Milou <emmanuel.milou@savoirfairelinux.com>
Date: Thu, 21 Feb 2008 10:40:03 -0500
Subject: [PATCH] ALSA: capture and playback (Unix Read/Write) - READ COMMENTS

Not implemented yet: ringtones, dtmf

#### Recommended play devices names (alsa-project.org)
#### http://www.alsa-project.org/main/index.php/DeviceNames
Device: #default --> capture : too much noise
		     playback : glitchs
		     dmix
	#plug:front  -->  playback almost perfect
		         capture :bad audio (noise noise noise !!!)
 		         dmix not enabled
 	#plug:rear  -->  doesn't exist on my sound card (Error: unknown PCM device)
	#plug:center_lfe --> idem
	#plug:side  --> idem

If there is multiple sound cards on your system, you can select the one you prefer like that:
  plug:front:0 select the card 0, 0 refers to the number in /proc/asound/cards.
  plug:front:Intel with the name of the card
My /proc/asound/cards:
0 [Intel          ]: HDA-Intel - HDA Intel
                      HDA Intel at 0xfdff4000 irq 23

##### Device names not recommmended (alsa-project.org)
These devices maps directly to the driver devices and doesn't handle an abstraction
	plughw -->  playback almost perfect
		    capture : noise plus weird behaviour
                    dmix not enabled
        hw  -->     playback : not audible ( maybe no resampling ?? no format conversion ??)
		    capture : XRUN mode
	            dmix not enabled
---
 src/audio/audiolayer.cpp | 477 ++++++++++++++++++---------------------
 src/audio/audiolayer.h   |  22 +-
 src/audio/audiortp.cpp   |   5 +-
 3 files changed, 238 insertions(+), 266 deletions(-)

diff --git a/src/audio/audiolayer.cpp b/src/audio/audiolayer.cpp
index d892214c50..db39e5fc62 100644
--- a/src/audio/audiolayer.cpp
+++ b/src/audio/audiolayer.cpp
@@ -29,7 +29,9 @@
 #include "../manager.h"
 #include "../user_cfg.h"
 
-#define PCM_NAME_DEFAULT  "plughw:0,0"
+#define PCM_NAME_DEFAULT  "default"
+#define PCM_PAUSE 1
+#define PCM_RESUME  0
 
 #ifdef SFL_TEST_SINE
 #include <cmath>
@@ -41,9 +43,12 @@
   , _micRingBuffer(SIZEBUF)
     , _defaultVolume(100)
   , _errorMessage("")
-    , _manager(manager)
+  , _manager(manager)
+  , _playback_handle( NULL )
+  , _capture_handle( NULL )
+    , device_closed( true )
 {
-  _sampleRate = 8000;
+  //_sampleRate = 8000;
 
   _inChannel  = 1; // don't put in stereo
   _outChannel = 1; // don't put in stereo
@@ -65,33 +70,26 @@
 // Destructor
 AudioLayer::~AudioLayer (void) 
 { 
-  if(_playback_handle != NULL) {
-    close_alsa();
-    _playback_handle = NULL ;
+  device_closed = true;
+  if(_capture_handle){
+    snd_pcm_drop( _capture_handle );
+    snd_pcm_close( _capture_handle );
+    _capture_handle = 0;
+  }
+  if(_playback_handle){
+    snd_pcm_drop( _playback_handle );
+    snd_pcm_close( _playback_handle );
+    _playback_handle = 0;
   }
 #ifdef SFL_TEST_SINE
   delete [] table_;
 #endif
 }
 
-  void
-AudioLayer::close_alsa (void) 
-{
-  _debug(" Alsa close stream \n");
-  //ost::MutexLock guard(_mutex);
-  snd_pcm_close(_playback_handle);
-}
-
-bool
-AudioLayer::hasStream(void) {
-  ost::MutexLock guard(_mutex);
-  return (_playback_handle!=0 ? true : false); 
-}
 
-  void
+  bool 
 AudioLayer::openDevice (int indexIn, int indexOut, int sampleRate, int frameSize) 
 {
-
   _indexIn = indexIn;
   _indexOut = indexOut;
   _sampleRate = sampleRate;
@@ -102,98 +100,11 @@ AudioLayer::openDevice (int indexIn, int indexOut, int sampleRate, int frameSize
   _debug("                   : sample rate=%5d, format=%s\n", _sampleRate, SFLPortaudioFormatString);
   _debug("                   : frame per buffer=%d\n", FRAME_PER_BUFFER);
 
-  // Name of the PCM device
+  ost::MutexLock guard( _mutex );
   // TODO: Must be dynamic
-
-  // TODO: capture
-  // Capture stream
-  snd_pcm_stream_t capture_stream = SND_PCM_STREAM_CAPTURE;
-
-  // Open the playback device
-  open_playback_device(PCM_NAME_DEFAULT);
-
-  // Set up the parameters required to open a device:
-  init_hw_parameters();
-
-  device_info();
-
-  //ost::MutexLock guard(_mutex);
-}
-
-void 
-AudioLayer::open_playback_device(std::string pcm_name)
-{
-  // Playback stream
-  snd_pcm_stream_t playback_stream = SND_PCM_STREAM_PLAYBACK;
-
-  if(snd_pcm_open(&_playback_handle, pcm_name.c_str(),  playback_stream, SND_PCM_NONBLOCK) < 0){
-    _debug(" Error while opening PCM device %s\n", pcm_name.c_str());
-  }
-  else
-    _debug(" Device %s successfully opened. \n", pcm_name.c_str());
-}
-
-void
-AudioLayer::init_hw_parameters(  )
-{
-  int periods = 2;
-  snd_pcm_uframes_t periodSize = 8192;
-  unsigned int sr = 44100; //(unsigned int)sampleRate;
-
-  // Information about the hardware
-  snd_pcm_hw_params_t *hwparams;
-  // Allocate the struct on the stack
-  snd_pcm_hw_params_alloca( &hwparams );
-  // Allocate memory space
-  if(snd_pcm_hw_params_malloc( &hwparams) < 0)
-    _debug(" can not allocate hardware paramater structure. \n");
-  // Init hwparams with full configuration space
-  if(snd_pcm_hw_params_any(_playback_handle, hwparams) < 0){
-    _debug(" Can not configure this PCM device .\n");  
-  }
-  // Set access type
-  if(snd_pcm_hw_params_set_access( _playback_handle , hwparams , SND_PCM_ACCESS_RW_INTERLEAVED ) <0){
-    _debug(" Error setting access. \n");
-  }
-  // Set sample format 
-  if(snd_pcm_hw_params_set_format( _playback_handle, hwparams , SND_PCM_FORMAT_S16_LE) < 0 ){
-    _debug(" Error setting format. \n");
-  }
-  // Set sample rate
-  if(snd_pcm_hw_params_set_rate_near( _playback_handle, hwparams, &sr, 0 ) <0 ) {
-    _debug(" Error setting sample rate. \n");
-  }
-  if(_sampleRate != sr)
-    _debug(" The rate %i Hz is not supported by your hardware.\n ==> Using %i Hz instead. \n", _sampleRate, sr);
-  // Set number of channels
-  if (snd_pcm_hw_params_set_channels( _playback_handle, hwparams, _inChannel) < 0) 
-    _debug(" Error setting channels. \n");
-  // Set number of periods
-  if (snd_pcm_hw_params_set_periods( _playback_handle, hwparams, periods, 0) < 0)
-    _debug(" Error setting periods. \n ");
-  // Set buffer size
-  if(snd_pcm_hw_params_set_buffer_size( _playback_handle, hwparams,  (periodSize * periods) >>2) < 0 )
-    _debug(" Error setting buffer size. \n ");
-  // Apply hardware parameters to the device
-  if(snd_pcm_hw_params( _playback_handle, hwparams) < 0 )
-    _debug(" Error setting HW params. \n ");
-
+  return open_device( PCM_NAME_DEFAULT );
 }
 
-int
-AudioLayer::device_info( void )
-{
-  /*snd_pcm_info_t *info;
-  if(snd_pcm_info( _playback_handle , info) <0 ) {
-    _debug(" Can not gather infos on opened device. \n");  
-    return 0;
-  }
-  else{*/
-      return 1;
- // }    
-}
-
-
   int
 AudioLayer::getDeviceCount()
 {
@@ -204,232 +115,292 @@ AudioLayer::getDeviceCount()
   void
 AudioLayer::startStream(void) 
 {
-
-  snd_pcm_prepare( _playback_handle );
-  _debug(" ALSA start stream. \n");
-  if( snd_pcm_state( _playback_handle ) == SND_PCM_STATE_PREPARED )
-    snd_pcm_start( _playback_handle );
-  else
-    _debug(" Device not ready to start. \n");
-  //playSinusWave();
+  // STATE PREPARED
+  ost::MutexLock guard( _mutex );
+  _debug(" entry startStream() - c => %d - p => %d\n", snd_pcm_state(_capture_handle), snd_pcm_state( _playback_handle));
+  snd_pcm_start( _capture_handle ) ;
+  snd_pcm_start( _playback_handle ) ;
+  // STATE RUNNING
+  _debug(" exit startStream() - c => %d - p => %d\n", snd_pcm_state(_capture_handle), snd_pcm_state( _playback_handle));
 }
 
 
   void
 AudioLayer::stopStream(void) 
 {
-  _debug(" Alsa stop stream. \n");
-  ost::MutexLock guard(_mutex);
-  if( isStreamActive() ){
-    // tells the device to stop reading 
-    snd_pcm_drop(_playback_handle);
-    _mainSndRingBuffer.flush();
-    _urgentRingBuffer.flush();
-    _micRingBuffer.flush();
-  }
-  else
-    _debug(" Device not running. \n" );
-}
-
-  void
-AudioLayer::playSinusWave( void )
-{
-  unsigned char* data;
-  int pcmreturn, l1, l2;
-  short s1, s2;
-  int frames;
-
-  data = (unsigned char*)malloc(8192);
-  frames = 8192 >> 2;
-  for(l1 = 0; l1 < 100; l1++) {
-    for(l2 = 0; l2 < frames; l2++) {
-      s1 = (l2 % 128) * 100 - 5000;
-      s2 = (l2 % 256) * 100 - 5000;
-      data[4*l2] = (unsigned char)s1;
-      data[4*l2+1] = s1 >> 8;
-      data[4*l2+2] = (unsigned char)s2;
-      data[4*l2+3] = s2 >> 8;
-    }
-    /* Write num_frames frames from buffer data to the PCM device pointed to by pcm_handle */
-    /* writei for interleaved */
-    /* writen for non-interleaved */
-    while ((pcmreturn = snd_pcm_writei(_playback_handle, data, frames)) < 0) {
-      snd_pcm_prepare(_playback_handle);
-      _debug("<<<<<<<<<<<<<<< Buffer Underrun >>>>>>>>>>>>>>>\n");
-    }
-  }
+  ost::MutexLock guard( _mutex );
+  _debug(" entry stopStream() - c => %d - p => %d\n", snd_pcm_state(_capture_handle), snd_pcm_state( _playback_handle));
+  snd_pcm_drop( _capture_handle );
+  snd_pcm_prepare( _capture_handle );
+  snd_pcm_drop( _playback_handle );
+  snd_pcm_prepare( _playback_handle );
+  _debug(" exit stopStream() - c => %d - p => %d\n", snd_pcm_state(_capture_handle), snd_pcm_state( _playback_handle));
 }
 
 
-
-//TODO
   void
 AudioLayer::sleep(int msec) 
 {
+  //snd_pcm_wait(_playback_handle, msec);
 }
 
-//TODO
   bool
 AudioLayer::isStreamActive (void) 
 {
-  ost::MutexLock guard(_mutex);
-  if(snd_pcm_state(_playback_handle) == SND_PCM_STATE_RUNNING)
+  ost::MutexLock guard( _mutex );
+  if(!device_closed)
     return true;
   else
     return false;
 }
 
+
   int 
 AudioLayer::putMain(void* buffer, int toCopy)
 {
-  play_alsa(buffer, toCopy);
-  //ost::MutexLock guard(_mutex);
-  /*int a = _mainSndRingBuffer.AvailForPut();
-  if ( a >= toCopy ) {
-    return _mainSndRingBuffer.Put(buffer, toCopy, _defaultVolume);
-  } else {
-    _debug("Chopping sound, Ouch! RingBuffer full ?\n");
-    return _mainSndRingBuffer.Put(buffer, a, _defaultVolume);
-  }*/
+  ost::MutexLock guard( _mutex );
+  if ( _playback_handle ) 
+    write(buffer, toCopy);
   return 0;
 }
 
   void
 AudioLayer::flushMain()
 {
-  ost::MutexLock guard(_mutex);
-  _mainSndRingBuffer.flush();
 }
 
   int
 AudioLayer::putUrgent(void* buffer, int toCopy)
 {
-  ost::MutexLock guard(_mutex);
-  if ( hasStream() ) {
-    int a = _urgentRingBuffer.AvailForPut();
-    if ( a >= toCopy ) {
-      return _urgentRingBuffer.Put(buffer, toCopy, _defaultVolume);
-    } else {
-      return _urgentRingBuffer.Put(buffer, a, _defaultVolume);
-    }
-  }
+  ost::MutexLock guard( _mutex );
+  if ( _playback_handle ) 
+    //write(buffer, toCopy);
   return 0;
 }
 
   int
 AudioLayer::canGetMic()
 {
-  if ( hasStream() ) {
-    return _micRingBuffer.AvailForGet();
-  } else {
-    return 0;
+  int avail;
+  if ( _capture_handle ) {
+    avail = snd_pcm_avail_update( _capture_handle );
+    //printf("%d\n", avail ); 
+    if(avail > 0)
+      return avail;
+    else 
+      return 0;  
   }
+  else
+    return 0;
 }
 
   int 
 AudioLayer::getMic(void *buffer, int toCopy)
 {
-  if( hasStream() ) {
-    return _micRingBuffer.Get(buffer, toCopy, 100);
-  } else {
+
+  if( _capture_handle ) 
+    return read(buffer, toCopy);
+  else
     return 0;
-  }
 }
 
   void
 AudioLayer::flushMic()
 {
-  _micRingBuffer.flush();
 }
 
   bool
 AudioLayer::isStreamStopped (void) 
 {
-  ost::MutexLock guard(_mutex);
-  if(snd_pcm_state( _playback_handle ) == SND_PCM_STATE_XRUN)
-    return true;
-  else
-    return false;
+  ost::MutexLock guard( _mutex );
+  return !(is_playback_active() & is_capture_active());
 }
 
 void
 AudioLayer::toggleEchoTesting() {
-  ost::MutexLock guard(_mutex);
+  ost::MutexLock guard( _mutex );
   _echoTesting = (_echoTesting == true) ? false : true;
 }
 
-int 
-AudioLayer::audioCallback (const void *inputBuffer, void *outputBuffer, 
-    unsigned long framesPerBuffer){ 
 
-  SFLDataFormat *in  = (SFLDataFormat *) inputBuffer;
-  SFLDataFormat *out = (SFLDataFormat *) outputBuffer;
+//////////////////////////////////////////////////////////////////////////////////////////////
+/////////////////   ALSA PRIVATE FUNCTIONS   ////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////////////////
 
-  if (_echoTesting) {
-    memcpy(out, in, framesPerBuffer*sizeof(SFLDataFormat));
-    return framesPerBuffer*sizeof(SFLDataFormat);
-  }
+bool
+AudioLayer::isPlaybackActive(void) {
+  ost::MutexLock guard( _mutex );
+  if( _playback_handle )
+    return (snd_pcm_state(_playback_handle) == SND_PCM_STATE_RUNNING ? true : false); 
+  else
+    return false;
+}
 
-  int toGet; 
-  int toPut;
-  int urgentAvail; // number of data right and data left
-  int normalAvail; // number of data right and data left
-  int micAvailPut;
-  unsigned short spkrVolume = _manager->getSpkrVolume();
-  unsigned short micVolume  = _manager->getMicVolume();
-
-  // AvailForGet tell the number of chars inside the buffer
-  // framePerBuffer are the number of data for one channel (left)
-  urgentAvail = _urgentRingBuffer.AvailForGet();
-  if (urgentAvail > 0) {
-    // Urgent data (dtmf, incoming call signal) come first.		
-    toGet = (urgentAvail < (int)(framesPerBuffer * sizeof(SFLDataFormat))) ? urgentAvail : framesPerBuffer * sizeof(SFLDataFormat);
-    _urgentRingBuffer.Get(out, toGet, spkrVolume);
-    // Consume the regular one as well (same amount of bytes)
-    _mainSndRingBuffer.Discard(toGet);
-  } else {
-    AudioLoop* tone = _manager->getTelephoneTone();
-    if ( tone != 0) {
-      tone->getNext(out, framesPerBuffer, spkrVolume);
-    } else if ( (tone=_manager->getTelephoneFile()) != 0 ) {
-      tone->getNext(out, framesPerBuffer, spkrVolume);
-    } else {
-      // If nothing urgent, play the regular sound samples
-      normalAvail = _mainSndRingBuffer.AvailForGet();
-      toGet = (normalAvail < (int)(framesPerBuffer * sizeof(SFLDataFormat))) ? normalAvail : framesPerBuffer * sizeof(SFLDataFormat);
-
-      if (toGet) {
-	_mainSndRingBuffer.Get(out, toGet, spkrVolume);
-      } else {
-	bzero(out, framesPerBuffer * sizeof(SFLDataFormat));
-      }
-    }
-  }
+bool
+AudioLayer::isCaptureActive(void) {
+  ost::MutexLock guard( _mutex );
+  if( _capture_handle )
+    return (snd_pcm_state( _capture_handle) == SND_PCM_STATE_RUNNING ? true : false); 
+  else
+    return false;
+}
 
-  // Additionally handle the mic's audio stream 
-  micAvailPut = _micRingBuffer.AvailForPut();
-  toPut = (micAvailPut <= (int)(framesPerBuffer * sizeof(SFLDataFormat))) ? micAvailPut : framesPerBuffer * sizeof(SFLDataFormat);
-  //_debug("AL: Nb sample: %d char, [0]=%f [1]=%f [2]=%f\n", toPut, in[0], in[1], in[2]);
-  _micRingBuffer.Put(in, toPut, micVolume);
 
-  return toPut;
+  bool 
+AudioLayer::open_device(std::string pcm_name)
+{
+  int err;
+  snd_pcm_hw_params_t *hwparams = NULL;
+  unsigned int rate_in = _sampleRate;
+  unsigned int rate_out = _sampleRate;
+  int direction = 0;
+  snd_pcm_uframes_t period_size_in = 1024;
+  snd_pcm_uframes_t buffer_size_in = 2048;
+  snd_pcm_uframes_t period_size_out = 2048;
+  snd_pcm_uframes_t buffer_size_out = 4096;
+  snd_pcm_sw_params_t *swparams = NULL;
+
+  _debug(" Opening capture device %s\n", pcm_name.c_str());
+  if(err = snd_pcm_open(&_capture_handle, pcm_name.c_str(),  SND_PCM_STREAM_CAPTURE, SND_PCM_NONBLOCK) < 0){
+    _debug(" Error while opening capture device %s (%s)\n", pcm_name.c_str(), snd_strerror(err));
+    return false;
+  }
+  if( err = snd_pcm_hw_params_malloc( &hwparams ) < 0 ) {
+    _debug(" Cannot allocate hardware parameter structure (%s)\n", snd_strerror(err));
+    return false;
+  }
+  if( err = snd_pcm_hw_params_any(_capture_handle, hwparams) < 0) _debug(" Cannot initialize hardware parameter structure (%s)\n", snd_strerror(err));
+  if( err = snd_pcm_hw_params_set_access( _capture_handle, hwparams, SND_PCM_ACCESS_RW_INTERLEAVED) < 0) _debug(" Cannot set access type (%s)\n", snd_strerror(err));
+  if( err = snd_pcm_hw_params_set_format( _capture_handle, hwparams, SND_PCM_FORMAT_S16_LE) < 0) _debug(" Cannot set sample format (%s)\n", snd_strerror(err));
+  if( err = snd_pcm_hw_params_set_rate_near( _capture_handle, hwparams, &rate_in, &direction) < 0) _debug(" Cannot set sample rate (%s)\n", snd_strerror(err));
+  if( err = snd_pcm_hw_params_set_channels( _capture_handle, hwparams, 1) < 0) _debug(" Cannot set channel count (%s)\n", snd_strerror(err));
+  if( err = snd_pcm_hw_params_set_period_size_near( _capture_handle, hwparams, &period_size_out , &direction) < 0) _debug(" Cannot set period size (%s)\n", snd_strerror(err));
+  if( err = snd_pcm_hw_params_set_buffer_size_near( _capture_handle, hwparams, &buffer_size_out ) < 0) _debug(" Cannot set buffer size (%s)\n", snd_strerror(err));
+  if( err = snd_pcm_hw_params( _capture_handle, hwparams ) < 0) _debug(" Cannot set hw parameters (%s)\n", snd_strerror(err));
+  snd_pcm_hw_params_free( hwparams );
+
+
+  _debug(" Opening playback device %s\n", pcm_name.c_str());
+  if(err = snd_pcm_open(&_playback_handle, pcm_name.c_str(),  SND_PCM_STREAM_PLAYBACK, SND_PCM_NONBLOCK) < 0){
+    _debug(" Error while opening playback device %s (%s)\n", pcm_name.c_str(), snd_strerror(err));
+    return false;
+  }
+  if( err = snd_pcm_hw_params_malloc( &hwparams ) < 0 ) {
+    _debug(" Cannot allocate hardware parameter structure (%s)\n", snd_strerror(err));
+    return false;
+  }
+  if( err = snd_pcm_hw_params_any( _playback_handle, hwparams) < 0) _debug(" Cannot initialize hardware parameter structure (%s)\n", snd_strerror(err));
+  if( err = snd_pcm_hw_params_set_access( _playback_handle, hwparams, SND_PCM_ACCESS_RW_INTERLEAVED) < 0) _debug(" Cannot set access type (%s)\n", snd_strerror(err));
+  if( err = snd_pcm_hw_params_set_format( _playback_handle, hwparams, SND_PCM_FORMAT_S16_LE) < 0) _debug(" Cannot set sample format (%s)\n", snd_strerror(err));
+  if( err = snd_pcm_hw_params_set_rate_near( _playback_handle, hwparams, &rate_out, &direction) < 0) _debug(" Cannot set sample rate (%s)\n", snd_strerror(err));
+  if( err = snd_pcm_hw_params_set_channels( _playback_handle, hwparams, 1) < 0) _debug(" Cannot set channel count (%s)\n", snd_strerror(err));
+  if( err = snd_pcm_hw_params_set_period_size_near( _playback_handle, hwparams, &period_size_out , &direction) < 0) _debug(" Cannot set period size (%s)\n", snd_strerror(err));
+  if( err = snd_pcm_hw_params_set_buffer_size_near( _playback_handle, hwparams, &buffer_size_out ) < 0) _debug(" Cannot set buffer size (%s)\n", snd_strerror(err));
+  if( err = snd_pcm_hw_params( _playback_handle, hwparams ) < 0) _debug(" Cannot set hw parameters (%s)\n", snd_strerror(err));
+  snd_pcm_hw_params_free( hwparams );
+
+  snd_pcm_uframes_t val;
+  snd_pcm_sw_params_alloca( &swparams );
+  snd_pcm_sw_params_current( _playback_handle, swparams );
+
+  if( err = snd_pcm_sw_params_get_start_threshold( swparams, &val ) < 0 ) _debug(" Cannot get start threshold (%s)\n", snd_strerror(err)); 
+  if( err = snd_pcm_sw_params_get_stop_threshold( swparams, &val ) < 0 ) _debug(" Cannot get stop threshold (%s)\n", snd_strerror(err)); 
+  if( err = snd_pcm_sw_params_get_boundary( swparams, &val ) < 0 ) _debug(" Cannot get boundary (%s)\n", snd_strerror(err)); 
+  if( err = snd_pcm_sw_params_set_silence_threshold( _playback_handle, swparams, 0 ) < 0 ) _debug(" Cannot set silence threshold (%s)\n", snd_strerror(err)); 
+  if( err = snd_pcm_sw_params_set_silence_size( _playback_handle, swparams, 0 ) < 0 ) _debug(" Cannot set silence size (%s)\n", snd_strerror(err)); 
+  if( err = snd_pcm_sw_params( _playback_handle, swparams ) < 0 ) _debug(" Cannot set sw parameters (%s)\n", snd_strerror(err)); 
+
+  device_closed = false;
+
+  return true;
+}
+
+  bool 
+AudioLayer::is_playback_active( void )
+{
+  if(snd_pcm_state(_playback_handle) == SND_PCM_STATE_RUNNING)
+    return true;
+  else
+    return false;
 }
 
+  bool
+AudioLayer::is_capture_active( void )
+{
+  if(snd_pcm_state(_capture_handle) == SND_PCM_STATE_RUNNING)
+    return true;
+  else
+    return false;
+}
 
 
   int
-AudioLayer::play_alsa(void* buffer, int length)
+AudioLayer::write(void* buffer, int length)
 {
-  if(_playback_handle == NULL)
+  if(device_closed || _playback_handle == NULL)
     return 0;
 
+  int bytes;
+
   snd_pcm_uframes_t frames = snd_pcm_bytes_to_frames( _playback_handle, length);
-  snd_pcm_prepare( _playback_handle );
-  if( snd_pcm_writei( _playback_handle, buffer, frames) < 0){
+  if( bytes = snd_pcm_writei( _playback_handle, buffer, frames) < 0 ) {
     snd_pcm_prepare( _playback_handle );
-    _debug(" Buffer underrun!!!\n");
+    _debug(" Playback error (%s)\n", snd_strerror(bytes));
     return 0;
   }
   return 1;
 }
 
+  int
+AudioLayer::read( void* target_buffer, int toCopy)
+{
+  if(device_closed || _capture_handle == NULL)
+    return 0;
+
+  int bytes;
+  snd_pcm_uframes_t frames = snd_pcm_bytes_to_frames( _capture_handle, toCopy);
+  if( bytes = snd_pcm_readi( _capture_handle, target_buffer, frames) < 0 ) {
+    int err = bytes;
+    switch(err){
+      case EPERM:
+	_debug(" Capture EPERM (%s)\n", snd_strerror(bytes));
+	handle_xrun_state();
+	break;
+      case -ESTRPIPE:
+	_debug(" Capture ESTRPIPE (%s)\n", snd_strerror(bytes));
+	snd_pcm_resume( _capture_handle);
+	break;
+      case -EAGAIN:
+	_debug(" Capture EAGAIN (%s)\n", snd_strerror(bytes));
+	break;
+      case -EBADFD:
+	_debug(" Capture EBADFD (%s)\n", snd_strerror(bytes));
+	break;
+      case -EPIPE:
+	_debug(" Capture EPIPE (%s)\n", snd_strerror(bytes));
+	handle_xrun_state();
+	break;
+    }
+    return 0;
+  }
+  return toCopy;
+}
+
+
+  void
+AudioLayer::handle_xrun_state( void )
+{
+  snd_pcm_status_t* status;
+  snd_pcm_status_alloca( &status );
+
+  int res = snd_pcm_status( _capture_handle, status );
+  if( res <= 0){
+    if(snd_pcm_status_get_state(status) == SND_PCM_STATE_XRUN ){
+      snd_pcm_drop( _capture_handle );
+      snd_pcm_prepare( _capture_handle );
+      snd_pcm_start( _capture_handle ); 
+    }
+  }
+  else
+    _debug(" Get status failed\n");
+}
diff --git a/src/audio/audiolayer.h b/src/audio/audiolayer.h
index 973eb6856f..09c8408e22 100644
--- a/src/audio/audiolayer.h
+++ b/src/audio/audiolayer.h
@@ -48,13 +48,15 @@ class AudioLayer {
      * @param sampleRate
      * @param frameSize
      */
-    void openDevice(int, int, int, int);
+    bool openDevice(int, int, int, int);
     void startStream(void);
     void stopStream(void);
     void sleep(int);
-    bool hasStream(void);
+    bool isPlaybackActive( void );
+    bool isCaptureActive( void );
     bool isStreamActive(void);
     bool isStreamStopped(void);
+    void closeStream();
 
     void flushMain();
     int putMain(void* buffer, int toCopy);
@@ -99,24 +101,22 @@ class AudioLayer {
     void toggleEchoTesting();
 
   private:
-    void close_alsa (void);
-    int play_alsa( void* , int );
-    int device_info( void );
-    void init_hw_parameters( void );
-    void open_playback_device( std::string ); 
+    bool open_device( std::string ); 
+    int write( void* , int );
+    int read( void*, int );
+    bool is_playback_active( void );
+    bool is_capture_active( void );
+    void handle_xrun_state( void );
     RingBuffer _urgentRingBuffer;
     RingBuffer _mainSndRingBuffer;
     RingBuffer _micRingBuffer;
     ManagerImpl* _manager; // augment coupling, reduce indirect access
     // a audiolayer can't live without manager
 
-    //portaudio::MemFunCallbackStream<AudioLayer> *_stream;
-
     snd_pcm_t* _playback_handle;
-    snd_pcm_state_t* playback_state;
     snd_pcm_t* _capture_handle;
+    bool device_closed;
 
-    int playback_callback(snd_pcm_sframes_t nframes);
     /**
      * Portaudio indexes of audio devices on which stream has been opened 
      */
diff --git a/src/audio/audiortp.cpp b/src/audio/audiortp.cpp
index 58cb4fcb7a..393faa799b 100644
--- a/src/audio/audiortp.cpp
+++ b/src/audio/audiortp.cpp
@@ -318,9 +318,11 @@ try {
 	int maxBytesToGet = _layerSampleRate * _layerFrameSize * sizeof(SFLDataFormat) / 1000;
 	// available bytes inside ringbuffer
 	int availBytesFromMic = audiolayer->canGetMic();
+	//printf("%i \n", availBytesFromMic);
 
 	// take the lowest
 	int bytesAvail = (availBytesFromMic < maxBytesToGet) ? availBytesFromMic : maxBytesToGet;
+	//printf("%i\n", bytesAvail);
 	// Get bytes from micRingBuffer to data_from_mic
 	int nbSample = audiolayer->getMic(_dataAudioLayer, bytesAvail) / sizeof(SFLDataFormat);
 	int nb_sample_up = nbSample;
@@ -427,7 +429,6 @@ try {
 
 
 		audiolayer->putMain(toAudioLayer, nbSample * sizeof(SFLDataFormat));
-
 		// Notify (with a beep) an incoming call when there is already a call 
 		countTime += time->getSecond();
 		if (Manager::instance().incomingCallWaiting() > 0) {
@@ -543,7 +544,7 @@ try {
 	int countTime = 0; // for receive
 	TimerPort::setTimer(_layerFrameSize);
 
-	audiolayer->flushMic();
+	//audiolayer->flushMic();
 	audiolayer->startStream();
 	_start.post();
 	_debug("- ARTP Action: Start\n");
-- 
GitLab