From 35a4aa424b3b6cbff1126329c2c25f0d10065dba Mon Sep 17 00:00:00 2001
From: Emmanuel Milou <emmanuel.milou@savoirfairelinux.com>
Date: Wed, 14 May 2008 15:43:58 -0400
Subject: [PATCH] pulseaudio addons

---
 src/Makefile.am          |   3 +-
 src/audio/Makefile.am    |   2 +-
 src/audio/alsalayer.cpp  |  54 ++++++++++--------
 src/audio/audiolayer.cpp |  50 ++++++++--------
 src/audio/audiolayer.h   |   9 ++-
 src/audio/pulselayer.cpp | 119 +++++++++++++++++++++++++++++++++++----
 src/audio/pulselayer.h   |  45 ++++++++++++---
 src/global.h             |   5 ++
 src/managerimpl.cpp      |  17 +++++-
 9 files changed, 232 insertions(+), 72 deletions(-)

diff --git a/src/Makefile.am b/src/Makefile.am
index 2110acbfc9..ca7dc83f1b 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -29,6 +29,7 @@ IAXHEADERS =
 endif
 
 ALSAFLAG= -lasound
+PULSEAUDIO_LIBS=-lpulse
 
 SUBDIRS = audio config dbus $(ZEROCONFDIR) contact memmanager video mixer
 
@@ -41,7 +42,7 @@ sflphoned_SOURCES = eventthread.cpp 	main.cpp 	voiplink.cpp \
 sflphoned_CXXFLAGS = -DPREFIX=\"$(prefix)\" -DPROGSHAREDIR=\"${datadir}/sflphone\" $(ZEROCONFFLAGS) $(IAX_FLAGS) $(SFLPHONE_CFLAGS) $(SIP_CFLAGS)
 
 #sflphoned_LDFLAGS = -static
-sflphoned_LDADD =  ./libsflphone.la $(SFLPHONE_LIBS) $(ZEROCONFLIB) $(LIB_DNSSD) $(IAX_LIBS) $(EXOSIP_LIBS) $(ALSAFLAG) 
+sflphoned_LDADD =  ./libsflphone.la $(SFLPHONE_LIBS) $(ZEROCONFLIB) $(LIB_DNSSD) $(IAX_LIBS) $(EXOSIP_LIBS) $(ALSAFLAG) $(PULSEAUDIO_LIBS)
 AM_CPPFLAGS = -I$(top_srcdir)/include -I$(top_srcdir)/libs $(libccext2_CFLAGS) $(libccgnu2_CFLAGS) $(IAX_CFLAGS) $(USER_INCLUDES) $(libdbuscpp_CFLAGS) \
 	      -DCODECS_DIR=\""$(sflcodecdir)"\" 
 	      -DENABLE_TRACE
diff --git a/src/audio/Makefile.am b/src/audio/Makefile.am
index 22c0c99e45..13bb710847 100644
--- a/src/audio/Makefile.am
+++ b/src/audio/Makefile.am
@@ -28,7 +28,7 @@ tonegenerator.cpp   codecDescriptor.cpp \
 audioloop.cpp ringbuffer.cpp $(SPEEX_SOURCES_CPP)
 
 AM_CXXFLAGS = -I$(top_srcdir)/include -I$(top_srcdir)/libs $(libccext2_CFLAGS) $(libdbuscpp_CFLAGS) $(libccrtp1_CFLAGS) $(USER_INCLUDES) \
- 	      -DCODECS_DIR=\""$(sflcodecdir)"\" $(SPEEX_FLAG) $(GSM_FLAG) $(ILBC_FLAG)	
+ 	      -DCODECS_DIR=\""$(sflcodecdir)"\" $(SPEEX_FLAG) $(GSM_FLAG) $(ILBC_FLAG) 
 
 noinst_HEADERS = audioloop.h    common.h ringbuffer.h    audiofile.h  \
  tonelist.h         audiortp.h   audiolayer.h alsalayer.h  pulselayer.h audiodevice.h \
diff --git a/src/audio/alsalayer.cpp b/src/audio/alsalayer.cpp
index 44c11dcba4..1003709b01 100644
--- a/src/audio/alsalayer.cpp
+++ b/src/audio/alsalayer.cpp
@@ -21,10 +21,9 @@
 
 #include "alsalayer.h"
 
-
 // Constructor
 AlsaLayer::AlsaLayer( ManagerImpl* manager ) 
-  : AudioLayer( manager ) 
+  : AudioLayer( manager , ALSA ) 
   , _PlaybackHandle(NULL)
   , _CaptureHandle(NULL)
 {
@@ -135,7 +134,7 @@ AlsaLayer::fillHWBuffer( void)
       data[4*l2+2] = (unsigned char)s2;
       data[4*l2+3] = s2 >> 8;
     }
-    while ((pcmreturn = snd_pcm_writei(_PlaybackHandle, data, frames)) < 0) {
+    while ((pcmreturn = snd_pcm_mmap_writei(_PlaybackHandle, data, frames)) < 0) {
       snd_pcm_prepare(_PlaybackHandle);
       //_debugAlsa("< Buffer Underrun >\n");
     }
@@ -213,7 +212,6 @@ AlsaLayer::isStreamStopped (void)
   return !(isStreamActive());
 }
 
-
 //////////////////////////////////////////////////////////////////////////////////////////////
 /////////////////   ALSA PRIVATE FUNCTIONS   ////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////////////////////////////
@@ -272,8 +270,8 @@ AlsaLayer::open_device(std::string pcm_p, std::string pcm_c, int flag)
   unsigned int rate_in = getSampleRate();
   unsigned int rate_out = getSampleRate();
   int dir = 0;
-  snd_pcm_uframes_t period_size = 2048;
-  snd_pcm_uframes_t buffer_size = period_size * 4 ; 
+  snd_pcm_uframes_t period_size_in = getFrameSize() * getSampleRate() / 1000 *  2 ;
+  snd_pcm_uframes_t buffer_size_in = period_size_in * 4 ; 
   snd_pcm_uframes_t threshold = 1024 ;
   snd_pcm_uframes_t period_size_out =  getFrameSize() * getSampleRate() / 1000 *  2;//1024 ;
   snd_pcm_uframes_t buffer_size_out = period_size_out * 4 ;
@@ -301,7 +299,11 @@ AlsaLayer::open_device(std::string pcm_p, std::string pcm_c, int flag)
     if( err = snd_pcm_hw_params_set_channels( _CaptureHandle, hwParams, 1) < 0) _debugAlsa(" Cannot set channel count (%s)\n", snd_strerror(err));
     if( err = snd_pcm_hw_params_set_period_time_near( _CaptureHandle, hwParams, &period_time , &dir) < 0) _debugAlsa(" Cannot set period time (%s)\n", snd_strerror(err));
     if( err = snd_pcm_hw_params_set_buffer_time_near( _CaptureHandle, hwParams, &buffer_time , &dir) < 0) _debugAlsa(" Cannot set buffer time (%s)\n", snd_strerror(err));
+    if( err = snd_pcm_hw_params_get_period_size( hwParams, &period_size_in , &dir) < 0) _debugAlsa(" Cannot get period size (%s)\n", snd_strerror(err));
+    if( err = snd_pcm_hw_params_get_buffer_size( hwParams, &buffer_size_in ) < 0) _debugAlsa(" Cannot get buffer size (%s)\n", snd_strerror(err));
     if( err = snd_pcm_hw_params( _CaptureHandle, hwParams ) < 0) _debugAlsa(" Cannot set hw parameters (%s)\n", snd_strerror(err));
+    _debug("buffer size = %d\n" , period_size_in);
+    _debug("period size = %d\n" , buffer_size_in);
     snd_pcm_hw_params_free( hwParams );
 
     snd_pcm_uframes_t val ;
@@ -323,8 +325,8 @@ AlsaLayer::open_device(std::string pcm_p, std::string pcm_c, int flag)
   {
 
     _debugAlsa(" Opening playback device %s\n", pcm_p.c_str());
-    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());
+    if(err = snd_pcm_open(&_PlaybackHandle, pcm_p.c_str(),  SND_PCM_STREAM_PLAYBACK, SND_PCM_NONBLOCK ) < 0){
+      _debugAlsa("Error while opening playback device %s\n",  pcm_c.c_str());
       setErrorMessage( ALSA_PLAYBACK_DEVICE );
       return false;
     }
@@ -333,14 +335,15 @@ AlsaLayer::open_device(std::string pcm_p, std::string pcm_c, int flag)
       return false;
     }
     if( err = snd_pcm_hw_params_any( _PlaybackHandle,hwParams) < 0) _debugAlsa(" Cannot initialize hardware parameter structure (%s)\n", snd_strerror(err));
-    if( err = snd_pcm_hw_params_set_access( _PlaybackHandle, hwParams, SND_PCM_ACCESS_RW_INTERLEAVED) < 0) _debugAlsa(" Cannot set access type (%s)\n", snd_strerror(err));
+    if( err = snd_pcm_hw_params_set_access( _PlaybackHandle, hwParams, SND_PCM_ACCESS_MMAP_INTERLEAVED) < 0) _debugAlsa(" Cannot set access type (%s)\n", snd_strerror(err));
+    //if( err = snd_pcm_hw_params_set_access( _PlaybackHandle, hwParams, SND_PCM_ACCESS_RW_INTERLEAVED) < 0) _debugAlsa(" Cannot set access type (%s)\n", snd_strerror(err));
     if( err = snd_pcm_hw_params_set_format( _PlaybackHandle, hwParams, SND_PCM_FORMAT_S16_LE) < 0) _debugAlsa(" Cannot set sample format (%s)\n", snd_strerror(err));
     if( err = snd_pcm_hw_params_set_rate( _PlaybackHandle, hwParams, rate_out, dir) < 0) _debugAlsa(" Cannot set sample rate (%s)\n", snd_strerror(err));
     if( err = snd_pcm_hw_params_set_channels( _PlaybackHandle, hwParams, 1) < 0) _debugAlsa(" Cannot set channel count (%s)\n", snd_strerror(err));
-
-    if( err = snd_pcm_hw_params_set_buffer_size( _PlaybackHandle, hwParams, buffer_size ) < 0) _debugAlsa(" Cannot set buffer size (%s)\n", snd_strerror(err));
-    if( err = snd_pcm_hw_params_set_period_size_near( _PlaybackHandle, hwParams, &period_size , &dir) < 0) _debugAlsa(" Cannot set period size (%s)\n", snd_strerror(err));
-
+    if( err = snd_pcm_hw_params_set_buffer_time_near( _PlaybackHandle, hwParams, &buffer_time , &dir) < 0) _debugAlsa(" Cannot set buffer time (%s)\n", snd_strerror(err));
+    if( err = snd_pcm_hw_params_set_period_time_near( _PlaybackHandle, hwParams, &period_time , &dir) < 0) _debugAlsa(" Cannot set period time (%s)\n", snd_strerror(err));
+    if( err = snd_pcm_hw_params_get_period_size(  hwParams, &_periodSize , &dir) < 0) _debugAlsa(" Cannot get period size (%s)\n", snd_strerror(err));
+    if( err = snd_pcm_hw_params_get_buffer_size(  hwParams, &buffer_size_out ) < 0) _debugAlsa(" Cannot get buffer size (%s)\n", snd_strerror(err));
     if( err = snd_pcm_hw_params( _PlaybackHandle, hwParams ) < 0) _debugAlsa(" Cannot set hw parameters (%s)\n", snd_strerror(err));
 
 
@@ -366,7 +369,7 @@ AlsaLayer::open_device(std::string pcm_p, std::string pcm_c, int flag)
     if( err = snd_pcm_sw_params( _PlaybackHandle, swparams ) < 0 ) _debugAlsa(" Cannot set sw parameters (%s)\n", snd_strerror(err)); 
     snd_pcm_sw_params_free( swparams );
 
-    //if ( err = snd_async_add_pcm_handler( &_AsyncHandler, _PlaybackHandle , AlsaCallBack, this ) < 0)	_debugAlsa(" Unable to install the async callback handler (%s)\n", snd_strerror(err));
+    if ( err = snd_async_add_pcm_handler( &_AsyncHandler, _PlaybackHandle , AlsaCallBack, this ) < 0)	_debugAlsa(" Unable to install the async callback handler (%s)\n", snd_strerror(err));
     deviceClosed = false;
   }
   //fillHWBuffer();
@@ -379,26 +382,28 @@ AlsaLayer::open_device(std::string pcm_p, std::string pcm_c, int flag)
   int
 AlsaLayer::write(void* buffer, int length)
 {
+  //if(snd_pcm_state( _PlaybackHandle ) == SND_PCM_STATE_XRUN)
+  //handle_xrun_playback();  
+  //_debugAlsa("avail = %d - toWrite = %d\n" , snd_pcm_avail_update( _PlaybackHandle ) , length / 2);
+
   snd_pcm_uframes_t frames = snd_pcm_bytes_to_frames( _PlaybackHandle, length);
-  //int err = snd_pcm_mmap_writei( _PlaybackHandle , buffer , frames );
-  int err = snd_pcm_writei( _PlaybackHandle , buffer , frames );
+  int err = snd_pcm_mmap_writei( _PlaybackHandle , buffer , frames );
   switch(err) {
     case -EAGAIN: 
-      _debugAlsa("EAGAIN (%s)\n", snd_strerror( err ));
-      //snd_pcm_resume( _PlaybackHandle );
+      _debugAlsa(" (%s)\n", snd_strerror( err ));
+      snd_pcm_resume( _PlaybackHandle );
       break;
     case -EPIPE: 
       _debugAlsa(" UNDERRUN (%s)\n", snd_strerror(err));
       handle_xrun_playback();
-      //snd_pcm_mmap_writei( _PlaybackHandle , buffer , frames );
-      //snd_pcm_writei( _PlaybackHandle , buffer , frames );
+      snd_pcm_mmap_writei( _PlaybackHandle , buffer , frames );
       break;
     case -ESTRPIPE:
-      _debugAlsa("ESTRPIPE (%s)\n", snd_strerror(err));
-      //snd_pcm_resume( _PlaybackHandle );
+      _debugAlsa(" (%s)\n", snd_strerror(err));
+      snd_pcm_resume( _PlaybackHandle );
       break;
     case -EBADFD:
-      _debugAlsa("EBADFD (%s)\n", snd_strerror( err ));
+      _debugAlsa(" (%s)\n", snd_strerror( err ));
       break;
   }
 
@@ -480,8 +485,7 @@ AlsaLayer::handle_xrun_playback( void )
     state = snd_pcm_status_get_state( status );
     if( state  == SND_PCM_STATE_XRUN )
     {
-      //snd_pcm_drop( _PlaybackHandle );
-      _debug("Underrun\n");
+      snd_pcm_drop( _PlaybackHandle );
       snd_pcm_prepare( _PlaybackHandle );
       //snd_pcm_start( _PlaybackHandle ); 
     }
diff --git a/src/audio/audiolayer.cpp b/src/audio/audiolayer.cpp
index 0b0c54edb2..d799939335 100644
--- a/src/audio/audiolayer.cpp
+++ b/src/audio/audiolayer.cpp
@@ -152,7 +152,7 @@ AudioLayer::fillHWBuffer( void)
       data[4*l2+2] = (unsigned char)s2;
       data[4*l2+3] = s2 >> 8;
     }
-    while ((pcmreturn = snd_pcm_writei(_PlaybackHandle, data, frames)) < 0) {
+    while ((pcmreturn = snd_pcm_mmap_writei(_PlaybackHandle, data, frames)) < 0) {
       snd_pcm_prepare(_PlaybackHandle);
       //_debugAlsa("< Buffer Underrun >\n");
     }
@@ -295,8 +295,8 @@ AudioLayer::open_device(std::string pcm_p, std::string pcm_c, int flag)
   unsigned int rate_in = getSampleRate();
   unsigned int rate_out = getSampleRate();
   int dir = 0;
-  snd_pcm_uframes_t period_size = 2048;
-  snd_pcm_uframes_t buffer_size = period_size * 4 ; 
+  snd_pcm_uframes_t period_size_in = getFrameSize() * getSampleRate() / 1000 *  2 ;
+  snd_pcm_uframes_t buffer_size_in = period_size_in * 4 ; 
   snd_pcm_uframes_t threshold = 1024 ;
   snd_pcm_uframes_t period_size_out =  getFrameSize() * getSampleRate() / 1000 *  2;//1024 ;
   snd_pcm_uframes_t buffer_size_out = period_size_out * 4 ;
@@ -324,7 +324,11 @@ AudioLayer::open_device(std::string pcm_p, std::string pcm_c, int flag)
     if( err = snd_pcm_hw_params_set_channels( _CaptureHandle, hwParams, 1) < 0) _debugAlsa(" Cannot set channel count (%s)\n", snd_strerror(err));
     if( err = snd_pcm_hw_params_set_period_time_near( _CaptureHandle, hwParams, &period_time , &dir) < 0) _debugAlsa(" Cannot set period time (%s)\n", snd_strerror(err));
     if( err = snd_pcm_hw_params_set_buffer_time_near( _CaptureHandle, hwParams, &buffer_time , &dir) < 0) _debugAlsa(" Cannot set buffer time (%s)\n", snd_strerror(err));
+    if( err = snd_pcm_hw_params_get_period_size( hwParams, &period_size_in , &dir) < 0) _debugAlsa(" Cannot get period size (%s)\n", snd_strerror(err));
+    if( err = snd_pcm_hw_params_get_buffer_size( hwParams, &buffer_size_in ) < 0) _debugAlsa(" Cannot get buffer size (%s)\n", snd_strerror(err));
     if( err = snd_pcm_hw_params( _CaptureHandle, hwParams ) < 0) _debugAlsa(" Cannot set hw parameters (%s)\n", snd_strerror(err));
+    _debug("buffer size = %d\n" , period_size_in);
+    _debug("period size = %d\n" , buffer_size_in);
     snd_pcm_hw_params_free( hwParams );
 
     snd_pcm_uframes_t val ;
@@ -346,8 +350,8 @@ AudioLayer::open_device(std::string pcm_p, std::string pcm_c, int flag)
   {
 
     _debugAlsa(" Opening playback device %s\n", pcm_p.c_str());
-    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());
+    if(err = snd_pcm_open(&_PlaybackHandle, pcm_p.c_str(),  SND_PCM_STREAM_PLAYBACK, SND_PCM_NONBLOCK ) < 0){
+      _debugAlsa("Error while opening playback device %s\n",  pcm_c.c_str());
       setErrorMessage( ALSA_PLAYBACK_DEVICE );
       return false;
     }
@@ -356,14 +360,15 @@ AudioLayer::open_device(std::string pcm_p, std::string pcm_c, int flag)
       return false;
     }
     if( err = snd_pcm_hw_params_any( _PlaybackHandle,hwParams) < 0) _debugAlsa(" Cannot initialize hardware parameter structure (%s)\n", snd_strerror(err));
-    if( err = snd_pcm_hw_params_set_access( _PlaybackHandle, hwParams, SND_PCM_ACCESS_RW_INTERLEAVED) < 0) _debugAlsa(" Cannot set access type (%s)\n", snd_strerror(err));
+    if( err = snd_pcm_hw_params_set_access( _PlaybackHandle, hwParams, SND_PCM_ACCESS_MMAP_INTERLEAVED) < 0) _debugAlsa(" Cannot set access type (%s)\n", snd_strerror(err));
+    //if( err = snd_pcm_hw_params_set_access( _PlaybackHandle, hwParams, SND_PCM_ACCESS_RW_INTERLEAVED) < 0) _debugAlsa(" Cannot set access type (%s)\n", snd_strerror(err));
     if( err = snd_pcm_hw_params_set_format( _PlaybackHandle, hwParams, SND_PCM_FORMAT_S16_LE) < 0) _debugAlsa(" Cannot set sample format (%s)\n", snd_strerror(err));
     if( err = snd_pcm_hw_params_set_rate( _PlaybackHandle, hwParams, rate_out, dir) < 0) _debugAlsa(" Cannot set sample rate (%s)\n", snd_strerror(err));
     if( err = snd_pcm_hw_params_set_channels( _PlaybackHandle, hwParams, 1) < 0) _debugAlsa(" Cannot set channel count (%s)\n", snd_strerror(err));
-
-    if( err = snd_pcm_hw_params_set_buffer_size( _PlaybackHandle, hwParams, buffer_size ) < 0) _debugAlsa(" Cannot set buffer size (%s)\n", snd_strerror(err));
-    if( err = snd_pcm_hw_params_set_period_size_near( _PlaybackHandle, hwParams, &period_size , &dir) < 0) _debugAlsa(" Cannot set period size (%s)\n", snd_strerror(err));
-
+    if( err = snd_pcm_hw_params_set_buffer_time_near( _PlaybackHandle, hwParams, &buffer_time , &dir) < 0) _debugAlsa(" Cannot set buffer time (%s)\n", snd_strerror(err));
+    if( err = snd_pcm_hw_params_set_period_time_near( _PlaybackHandle, hwParams, &period_time , &dir) < 0) _debugAlsa(" Cannot set period time (%s)\n", snd_strerror(err));
+    if( err = snd_pcm_hw_params_get_period_size(  hwParams, &_periodSize , &dir) < 0) _debugAlsa(" Cannot get period size (%s)\n", snd_strerror(err));
+    if( err = snd_pcm_hw_params_get_buffer_size(  hwParams, &buffer_size_out ) < 0) _debugAlsa(" Cannot get buffer size (%s)\n", snd_strerror(err));
     if( err = snd_pcm_hw_params( _PlaybackHandle, hwParams ) < 0) _debugAlsa(" Cannot set hw parameters (%s)\n", snd_strerror(err));
 
 
@@ -389,7 +394,7 @@ AudioLayer::open_device(std::string pcm_p, std::string pcm_c, int flag)
     if( err = snd_pcm_sw_params( _PlaybackHandle, swparams ) < 0 ) _debugAlsa(" Cannot set sw parameters (%s)\n", snd_strerror(err)); 
     snd_pcm_sw_params_free( swparams );
 
-    //if ( err = snd_async_add_pcm_handler( &_AsyncHandler, _PlaybackHandle , AlsaCallBack, this ) < 0)	_debugAlsa(" Unable to install the async callback handler (%s)\n", snd_strerror(err));
+    if ( err = snd_async_add_pcm_handler( &_AsyncHandler, _PlaybackHandle , AlsaCallBack, this ) < 0)	_debugAlsa(" Unable to install the async callback handler (%s)\n", snd_strerror(err));
     deviceClosed = false;
   }
   //fillHWBuffer();
@@ -402,26 +407,28 @@ AudioLayer::open_device(std::string pcm_p, std::string pcm_c, int flag)
   int
 AudioLayer::write(void* buffer, int length)
 {
+  //if(snd_pcm_state( _PlaybackHandle ) == SND_PCM_STATE_XRUN)
+  //handle_xrun_playback();  
+  //_debugAlsa("avail = %d - toWrite = %d\n" , snd_pcm_avail_update( _PlaybackHandle ) , length / 2);
+
   snd_pcm_uframes_t frames = snd_pcm_bytes_to_frames( _PlaybackHandle, length);
-  //int err = snd_pcm_mmap_writei( _PlaybackHandle , buffer , frames );
-  int err = snd_pcm_writei( _PlaybackHandle , buffer , frames );
+  int err = snd_pcm_mmap_writei( _PlaybackHandle , buffer , frames );
   switch(err) {
     case -EAGAIN: 
-      _debugAlsa("EAGAIN (%s)\n", snd_strerror( err ));
-      //snd_pcm_resume( _PlaybackHandle );
+      _debugAlsa(" (%s)\n", snd_strerror( err ));
+      snd_pcm_resume( _PlaybackHandle );
       break;
     case -EPIPE: 
       _debugAlsa(" UNDERRUN (%s)\n", snd_strerror(err));
       handle_xrun_playback();
-      //snd_pcm_mmap_writei( _PlaybackHandle , buffer , frames );
-      //snd_pcm_writei( _PlaybackHandle , buffer , frames );
+      snd_pcm_mmap_writei( _PlaybackHandle , buffer , frames );
       break;
     case -ESTRPIPE:
-      _debugAlsa("ESTRPIPE (%s)\n", snd_strerror(err));
-      //snd_pcm_resume( _PlaybackHandle );
+      _debugAlsa(" (%s)\n", snd_strerror(err));
+      snd_pcm_resume( _PlaybackHandle );
       break;
     case -EBADFD:
-      _debugAlsa("EBADFD (%s)\n", snd_strerror( err ));
+      _debugAlsa(" (%s)\n", snd_strerror( err ));
       break;
   }
 
@@ -503,8 +510,7 @@ AudioLayer::handle_xrun_playback( void )
     state = snd_pcm_status_get_state( status );
     if( state  == SND_PCM_STATE_XRUN )
     {
-      //snd_pcm_drop( _PlaybackHandle );
-      _debug("Underrun\n");
+      snd_pcm_drop( _PlaybackHandle );
       snd_pcm_prepare( _PlaybackHandle );
       //snd_pcm_start( _PlaybackHandle ); 
     }
diff --git a/src/audio/audiolayer.h b/src/audio/audiolayer.h
index 3a0f549936..af585c00af 100644
--- a/src/audio/audiolayer.h
+++ b/src/audio/audiolayer.h
@@ -51,9 +51,10 @@ class AudioLayer {
      * Constructor
      * @param manager An instance of managerimpl
      */
-    AudioLayer( ManagerImpl* manager )
+    AudioLayer( ManagerImpl* manager , int type )
       :	  _manager(manager)
 	, _urgentBuffer( SIZEBUF )
+	, _layerType( type )
     {
       _inChannel  = 1; // don't put in stereo
       _outChannel = 1; // don't put in stereo
@@ -80,7 +81,7 @@ class AudioLayer {
      *			  SFL_PCM_BOTH
      * @param plugin	  The alsa plugin ( dmix , default , front , surround , ...)
      */
-    virtual bool openDevice(int indexIn, int indexOut, int sampleRate, int frameSize, int stream, std::string plugin) = 0;
+    virtual bool openDevice(int indexIn, int indexOut, int sampleRate, int frameSize, int stream , std::string plugin) = 0;
 
     /**
      * Start the capture stream and prepare the playback stream. 
@@ -226,8 +227,12 @@ class AudioLayer {
      */
     bool getCurrentState( void ) { return _talk; }
 
+    int getLayerType( void ) { return _layerType; }
+
   protected:
 
+    int _layerType;
+
     /**
      * Drop the pending frames and close the capture device
      */
diff --git a/src/audio/pulselayer.cpp b/src/audio/pulselayer.cpp
index 9755ced1e3..5cb4dd9d2f 100644
--- a/src/audio/pulselayer.cpp
+++ b/src/audio/pulselayer.cpp
@@ -17,7 +17,6 @@
  *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  */
 
-
 #include "pulselayer.h"
 
 static pa_context *context = NULL;
@@ -25,15 +24,13 @@ static pa_mainloop_api *mainloop_api = NULL;
 static pa_sample_spec sample_spec;
 static pa_channel_map channel_map;
 
-static std::string stream_p = NULL;
-static std::string stream_r = NULL;
-
-
 PulseLayer::PulseLayer(ManagerImpl* manager)
-  : AudioLayer( manager )    
+  : AudioLayer( manager , PULSEAUDIO )    
+  , playback( NULL )
+  , record( NULL )
 {
-  playback = NULL;   
-  record = NULL; 
+  _debug("Pulse audio constructor: Create context\n");
+  create_context();
 }
 
 // Destructor
@@ -45,15 +42,81 @@ PulseLayer::~PulseLayer (void)
   // pa_stream_disconnect();
 }
 
+void
+PulseLayer::create_context( void )
+{
+  pa_context_flags_t flag = PA_CONTEXT_NOAUTOSPAWN ;  
+  int ret = 1;
+
+  // Instanciate a mainloop object
+  pa_mainloop *m;
+  if(!( m=pa_mainloop_new()))
+    _debug("Error while creating the mainloop\n");
+  mainloop_api = pa_mainloop_get_api( m );
+
+  // Instanciate a context
+  if( !(context = pa_context_new( mainloop_api , "SFLphone" )))
+    _debug("Error while creating the context\n");
+  pa_context_ref( context );
+
+  pa_context_set_state_callback(context, context_state_callback, NULL);
+
+  pa_context_connect( context, NULL , flag , NULL );
+  
+  // Run the main loop
+  pa_mainloop_run(m , &ret);
+
+  _debug("Context creation done\n");
+}
+
 void 
 PulseLayer::stream_state_callback( pa_stream* s, void* user_data )
 {
   _debug("The state of the stream changed\n");
 }
 
+void 
+PulseLayer::context_state_callback( pa_context* c, void* user_data )
+{
+  _debug("The state of the context changed\n");
+  assert(c);
+  switch(pa_context_get_state(c)){
+    case PA_CONTEXT_CONNECTING:
+    case PA_CONTEXT_AUTHORIZING:
+    case PA_CONTEXT_SETTING_NAME:
+      _debug("Waiting....\n");
+      break;
+    case PA_CONTEXT_READY:
+      pa_cvolume cv;
+      assert(c && !playback && !record);
+      _debug("Connection to PulseAudio server established\n");	
+      playback = pa_stream_new( c, "playback stream" , &sample_spec, &channel_map);
+      record = pa_stream_new( c, "capture stream" , &sample_spec, &channel_map);
+
+      assert(playback);
+      assert(record);
 
-  void
-PulseLayer::openDevice (int indexIn, int indexOut, int sampleRate, int frameSize) 
+      // Set up the parameters required to open a (Callback)Stream:
+
+      pa_stream_set_state_callback(playback, stream_state_callback, NULL);
+      // Transferring Data - Asynchronous Mode
+      pa_stream_set_write_callback(playback, audioCallback, NULL);
+      pa_stream_connect_playback( playback, NULL , NULL , flag , NULL, NULL );
+
+      break;
+    case PA_CONTEXT_TERMINATED:
+      _debug("Context terminated\n");
+      break;
+    case PA_CONTEXT_FAILED:
+    default:
+      _debug(" Error : %s" , pa_strerror(pa_context_errno(context)));
+      exit(1);
+  }
+}
+
+
+ bool 
+PulseLayer::openDevice(int indexIn, int indexOut, int sampleRate, int frameSize , int stream, std::string plugin) 
 {
   _sampleRate = sampleRate;
   _frameSize = frameSize;	
@@ -68,11 +131,13 @@ PulseLayer::openDevice (int indexIn, int indexOut, int sampleRate, int frameSize
   _debug("                   : nb channel in=%2d, out=%2d\n", _inChannel, _outChannel);
   _debug("                   : sample rate=%5d\n", _sampleRate );
 
+  /*
   assert(context);
   switch(pa_context_get_state(context)){
     case PA_CONTEXT_CONNECTING:
     case PA_CONTEXT_AUTHORIZING:
     case PA_CONTEXT_SETTING_NAME:
+      _debug("Waiting....\n");
       break;
     case PA_CONTEXT_READY:
       pa_cvolume cv;
@@ -99,7 +164,22 @@ PulseLayer::openDevice (int indexIn, int indexOut, int sampleRate, int frameSize
     default:
       _debug(" Error : %s" , pa_strerror(pa_context_errno(context)));
       exit(1);
-  }
+  }*/
+}
+
+void 
+PulseLayer::closeCaptureStream( void )
+{
+}
+
+void 
+PulseLayer::closePlaybackStream( void )
+{
+}
+
+int 
+PulseLayer::playSamples(void* buffer, int toCopy, bool isTalking)
+{
 }
 
   int 
@@ -137,6 +217,23 @@ PulseLayer::isStreamStopped (void)
 {
 }
 
+ void 
+PulseLayer::startStream (void) 
+{
+  _debug("Start stream\n");
+}
+
+ void 
+PulseLayer::stopStream (void) 
+{
+  _debug("Stop stream\n");
+}
+
+ bool 
+PulseLayer::isStreamActive (void) 
+{
+}
+
 
   void 
 PulseLayer::audioCallback ( pa_stream* s, size_t bytes, void* user_data )
diff --git a/src/audio/pulselayer.h b/src/audio/pulselayer.h
index 9fc0d6a3d5..6076711f88 100644
--- a/src/audio/pulselayer.h
+++ b/src/audio/pulselayer.h
@@ -30,13 +30,22 @@ class PulseLayer : public AudioLayer {
     PulseLayer(ManagerImpl* manager);
     ~PulseLayer(void);
 
-    /*
-     * @param indexIn
-     * @param indexOut
-     * @param sampleRate
-     * @param frameSize
+    /**
+     * Check if no devices are opened, otherwise close them.
+     * Then open the specified devices by calling the private functions open_device
+     * @param indexIn	The number of the card choosen for capture
+     * @param indexOut	The number of the card choosen for playback
+     * @param sampleRate  The sample rate 
+     * @param frameSize	  The frame size
+     * @param stream	  To indicate which kind of stream you want to open
+     *			  SFL_PCM_CAPTURE
+     *			  SFL_PCM_PLAYBACK
+     *			  SFL_PCM_BOTH
+     * @param plugin	  The alsa plugin ( dmix , default , front , surround , ...)
      */
-    void openDevice(int, int, int, int);
+    bool openDevice(int indexIn, int indexOut, int sampleRate, int frameSize , int stream, std::string plugin) ;
+
+
     void startStream(void);
     void stopStream(void);
     bool isStreamActive(void);
@@ -56,9 +65,19 @@ class PulseLayer : public AudioLayer {
     int getMic(void *, int);
     void flushMic();
 
+    /**
+     * Send samples to the audio device. 
+     * @param buffer The buffer containing the data to be played ( voice and DTMF )
+     * @param toCopy The number of samples, in bytes
+     * @param isTalking	If whether or not the conversation is running
+     * @return int The number of bytes played
+     */
+    int playSamples(void* buffer, int toCopy, bool isTalking) ;
+
     static void audioCallback ( pa_stream* s, size_t bytes, void* user_data );
 
     static void stream_state_callback( pa_stream* s, void* user_data );	
+    static void context_state_callback( pa_context* c, void* user_data );	
 
     /**
      * Scan the sound card available on the system
@@ -96,10 +115,20 @@ class PulseLayer : public AudioLayer {
      * Get the current audio plugin.
      * @return std::string  The name of the audio plugin
      */
-    std::string getAudioPlugin( void ) { return ""; }
+    std::string getAudioPlugin( void ) { return "default"; }
 
   private:
-    void closeStream (void);
+    /**
+     * Drop the pending frames and close the capture device
+     */
+    void closeCaptureStream( void );
+
+    /**
+     * Drop the pending frames and close the playback device
+     */
+    void closePlaybackStream( void );
+
+    void create_context( void );
 
     pa_stream* playback;
     pa_stream* record;
diff --git a/src/global.h b/src/global.h
index af95fbc6dd..f6e9cd00f0 100644
--- a/src/global.h
+++ b/src/global.h
@@ -122,4 +122,9 @@ typedef short int16;
 #define ALSA_PLAYBACK_DEVICE          0x0010	/** Error while opening playback device */
 #define NETWORK_UNREACHABLE           0x0011	/** Network unreachable */
 
+#define ALSA			  0 
+#define PULSEAUDIO		  1
+//#define AUDIODRIVER		  ALSA
+#define CHECK_INTERFACE( layer , api )		  (layer == api) 
+
 #endif	// __GLOBAL_H__
diff --git a/src/managerimpl.cpp b/src/managerimpl.cpp
index 6b9f06e12f..b100deefd9 100644
--- a/src/managerimpl.cpp
+++ b/src/managerimpl.cpp
@@ -1433,8 +1433,8 @@ ManagerImpl::getCurrentAudioOutputPlugin( void )
 ManagerImpl::initAudioDriver(void) 
 {
   _debugInit("AudioLayer Creation");
-  //_audiodriver = new AudioLayer(this);
-  _audiodriver = new AlsaLayer( this );
+  //_audiodriver = new AlsaLayer( this );
+  _audiodriver = new PulseLayer( this );
   if (_audiodriver == 0) {
     _debug("Init audio driver error\n");
   } else {
@@ -1451,6 +1451,10 @@ ManagerImpl::initAudioDriver(void)
   void
 ManagerImpl::selectAudioDriver (void)
 {
+  int layer = _audiodriver->getLayerType();
+  _debug("Audio layer type: %i\n" , layer);
+
+#if CHECK_INTERFACE( layer , ALSA )
   std::string alsaPlugin = getConfigString( AUDIO , ALSA_PLUGIN );
   int numCardIn  = getConfigInt( AUDIO , ALSA_CARD_ID_IN );
   int numCardOut = getConfigInt( AUDIO , ALSA_CARD_ID_OUT );
@@ -1478,6 +1482,15 @@ ManagerImpl::selectAudioDriver (void)
   _audiodriver->openDevice( numCardIn , numCardOut, sampleRate, frameSize, SFL_PCM_BOTH, alsaPlugin ); 
   if( _audiodriver -> getErrorMessage() != -1 )
     notifyErrClient( _audiodriver -> getErrorMessage());
+#else
+  
+  _debug(" Pulse audio driver \n");
+  _audiodriver->openDevice( numCardIn , numCardOut, sampleRate, frameSize, SFL_PCM_BOTH, alsaPlugin ); 
+  if( _audiodriver -> getErrorMessage() != -1 )
+    notifyErrClient( _audiodriver -> getErrorMessage());
+
+#endif
+
 }
 
 /**
-- 
GitLab