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