diff --git a/src/audio/audiolayer.cpp b/src/audio/audiolayer.cpp deleted file mode 100644 index d799939335b1e22cda5456a85532f8bd12885c79..0000000000000000000000000000000000000000 --- a/src/audio/audiolayer.cpp +++ /dev/null @@ -1,664 +0,0 @@ -/* - * Copyright (C) 2008 Savoir-Faire Linux inc. - * Author: Yan Morin <yan.morin@savoirfairelinux.com> - * Author: Jerome Oufella <jerome.oufella@savoirfairelinux.com> - * 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 <cstdio> -#include <cstdlib> - -#include "audiolayer.h" -#include "../global.h" -#include "../manager.h" -#include "../user_cfg.h" - -#define PCM_PAUSE 1 -#define PCM_RESUME 0 - -#ifdef SFL_TEST_SINE -#include <cmath> -#endif - - AudioLayer::AudioLayer(ManagerImpl* manager) - : _defaultVolume(100) - , _manager(manager) - , _PlaybackHandle( NULL ) - , _CaptureHandle( NULL ) - , deviceClosed( true ) - , _urgentBuffer( SIZEBUF ) -{ - - _inChannel = 1; // don't put in stereo - _outChannel = 1; // don't put in stereo - _echoTesting = false; - -} - -// Destructor -AudioLayer::~AudioLayer (void) -{ - _debugAlsa("Close ALSA streams\n"); - closeCaptureStream(); - closePlaybackStream(); - deviceClosed = true; -} - - - bool -AudioLayer::openDevice (int indexIn, int indexOut, int sampleRate, int frameSize, int stream , std::string plugin) -{ - - if(deviceClosed == false) - { - if( stream == SFL_PCM_CAPTURE ) - closeCaptureStream(); - else if( stream == SFL_PCM_PLAYBACK) - closePlaybackStream(); - else - { - closeCaptureStream(); - closePlaybackStream(); - } - } - - _indexIn = indexIn; - _indexOut = indexOut; - _sampleRate = sampleRate; - _frameSize = frameSize; - _audioPlugin = plugin; - - _debugAlsa(" Setting audiolayer: device in=%2d, out=%2d\n", _indexIn, _indexOut); - _debugAlsa(" : alsa plugin=%s\n", _audioPlugin.c_str()); - _debugAlsa(" : nb channel in=%2d, out=%2d\n", _inChannel, _outChannel); - _debugAlsa(" : sample rate=%5d, format=%s\n", _sampleRate, SFLDataFormatString); - - ost::MutexLock lock( _mutex ); - - std::string pcmp = buildDeviceTopo( plugin , indexOut , 0); - std::string pcmc = buildDeviceTopo( PCM_PLUGHW , indexIn , 0); - return open_device( pcmp , pcmc , stream); -} - - void -AudioLayer::startStream(void) -{ - if( _CaptureHandle && _PlaybackHandle ) - { - _talk = true ; - _debugAlsa(" Start stream\n"); - int err; - //ost::MutexLock lock( _mutex ); - snd_pcm_prepare( _CaptureHandle ); - snd_pcm_start( _CaptureHandle ) ; - - snd_pcm_prepare( _PlaybackHandle ); - if( err = snd_pcm_start( _PlaybackHandle) < 0 ) _debugAlsa(" Cannot start (%s)\n", snd_strerror(err)); - } -} - - void -AudioLayer::stopStream(void) -{ - if( _CaptureHandle && _PlaybackHandle ) - { - //ost::MutexLock lock( _mutex ); - _debugAlsa(" Stop Stream\n "); - _talk = false; - snd_pcm_drop( _CaptureHandle ); - snd_pcm_prepare( _CaptureHandle ); - snd_pcm_drop( _PlaybackHandle ); - snd_pcm_prepare( _PlaybackHandle ); - _urgentBuffer.flush(); - } -} - -void AudioLayer::AlsaCallBack( snd_async_handler_t* pcm_callback ) -{ - ( ( AudioLayer *)snd_async_handler_get_callback_private( pcm_callback )) -> playTones(); -} - - void -AudioLayer::fillHWBuffer( void) -{ - unsigned char* data; - int pcmreturn, l1, l2; - short s1, s2; - int periodSize = 128 ; - int frames = periodSize >> 2 ; - _debug("frames = %d\n"); - - data = (unsigned char*)malloc(periodSize); - for(l1 = 0; l1 < 100; l1++) { - for(l2 = 0; l2 < frames; l2++) { - s1 = 0; - s2 = 0; - 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; - } - while ((pcmreturn = snd_pcm_mmap_writei(_PlaybackHandle, data, frames)) < 0) { - snd_pcm_prepare(_PlaybackHandle); - //_debugAlsa("< Buffer Underrun >\n"); - } - } -} - - bool -AudioLayer::isStreamActive (void) -{ - ost::MutexLock lock( _mutex ); - return (isPlaybackActive() && isCaptureActive()); -} - - - int -AudioLayer::playSamples(void* buffer, int toCopy, bool isTalking) -{ - //ost::MutexLock lock( _mutex ); - if( isTalking ) - _talk = true; - if ( _PlaybackHandle ){ - write( adjustVolume( buffer , toCopy , SFL_PCM_PLAYBACK ) , toCopy ); - } - return 0; -} - - int -AudioLayer::putUrgent(void* buffer, int toCopy) -{ - if ( _PlaybackHandle ){ - fillHWBuffer(); - int a = _urgentBuffer.AvailForPut(); - if( a >= toCopy ){ - return _urgentBuffer.Put( buffer , toCopy , _defaultVolume ); - } else { - return _urgentBuffer.Put( buffer , a , _defaultVolume ) ; - } - } - return 0; -} - - int -AudioLayer::canGetMic() -{ - int avail; - if ( _CaptureHandle ) { - avail = snd_pcm_avail_update( _CaptureHandle ); - //printf("%d\n", avail ); - if(avail > 0) - return avail; - else - return 0; - } - else - return 0; -} - - int -AudioLayer::getMic(void *buffer, int toCopy) -{ - int res = 0 ; - if( _CaptureHandle ) - { - res = read( buffer, toCopy ); - adjustVolume( buffer , toCopy , SFL_PCM_CAPTURE ); - } - return res ; -} - - - bool -AudioLayer::isStreamStopped (void) -{ - ost::MutexLock lock( _mutex ); - return !(isStreamActive()); -} - -void -AudioLayer::toggleEchoTesting() { - ost::MutexLock lock( _mutex ); - _echoTesting = (_echoTesting == true) ? false : true; -} - - -////////////////////////////////////////////////////////////////////////////////////////////// -///////////////// ALSA PRIVATE FUNCTIONS //////////////////////////////////////////////// -//////////////////////////////////////////////////////////////////////////////////////////// - - - - void -AudioLayer::playTones( void ) -{ - int frames = _periodSize ; - int maxBytes = frames * sizeof(SFLDataFormat) ; - SFLDataFormat* out = (SFLDataFormat*)malloc(maxBytes * sizeof(SFLDataFormat)); - if( _talk ) {} - else { - AudioLoop *tone = _manager -> getTelephoneTone(); - int spkrVol = _manager -> getSpkrVolume(); - if( tone != 0 ){ - tone -> getNext( out , frames , spkrVol ); - write( out , maxBytes ); - } - else if( ( tone=_manager->getTelephoneFile() ) != 0 ){ - tone ->getNext( out , frames , spkrVol ); - write( out , maxBytes ); - } - } - // free the temporary data buffer - free( out ); out = 0; -} - -bool -AudioLayer::isPlaybackActive(void) { - ost::MutexLock guard( _mutex ); - if( _PlaybackHandle ) - return (snd_pcm_state(_PlaybackHandle) == SND_PCM_STATE_RUNNING ? true : false); - else - return false; -} - -bool -AudioLayer::isCaptureActive(void) { - ost::MutexLock guard( _mutex ); - if( _CaptureHandle ) - return (snd_pcm_state( _CaptureHandle) == SND_PCM_STATE_RUNNING ? true : false); - else - return false; -} - - - bool -AudioLayer::open_device(std::string pcm_p, std::string pcm_c, int flag) -{ - std::stringstream errMsg; - int err; - snd_pcm_hw_params_t* hwParams = NULL; - snd_pcm_sw_params_t *swparams = NULL; - unsigned int rate_in = getSampleRate(); - unsigned int rate_out = getSampleRate(); - int dir = 0; - 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 ; - - unsigned int buffer_time = 80000; //80ms - unsigned int period_time = buffer_time / 4 ; //20ms - - if(flag == SFL_PCM_BOTH || flag == SFL_PCM_CAPTURE) - { - _debugAlsa("Opening capture device %s\n", pcm_c.c_str()); - 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 ); - return false; - } - - if( err = snd_pcm_hw_params_malloc( &hwParams ) < 0 ) { - _debugAlsa(" Cannot allocate hardware parameter structure (%s)\n", snd_strerror(err)); - return false; - } - if( err = snd_pcm_hw_params_any(_CaptureHandle, hwParams) < 0) _debugAlsa(" Cannot initialize hardware parameter structure (%s)\n", snd_strerror(err)); - if( err = snd_pcm_hw_params_set_access( _CaptureHandle, hwParams, SND_PCM_ACCESS_MMAP_INTERLEAVED) < 0) _debugAlsa(" Cannot set access type (%s)\n", snd_strerror(err)); - if( err = snd_pcm_hw_params_set_format( _CaptureHandle, 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_near( _CaptureHandle, hwParams, &rate_in, &dir) < 0) _debugAlsa(" Cannot set sample rate (%s)\n", snd_strerror(err)); - 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 ; - snd_pcm_sw_params_malloc( &swparams ); - snd_pcm_sw_params_current( _CaptureHandle, swparams ); - - if( err = snd_pcm_sw_params_set_start_threshold( _CaptureHandle, swparams, period_size_out) < 0 ) _debugAlsa(" Cannot set start threshold (%s)\n", snd_strerror(err)); - snd_pcm_sw_params_get_start_threshold( swparams , &val); - _debug("Start threshold = %d\n" ,val); - if( err = snd_pcm_sw_params_set_avail_min( _CaptureHandle, swparams, period_size_out) < 0) _debugAlsa(" Cannot set min avail (%s)\n" , snd_strerror(err)); - snd_pcm_sw_params_get_avail_min( swparams , &val); - _debug("Min available = %d\n" ,val); - if( err = snd_pcm_sw_params( _CaptureHandle, swparams ) < 0 ) _debugAlsa(" Cannot set sw parameters (%s)\n", snd_strerror(err)); - snd_pcm_sw_params_free( swparams ); - deviceClosed = false; - } - - if(flag == SFL_PCM_BOTH || flag == SFL_PCM_PLAYBACK) - { - - _debugAlsa(" 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; - } - if( err = snd_pcm_hw_params_malloc( &hwParams ) < 0 ) { - _debugAlsa(" Cannot allocate hardware parameter structure (%s)\n", snd_strerror(err)); - 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_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_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)); - - - snd_pcm_hw_params_free( hwParams ); - - snd_pcm_uframes_t val ; - snd_pcm_sw_params_malloc( &swparams ); - snd_pcm_sw_params_current( _PlaybackHandle, swparams ); - - if( err = snd_pcm_sw_params_set_start_threshold( _PlaybackHandle, swparams, period_size_out) < 0 ) _debugAlsa(" Cannot set start threshold (%s)\n", snd_strerror(err)); - snd_pcm_sw_params_get_start_threshold( swparams , &val); - _debug("Start threshold = %d\n" ,val); - //if( err = snd_pcm_sw_params_set_stop_threshold( _PlaybackHandle, swparams, buffer_size_out ) < 0 ) _debugAlsa(" Cannot set stop threshold (%s)\n", snd_strerror(err)); - //snd_pcm_sw_params_get_stop_threshold( swparams , &val); - //_debug("Stop threshold = %d\n" ,val); - if( err = snd_pcm_sw_params_set_avail_min( _PlaybackHandle, swparams, period_size_out) < 0) _debugAlsa(" Cannot set min avail (%s)\n" , snd_strerror(err)); - if( err = snd_pcm_sw_params_set_xfer_align( _PlaybackHandle, swparams, 1) < 0) _debugAlsa(" Cannot set xfer align (%s)\n" , snd_strerror(err)); - snd_pcm_sw_params_get_avail_min( swparams , &val); - _debug("Min available = %d\n" ,val); - //if( err = snd_pcm_sw_params_set_silence_threshold( _PlaybackHandle, swparams, period_size_out) < 0) _debugAlsa(" Cannot set silence threshold (%s)\n" , snd_strerror(err)); - //snd_pcm_sw_params_get_silence_threshold( swparams , &val); - // _debug("Silence threshold = %d\n" ,val); - 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)); - deviceClosed = false; - } - //fillHWBuffer(); - - _talk = false; - return true; -} - -//TODO first frame causes broken pipe (underrun) because not enough data are send --> make the handle wait to be ready - 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 ); - switch(err) { - case -EAGAIN: - _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 ); - break; - case -ESTRPIPE: - _debugAlsa(" (%s)\n", snd_strerror(err)); - snd_pcm_resume( _PlaybackHandle ); - break; - case -EBADFD: - _debugAlsa(" (%s)\n", snd_strerror( err )); - break; - } - - if( err >=0 && err < frames ) - _debugAlsa("Short write : %d out of %d\n", err , frames); - - return ( err > 0 )? err : 0 ; -} - - int -AudioLayer::read( void* buffer, int toCopy) -{ - if(deviceClosed || _CaptureHandle == NULL) - return 0; - int err; - if(snd_pcm_state( _CaptureHandle ) == SND_PCM_STATE_XRUN) - { - snd_pcm_prepare( _CaptureHandle ); - snd_pcm_start( _CaptureHandle ); - } - snd_pcm_uframes_t frames = snd_pcm_bytes_to_frames( _CaptureHandle, toCopy ); - if( err = snd_pcm_mmap_readi( _CaptureHandle, buffer, frames) < 0 ) { - switch(err){ - case EPERM: - _debugAlsa(" Capture EPERM (%s)\n", snd_strerror(err)); - snd_pcm_prepare( _CaptureHandle); - snd_pcm_start( _CaptureHandle ); - break; - case -ESTRPIPE: - _debugAlsa(" Capture ESTRPIPE (%s)\n", snd_strerror(err)); - snd_pcm_resume( _CaptureHandle); - break; - case -EAGAIN: - _debugAlsa(" Capture EAGAIN (%s)\n", snd_strerror(err)); - break; - case -EBADFD: - _debugAlsa(" Capture EBADFD (%s)\n", snd_strerror(err)); - break; - case -EPIPE: - _debugAlsa(" Capture EPIPE (%s)\n", snd_strerror(err)); - handle_xrun_capture(); - break; - } - return 0; - } - - return toCopy; - -} - - void -AudioLayer::handle_xrun_capture( void ) -{ - snd_pcm_status_t* status; - snd_pcm_status_alloca( &status ); - - int res = snd_pcm_status( _CaptureHandle, status ); - if( res <= 0){ - if(snd_pcm_status_get_state(status) == SND_PCM_STATE_XRUN ){ - snd_pcm_drop( _CaptureHandle ); - snd_pcm_prepare( _CaptureHandle ); - snd_pcm_start( _CaptureHandle ); - } - } - else - _debugAlsa(" Get status failed\n"); -} - - void -AudioLayer::handle_xrun_playback( void ) -{ - int state; - snd_pcm_status_t* status; - snd_pcm_status_alloca( &status ); - - 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 ) - { - snd_pcm_drop( _PlaybackHandle ); - snd_pcm_prepare( _PlaybackHandle ); - //snd_pcm_start( _PlaybackHandle ); - } - } -} - - std::string -AudioLayer::buildDeviceTopo( std::string plugin, int card, int subdevice ) -{ - std::string pcm = plugin; - std::stringstream ss,ss1; - if( pcm == "default" || pcm == "pulse") - return pcm; - ss << card; - pcm.append(":"); - pcm.append(ss.str()); - if( subdevice != 0 ){ - pcm.append(","); - ss1 << subdevice; - pcm.append(ss1.str()); - } - return pcm; -} - - std::vector<std::string> -AudioLayer::getSoundCardsInfo( int stream ) -{ - std::vector<std::string> cards_id; - HwIDPair p; - - snd_ctl_t* handle; - snd_ctl_card_info_t *info; - snd_pcm_info_t* pcminfo; - snd_ctl_card_info_alloca( &info ); - snd_pcm_info_alloca( &pcminfo ); - - int numCard = -1 ; - int err; - std::string description; - - if(snd_card_next( &numCard ) < 0 || numCard < 0) - return cards_id; - - while(numCard >= 0){ - std::stringstream ss; - ss << numCard; - std::string name= "hw:"; - 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 ); - } - } - snd_ctl_close( handle ); - } - if ( snd_card_next( &numCard ) < 0 ) { - break; - } - } - return cards_id; -} - - void -AudioLayer::closeCaptureStream( void) -{ - if(_CaptureHandle){ - snd_pcm_drop( _CaptureHandle ); - snd_pcm_close( _CaptureHandle ); - _CaptureHandle = 0; - } -} - - void -AudioLayer::closePlaybackStream( void) -{ - if(_PlaybackHandle){ - snd_pcm_drop( _PlaybackHandle ); - snd_pcm_close( _PlaybackHandle ); - _PlaybackHandle = 0; - } -} - - bool -AudioLayer::soundCardIndexExist( int card , int stream ) -{ - snd_ctl_t* handle; - snd_pcm_info_t *pcminfo; - snd_pcm_info_alloca( &pcminfo ); - std::string name = "hw:"; - std::stringstream ss; - ss << card ; - 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; - else - return true; - } - else - return false; -} - - int -AudioLayer::soundCardGetIndex( std::string description ) -{ - int i; - for( i = 0 ; i < IDSoundCards.size() ; i++ ) - { - HwIDPair p = IDSoundCards[i]; - if( p.second == description ) - return p.first ; - } - // else return the default one - return 0; -} - - void* -AudioLayer::adjustVolume( void* buffer , int len, int stream ) -{ - int vol; - if( stream == SFL_PCM_PLAYBACK ) - vol = _manager->getSpkrVolume(); - else - vol = _manager->getMicVolume(); - - SFLDataFormat* src = (SFLDataFormat*) buffer; - if( vol != 100 ) - { - int size = len / sizeof(SFLDataFormat); - int i; - for( i = 0 ; i < size ; i++ ){ - src[i] = src[i] * vol / 100 ; - } - } - return src ; -} diff --git a/src/audio/audiolayer.h b/src/audio/audiolayer.h index af585c00afb4e63928988d53e373211a20ae2195..a0083f99d85038994c0ec31096319abd11dfec0b 100644 --- a/src/audio/audiolayer.h +++ b/src/audio/audiolayer.h @@ -129,6 +129,8 @@ class AudioLayer { */ virtual int putUrgent(void* buffer, int toCopy) = 0; + virtual int putMain( void* buffer, int toCopy) = 0; + /** * Query the capture device for number of bytes available in the hardware ring buffer * @return int The number of bytes available diff --git a/src/audio/audiortp.cpp b/src/audio/audiortp.cpp index e98458bdc36af9fdd2098d8ffe81bb465eb94dcf..513b29db5814b09c303411ff0593f7aae070c6ba 100644 --- a/src/audio/audiortp.cpp +++ b/src/audio/audiortp.cpp @@ -377,8 +377,13 @@ AudioRtpRTX::receiveSessionForSpkr (int& countTime) toAudioLayer = _dataAudioLayer; #endif - - audiolayer->playSamples(toAudioLayer, nbSample * sizeof(SFLDataFormat), true); + // int layer = audiolayer->getLayerType(); + // _debug(" interface %i\n" , layer); +//#if CHECK_INTERFACE( layer , ALSA ) + // audiolayer->playSamples(toAudioLayer, nbSample * sizeof(SFLDataFormat), true); +//#else + audiolayer->putMain( toAudioLayer, nbSample * sizeof(SFLDataFormat) ); +//#endif // Notify (with a beep) an incoming call when there is already a call countTime += time->getSecond(); if (Manager::instance().incomingCallWaiting() > 0) { diff --git a/src/audio/pulselayer.cpp b/src/audio/pulselayer.cpp index db76eb4586e4551aa975a0d98efb98673528046c..6e1be72dc20e747842d1b9640b7d5723d51c069b 100644 --- a/src/audio/pulselayer.cpp +++ b/src/audio/pulselayer.cpp @@ -23,67 +23,85 @@ static pa_context *context = NULL; static pa_stream* playback = NULL; static pa_stream* record = NULL; static pa_mainloop_api *mainloop_api = NULL; -static pa_sample_spec sample_spec; +static pa_threaded_mainloop *m = NULL; + +static pa_sample_spec sample_spec ; + static pa_channel_map channel_map; -PulseLayer::PulseLayer(ManagerImpl* manager) +static std::string pcm_p, pcm_r; + +int framesPerBuffer = 882; + + PulseLayer::PulseLayer(ManagerImpl* manager) : AudioLayer( manager , PULSEAUDIO ) + , _mainSndRingBuffer( SIZEBUF ) { _debug("Pulse audio constructor: Create context\n"); - create_context(); } // Destructor PulseLayer::~PulseLayer (void) { assert(mainloop_api); - mainloop_api->quit( mainloop_api, 0 ); - // pa_stream_flush(); - // pa_stream_disconnect(); + //mainloop_api->quit( mainloop_api, 0 ); + pa_stream_flush( playback , NULL, NULL); + pa_stream_disconnect( playback ); + pa_context_disconnect(context); } -void -PulseLayer::create_context( void ) + void +PulseLayer::connectPulseServer( 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 ); + pa_threaded_mainloop_lock( m ); - // Instanciate a context - if( !(context = pa_context_new( mainloop_api , "SFLphone" ))) - _debug("Error while creating the context\n"); - pa_context_ref( context ); + _debug("Connect the context to the server\n"); + pa_context_connect( context, NULL , flag , NULL ); - pa_context_set_state_callback(context, context_state_callback, NULL); + pa_context_set_state_callback(context, context_state_callback, this); + pa_threaded_mainloop_wait( m ); - pa_context_connect( context, NULL , flag , NULL ); - // Run the main loop - pa_mainloop_run(m , &ret); + if( pa_context_get_state( context ) != PA_CONTEXT_READY ){ + _debug("Error connecting to pulse audio server\n"); + pa_threaded_mainloop_unlock( m ); + } + + pa_threaded_mainloop_unlock( m ); _debug("Context creation done\n"); } -void + void PulseLayer::stream_state_callback( pa_stream* s, void* user_data ) { _debug("The state of the stream changed\n"); + assert(s); + switch(pa_stream_get_state(s)){ + case PA_STREAM_CREATING: + case PA_STREAM_TERMINATED: + _debug("Stream is creating...\n"); + break; + case PA_STREAM_READY: + _debug("Stream successfully created\n"); + break; + case PA_STREAM_FAILED: + default: + _debug("Stream error: %s\n" , pa_strerror(pa_context_errno(pa_stream_get_context(s)))); + break; + } } -void + void PulseLayer::context_state_callback( pa_context* c, void* user_data ) { _debug("The state of the context changed\n"); - sample_spec.format = PA_SAMPLE_S16LE; - sample_spec.channels = 1; - channel_map.channels = 1; - pa_stream_flags_t flag = PA_STREAM_START_CORKED ; - assert(c); + PulseLayer* pulse = (PulseLayer*)user_data; + //pa_stream_flags_t flag = PA_STREAM_INTERPOLATE_TIMING | PA_STREAM_AUTO_TIMING_UPDATE ; + assert(c && m); switch(pa_context_get_state(c)){ case PA_CONTEXT_CONNECTING: case PA_CONTEXT_AUTHORIZING: @@ -93,20 +111,8 @@ PulseLayer::context_state_callback( pa_context* c, void* user_data ) case PA_CONTEXT_READY: pa_cvolume cv; assert(c && !playback && !record); + pulse->createStreams( c ); _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); - - // 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"); @@ -118,70 +124,91 @@ PulseLayer::context_state_callback( pa_context* c, void* user_data ) } } + void +PulseLayer::createStreams( pa_context* c ) +{ + _debug( " Create Audio Streams \n "); + //pa_stream_flags_t flag = PA_STREAM_AUTO_TIMING_UPDATE; + pa_stream_flags_t flag = PA_STREAM_FIX_RATE; + sample_spec.format = PA_SAMPLE_S16LE; + sample_spec.rate = 44100; + sample_spec.channels = 1; + channel_map.channels = 1; + + if( !pa_sample_spec_valid( &sample_spec ) ){ + _debug("Invalid sample specifications\n"); + exit(0); + } + + if(!(playback = pa_stream_new( c, "SFLphone out" , &sample_spec, &channel_map))){ + _debug("Playback: pa_stream_new() failed : %s\n" , pa_strerror( pa_context_errno( c))); + exit(0); + } + + if(!(record = pa_stream_new( c, "SFLphone Mic" , &sample_spec, &channel_map))){ + _debug("Capture: pa_stream_new() failed : %s\n" , pa_strerror( pa_context_errno( c))); + exit(0); + } + + assert(playback); + assert(record); + assert(m); + + // Set up the parameters required to open a (Callback)Stream: + + pa_stream_connect_playback( playback, NULL , NULL , flag , NULL, NULL ); + pa_stream_set_state_callback(playback, stream_state_callback, NULL); + // Transferring Data - Asynchronous Mode + pa_stream_set_write_callback(playback, audioCallback, this); - bool + pa_threaded_mainloop_signal(m , 0); + + pa_stream_set_state_callback(record, stream_state_callback, NULL); + // Transferring Data - Asynchronous Mode + pa_stream_set_read_callback(record, audioCallback, this); + pa_stream_connect_record( record, NULL , NULL , flag ); + +} + + bool PulseLayer::openDevice(int indexIn, int indexOut, int sampleRate, int frameSize , int stream, std::string plugin) { _sampleRate = sampleRate; _frameSize = frameSize; - //sample_spec.rate = sampleRate; - //sample_spec.format = PA_SAMPLE_S16LE; - //sample_spec.channels = 1; - //channel_map.channels = 1; - //pa_stream_flags_t flag = PA_STREAM_START_CORKED ; - _debug(" Setting PulseLayer: device in=%2d, out=%2d\n", indexIn, indexOut); _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; - assert(context && !playback && !record); - _debug("Connection to PulseAudio server established\n"); - playback = pa_stream_new( context, "playback stream" , &sample_spec, &channel_map); - record = pa_stream_new( context, "capture stream" , &sample_spec, &channel_map); + m = pa_threaded_mainloop_new(); + assert(m); - assert(playback); - assert(record); + if( pa_threaded_mainloop_start( m ) < 0 ){ + _debug("Failed starting the mainloop\n"); + } - // Set up the parameters required to open a (Callback)Stream: + // Instanciate a context + if( !(context = pa_context_new( pa_threaded_mainloop_get_api( m ) , "SFLphone" ))) + _debug("Error while creating the context\n"); - 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 ); + assert(context); - 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); - }*/ + connectPulseServer(); + + _debug("Connection Done!! \n"); } -void + void PulseLayer::closeCaptureStream( void ) { } -void + void PulseLayer::closePlaybackStream( void ) { } -int + int PulseLayer::playSamples(void* buffer, int toCopy, bool isTalking) { } @@ -189,6 +216,15 @@ PulseLayer::playSamples(void* buffer, int toCopy, bool isTalking) int PulseLayer::putMain(void* buffer, int toCopy) { + int a = _mainSndRingBuffer.AvailForPut(); + if ( a >= toCopy ) { + return _mainSndRingBuffer.Put(buffer, toCopy, 100); + } else { + _debug("Chopping sound, Ouch! RingBuffer full ?\n"); + return _mainSndRingBuffer.Put(buffer, a, 100); + } + + return 0; } void @@ -204,11 +240,13 @@ PulseLayer::putUrgent(void* buffer, int toCopy) int PulseLayer::canGetMic() { + return 882; } int PulseLayer::getMic(void *buffer, int toCopy) { + return 160; } void @@ -221,29 +259,89 @@ PulseLayer::isStreamStopped (void) { } - void + void PulseLayer::startStream (void) { _debug("Start stream\n"); + //pa_stream_cork( playback , 0, NULL, NULL); } - void + void PulseLayer::stopStream (void) { _debug("Stop stream\n"); + pa_stream_drop( playback ); } - bool + bool PulseLayer::isStreamActive (void) { } - void -PulseLayer::audioCallback ( pa_stream* s, size_t bytes, void* user_data ) +PulseLayer::audioCallback ( pa_stream* s, size_t bytes, void* userdata ) { - _debug("Audio callback: New data may be written to the stream\n"); + pa_threaded_mainloop_signal( m , 0); + + assert( s && bytes ); + + PulseLayer* pulse = (PulseLayer*) userdata; + pulse->write(); + //if(pa_stream_get_state(s) == PA_STREAM_READY ) + //{ + //if( bytes > 0 ){ + // pa_stream_write( s, user_data, bytes, pa_xfree, 0, PA_SEEK_RELATIVE ); + //} + //} // pa_stream_write - // pa_stream_peek ( to read the next fragment from the buffer ) / pa_stream_drop( to remove the data from the buffer ) + // // pa_stream_peek ( to read the next fragment from the buffer ) / pa_stream_drop( to remove the data from the buffer ) + // + // int toPut; + // int urgentAvail; // number of data right and data left + // int micAvailPut; + // + // // 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 { + + // } + // } + // + // // 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); + } + void +PulseLayer::write( void ) +{ + int toGet; + int normalAvail; // number of data right and data left + SFLDataFormat* out = (SFLDataFormat*)malloc(framesPerBuffer * sizeof(SFLDataFormat)); + normalAvail = _mainSndRingBuffer.AvailForGet(); + toGet = (normalAvail < (int)(framesPerBuffer * sizeof(SFLDataFormat))) ? normalAvail : framesPerBuffer * sizeof(SFLDataFormat); + if (toGet) { + _mainSndRingBuffer.Get(out, toGet, 100); + _debug("Write %i bytes\n" , toGet); + pa_stream_write( playback , out , toGet , pa_xfree, 0 , PA_SEEK_RELATIVE); + _mainSndRingBuffer.Discard(toGet); + } else { + bzero(out, framesPerBuffer * sizeof(SFLDataFormat)); + } +} diff --git a/src/audio/pulselayer.h b/src/audio/pulselayer.h index a4e1b3bb81d896da584e77eb132c1884b9460d59..a63ce2319b635c524061e1722e5c4a3c658dd173 100644 --- a/src/audio/pulselayer.h +++ b/src/audio/pulselayer.h @@ -74,7 +74,7 @@ class PulseLayer : public AudioLayer { */ int playSamples(void* buffer, int toCopy, bool isTalking) ; - static void audioCallback ( pa_stream* s, size_t bytes, void* user_data ); + static void audioCallback ( pa_stream* s, size_t bytes, void* userdata ); static void stream_state_callback( pa_stream* s, void* user_data ); static void context_state_callback( pa_context* c, void* user_data ); @@ -123,12 +123,16 @@ class PulseLayer : public AudioLayer { */ void closeCaptureStream( void ); + void write( void ); + void createStreams( pa_context* c ); /** * Drop the pending frames and close the playback device */ void closePlaybackStream( void ); - void create_context( void ); + void connectPulseServer( void ); + + RingBuffer _mainSndRingBuffer; //pa_stream* playback; //pa_stream* record; diff --git a/src/managerimpl.cpp b/src/managerimpl.cpp index b100deefd92b1434af35e073187a7028d147c81d..08f0360d4f35879c86b950b657e165a5d9042c39 100644 --- a/src/managerimpl.cpp +++ b/src/managerimpl.cpp @@ -715,8 +715,14 @@ ManagerImpl::playATone(Tone::TONEID toneId) { unsigned int nbSampling = audioloop->getSize(); AudioLayer* audiolayer = getAudioDriver(); SFLDataFormat buf[nbSampling]; - if ( audiolayer ) { + if ( audiolayer ) { + int layer = audiolayer->getLayerType(); +#if CHECK_INTERFACE( layer , ALSA ) audiolayer->putUrgent( buf, nbSampling ); +#else + // Pulseaudio code + // startStream()?; +#endif } else return false; @@ -734,7 +740,11 @@ ManagerImpl::stopTone(bool stopAudio=true) { if (stopAudio) { AudioLayer* audiolayer = getAudioDriver(); - //if (audiolayer) { audiolayer->stopStream(); } + int layer = audiolayer->getLayerType(); +#if CHECK_INTERFACE( layer , ALSA ) +#else + //if (audiolayer) { audiolayer->stopStream(); } +#endif } _toneMutex.enterMutex(); @@ -799,6 +809,7 @@ ManagerImpl::ringtone() } AudioLayer* audiolayer = getAudioDriver(); + int layer = audiolayer->getLayerType(); if (audiolayer==0) { return; } int sampleRate = audiolayer->getSampleRate(); AudioCodec* codecForTone = _codecDescriptorMap.getFirstCodecAvailable(); @@ -810,10 +821,15 @@ ManagerImpl::ringtone() _toneMutex.enterMutex(); _audiofile.start(); _toneMutex.leaveMutex(); +#if CHECK_INTERFACE( layer, ALSA ) int size = _audiofile.getSize(); SFLDataFormat output[ size ]; _audiofile.getNext(output, size , 100); audiolayer->putUrgent( output , size ); +#else + // pulseaudio code + startStream(); +#endif } else { ringback(); } @@ -852,6 +868,7 @@ ManagerImpl::notificationIncomingCall(void) { AudioLayer* audiolayer = getAudioDriver(); if (audiolayer != 0) { + int layer = audiolayer->getLayerType(); unsigned int samplerate = audiolayer->getSampleRate(); std::ostringstream frequency; frequency << "440/" << FRAME_PER_BUFFER; @@ -860,7 +877,11 @@ ManagerImpl::notificationIncomingCall(void) { unsigned int nbSampling = tone.getSize(); SFLDataFormat buf[nbSampling]; tone.getNext(buf, tone.getSize()); +#if CHECK_INTERFACE( layer , ALSA ) audiolayer->playSamples(buf, sizeof(SFLDataFormat)*nbSampling, true); +#else + audiolayer->putUrgent( buf, sizeof(SFLDataFormat)*nbSampling ); +#endif } } @@ -1158,6 +1179,8 @@ ManagerImpl::getOutputAudioPluginList(void) void ManagerImpl::setInputAudioPlugin(const std::string& audioPlugin) { + int layer = _audiodriver -> getLayerType(); +#if CHECK_INTERFACE( layer , ALSA ) _debug("Set input audio plugin\n"); _audiodriver -> setErrorMessage( -1 ); _audiodriver -> openDevice( _audiodriver -> getIndexIn(), @@ -1168,6 +1191,8 @@ ManagerImpl::setInputAudioPlugin(const std::string& audioPlugin) audioPlugin); if( _audiodriver -> getErrorMessage() != -1) notifyErrClient( _audiodriver -> getErrorMessage() ); +#else +#endif } /** @@ -1176,6 +1201,8 @@ ManagerImpl::setInputAudioPlugin(const std::string& audioPlugin) void ManagerImpl::setOutputAudioPlugin(const std::string& audioPlugin) { + int layer = _audiodriver -> getLayerType(); +#if CHECK_INTERFACE( layer , ALSA ) _debug("Set output audio plugin\n"); _audiodriver -> setErrorMessage( -1 ); _audiodriver -> openDevice( _audiodriver -> getIndexIn(), @@ -1188,6 +1215,8 @@ ManagerImpl::setOutputAudioPlugin(const std::string& audioPlugin) notifyErrClient( _audiodriver -> getErrorMessage() ); // set config setConfig( AUDIO , ALSA_PLUGIN , audioPlugin ); +#else +#endif } /** @@ -1206,6 +1235,8 @@ ManagerImpl::getAudioOutputDeviceList(void) void ManagerImpl::setAudioOutputDevice(const int index) { + int layer = _audiodriver -> getLayerType(); +#if CHECK_INTERFACE( layer , ALSA ) _debug("Set audio output device: %i\n", index); _audiodriver -> setErrorMessage( -1 ); _audiodriver->openDevice(_audiodriver->getIndexIn(), @@ -1218,6 +1249,8 @@ ManagerImpl::setAudioOutputDevice(const int index) notifyErrClient( _audiodriver -> getErrorMessage() ); // set config setConfig( AUDIO , ALSA_CARD_ID_OUT , index ); +#else +#endif } /** @@ -1236,6 +1269,8 @@ ManagerImpl::getAudioInputDeviceList(void) void ManagerImpl::setAudioInputDevice(const int index) { + int layer = _audiodriver -> getLayerType(); +#if CHECK_INTERFACE( layer , ALSA ) _debug("Set audio input device %i\n", index); _audiodriver -> setErrorMessage( -1 ); _audiodriver->openDevice(index, @@ -1248,6 +1283,8 @@ ManagerImpl::setAudioInputDevice(const int index) notifyErrClient( _audiodriver -> getErrorMessage() ); // set config setConfig( AUDIO , ALSA_CARD_ID_IN , index ); +#else +#endif } /**