Commit a2a04360 authored by Emmanuel Milou's avatar Emmanuel Milou

Better hardware description + capture quality improved

The user can change the sound card, but not the plugin device.
Plugin device used: for capture --> plug:surround40 --> better sound quality
			playback --> plug:dmix
Dmtf working
Still no ringtones
parent d3febeef
......@@ -201,6 +201,7 @@ select_active_output_audio_device()
// Select active output device on server
devices = dbus_get_current_audio_devices_index();
currentDeviceIndex = atoi(devices[0]);
printf("audio device index for output = %d\n", currentDeviceIndex);
model = gtk_combo_box_get_model(GTK_COMBO_BOX(outputDeviceComboBox));
// Find the currently set output device
......@@ -346,8 +347,8 @@ detect_all_audio_settings()
config_window_fill_input_audio_device_list();
// Select active device in combo box
select_active_output_audio_device();
select_active_input_audio_device();
//select_active_output_audio_device();
//select_active_input_audio_device();
}
/**
......@@ -915,7 +916,7 @@ create_audio_tab ()
outputAudioDeviceManagerStore = gtk_list_store_new(2, G_TYPE_STRING, G_TYPE_INT);
config_window_fill_output_audio_device_list();
outputDeviceComboBox = gtk_combo_box_new_with_model(GTK_TREE_MODEL(outputAudioDeviceManagerStore));
// select_active_output_audio_device();
//select_active_output_audio_device();
gtk_label_set_mnemonic_widget(GTK_LABEL(titleLabel), outputDeviceComboBox);
g_signal_connect(G_OBJECT(outputDeviceComboBox), "changed", G_CALLBACK(select_audio_output_device), outputDeviceComboBox);
......@@ -936,7 +937,7 @@ create_audio_tab ()
inputAudioDeviceManagerStore = gtk_list_store_new(2, G_TYPE_STRING, G_TYPE_INT);
config_window_fill_input_audio_device_list();
inputDeviceComboBox = gtk_combo_box_new_with_model(GTK_TREE_MODEL(inputAudioDeviceManagerStore));
select_active_input_audio_device();
//select_active_input_audio_device();
gtk_label_set_mnemonic_widget(GTK_LABEL(titleLabel), inputDeviceComboBox);
g_signal_connect(G_OBJECT(inputDeviceComboBox), "changed", G_CALLBACK(select_audio_input_device), inputDeviceComboBox);
......
......@@ -43,25 +43,11 @@
, _capture_handle( NULL )
, device_closed( true )
{
//_sampleRate = 8000;
_inChannel = 1; // don't put in stereo
_outChannel = 1; // don't put in stereo
_echoTesting = false;
get_alsa_version();
//getHardware(2);
#ifdef SFL_TEST_SINE
leftPhase_ = 0;
tableSize_ = 200;
const double PI = 3.14159265;
table_ = new float[tableSize_];
for (int i = 0; i < tableSize_; ++i)
{
table_[i] = 0.125f * (float)sin(((double)i/(double)tableSize_)*PI*2.);
_debug("%9.8f\n", table_[i]);
}
#endif
}
// Destructor
......@@ -78,9 +64,6 @@ AudioLayer::~AudioLayer (void)
snd_pcm_close( _playback_handle );
_playback_handle = 0;
}
#ifdef SFL_TEST_SINE
delete [] table_;
#endif
}
......@@ -119,9 +102,9 @@ AudioLayer::openDevice (int indexIn, int indexOut, int sampleRate, int frameSize
ost::MutexLock guard( _mutex );
std::string pcmp = buildDeviceTopo(PCM_DMIX, indexOut );
std::string pcmc = buildDeviceTopo(PCM_FRONT, indexIn );
return open_device( pcmp , pcmc, flag);
std::string pcmp = buildDeviceTopo(PCM_DMIX, indexOut , 0);
std::string pcmc = buildDeviceTopo(PCM_SURROUND40, indexIn , 0);
return open_device( pcmp , pcmc , flag);
}
int
......@@ -136,8 +119,7 @@ AudioLayer::startStream(void)
{
_debug(" Start stream\n");
ost::MutexLock guard( _mutex );
//snd_pcm_wait( _capture_handle , 40);
//snd_pcm_prepare( _capture_handle );
snd_pcm_prepare( _capture_handle );
snd_pcm_start( _capture_handle ) ;
//snd_pcm_start( _playback_handle ) ;
}
......@@ -149,8 +131,6 @@ AudioLayer::stopStream(void)
ost::MutexLock guard( _mutex );
snd_pcm_drop( _capture_handle );
snd_pcm_prepare( _capture_handle );
//snd_pcm_drop( _playback_handle );
//snd_pcm_prepare( _playback_handle );
}
......@@ -164,10 +144,7 @@ AudioLayer::sleep(int msec)
AudioLayer::isStreamActive (void)
{
ost::MutexLock guard( _mutex );
if(!device_closed)
return true;
else
return false;
return (isPlaybackActive() && isCaptureActive());
}
......@@ -176,6 +153,7 @@ AudioLayer::playSamples(void* buffer, int toCopy)
{
ost::MutexLock guard( _mutex );
if ( _playback_handle ){
//_debug("Play samples\n");
write(buffer, toCopy);
}
return 0;
......@@ -232,7 +210,7 @@ AudioLayer::getMic(void *buffer, int toCopy)
AudioLayer::isStreamStopped (void)
{
ost::MutexLock guard( _mutex );
return !(is_playback_active() & is_capture_active());
return !(isStreamActive());
}
void
......@@ -273,13 +251,9 @@ 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;
unsigned int period_count_in = 2;
//snd_pcm_uframes_t period_size_in = 2048; //rate_in * _frameSize / 1000 ;
snd_pcm_uframes_t period_size_in = getFrameSize() * getSampleRate() / 1000 ;
snd_pcm_uframes_t buffer_size_in = 4096;
snd_pcm_uframes_t threshold = getFrameSize() * getSampleRate() / 1000 ;
_debugAlsa("Start threshold for mic =%i\n", threshold);
unsigned int period_count_out = 2;
snd_pcm_uframes_t period_size_out = 2048 ;
snd_pcm_uframes_t buffer_size_out = 4096 ;
snd_pcm_sw_params_t *swparams = NULL;
......@@ -291,6 +265,7 @@ AudioLayer::open_device(std::string pcm_p, std::string pcm_c, int flag)
_debug(" Error while opening capture device %s (%s)\n", pcm_c.c_str(), snd_strerror(err));
return false;
}
if( err = snd_pcm_hw_params_malloc( &hwparams ) < 0 ) {
_debug(" Cannot allocate hardware parameter structure (%s)\n", snd_strerror(err));
return false;
......@@ -341,60 +316,73 @@ AudioLayer::open_device(std::string pcm_p, std::string pcm_c, int flag)
snd_pcm_sw_params_current( _playback_handle, swparams );
if( err = snd_pcm_sw_params_set_start_threshold( _playback_handle, swparams, val ) < 0 ) _debug(" Cannot set start threshold (%s)\n", snd_strerror(err));
if( err = snd_pcm_sw_params_set_stop_threshold( _playback_handle, swparams, val * 4 ) < 0 ) _debug(" Cannot get stop threshold (%s)\n", snd_strerror(err));
if( err = snd_pcm_sw_params_set_stop_threshold( _playback_handle, swparams, buffer_size_out ) < 0 ) _debug(" Cannot set stop threshold (%s)\n", snd_strerror(err));
if( err = snd_pcm_sw_params( _playback_handle, swparams ) < 0 ) _debug(" Cannot set sw parameters (%s)\n", snd_strerror(err));
device_closed = false;
}
return true;
}
bool
AudioLayer::is_playback_active( void )
{
if(snd_pcm_state(_playback_handle) == SND_PCM_STATE_RUNNING)
return true;
else
return false;
}
bool
AudioLayer::is_capture_active( void )
{
if(snd_pcm_state(_capture_handle) == SND_PCM_STATE_RUNNING)
return true;
else
return false;
}
int
AudioLayer::write(void* buffer, int length)
{
if(device_closed || _playback_handle == NULL)
return 0;
int bytes;
short* buff = (short*) buffer;
int result = 0 ;
snd_pcm_uframes_t frames = snd_pcm_bytes_to_frames( _playback_handle, length);
if( bytes = snd_pcm_writei( _playback_handle, buffer, frames) < 0 ) {
snd_pcm_prepare( _playback_handle );
_debug(" Playback error (%s)\n", snd_strerror(bytes));
return 0;
while( frames > 0 )
{
bytes = snd_pcm_writei( _playback_handle, buff, frames);
if( bytes == -EAGAIN || (bytes >=0 && bytes < frames))
{
//snd_pcm_wait( _playback_handle, 20 );
break;
}
else if( bytes == -EPIPE )
{
_debugAlsa(" %d Alsa error from writei (%s)\n", bytes, snd_strerror(bytes));
snd_pcm_prepare( _playback_handle );
snd_pcm_writei( _playback_handle , buff , frames );
break;
}
return 1;
else if( bytes == -ESTRPIPE )
{
_debug(" Playback suspend \n");
snd_pcm_resume( _playback_handle );
break;
}
if( bytes != frames)
{
_debug(" Short write\n");
frames -= bytes;
buff += bytes;
}
}
return 0;
}
int
AudioLayer::read( void* target_buffer, int toCopy)
AudioLayer::read( void* buffer, int toCopy)
{
if(device_closed || _capture_handle == NULL)
return 0;
int err;
if(snd_pcm_state( _capture_handle ) == SND_PCM_STATE_XRUN)
snd_pcm_prepare( _capture_handle );
snd_pcm_uframes_t frames = snd_pcm_bytes_to_frames( _capture_handle, toCopy);
if( err = snd_pcm_readi( _capture_handle, target_buffer, frames) < 0 ) {
snd_pcm_uframes_t frames = snd_pcm_bytes_to_frames( _capture_handle, toCopy );
if( err = snd_pcm_readi( _capture_handle, buffer, frames) < 0 ) {
switch(err){
case EPERM:
_debug(" Capture EPERM (%s)\n", snd_strerror(err));
......@@ -418,7 +406,9 @@ AudioLayer::read( void* target_buffer, int toCopy)
}
return 0;
}
return toCopy;
}
void
......@@ -439,28 +429,19 @@ AudioLayer::handle_xrun_state( void )
_debug(" Get status failed\n");
}
std::string
AudioLayer::get_alsa_version( void )
{
std::stringstream out;
std::string version;
std::ifstream file( "/proc/asound/version" );
out << file.rdbuf();
version = out.str();
_debugAlsa("%s\n", version.c_str());
return version;
}
std::string
AudioLayer::buildDeviceTopo( std::string prefixe, int suffixe)
AudioLayer::buildDeviceTopo( std::string plugin, int card, int subdevice )
{
if( prefixe == PCM_DEFAULT)
return prefixe;
std::string pcm = prefixe;
std::ostringstream ss;
ss << suffixe;
std::string pcm = plugin;
std::stringstream ss,ss1;
ss << card;
pcm.append(":");
pcm.append(ss.str());
if( subdevice != 0 ){
pcm.append(",");
ss1 << subdevice;
pcm.append(ss1.str());
}
return pcm;
}
......@@ -477,7 +458,7 @@ AudioLayer::getSoundCardsInfo( int flag )
int numCard = -1 ;
int err;
int dev = -1;
std::string description;
if(snd_card_next( &numCard ) < 0 || numCard < 0)
return cards_id;
......@@ -498,16 +479,19 @@ AudioLayer::getSoundCardsInfo( int flag )
if( snd_ctl_pcm_info ( handle ,pcminfo ) < 0) _debug(" Cannot get info\n");
else{
_debug("card %i : %s [%s]- device %i : %s [%s]\n - driver %s - dir %i\n",
_debug("card %i : %s [%s]- device %i : %s [%s] \n - driver %s - dir %i\n",
numCard,
snd_ctl_card_info_get_id(info),
snd_ctl_card_info_get_name( info ),
numCard,
snd_pcm_info_get_device( pcminfo ),
snd_pcm_info_get_id(pcminfo),
snd_pcm_info_get_name( pcminfo),
snd_ctl_card_info_get_driver( info ),
snd_pcm_info_get_stream( pcminfo ) );
cards_id.push_back(snd_ctl_card_info_get_name( info ));
snd_pcm_info_get_stream( pcminfo ));
description = snd_ctl_card_info_get_name( info );
description.append(" - ");
description.append(snd_pcm_info_get_name( pcminfo ));
cards_id.push_back( description );
}
}
snd_ctl_close( handle );
......@@ -519,3 +503,4 @@ AudioLayer::getSoundCardsInfo( int flag )
}
return cards_id;
}
......@@ -45,55 +45,139 @@ class AudioLayer {
~AudioLayer(void);
/*
* @param indexIn
* @param indexOut
* @param sampleRate
* @param frameSize
* @param flag - 0 --> open playback and capture ; 1 --> open playback only ; 2 --> open capture only
* 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 flag To indicate which kind of stream you want to open
* SFL_PCM_CAPTURE
* SFL_PCM_PLAYBACK
* SFL_PCM_BOTH
*/
bool openDevice(int, int, int, int, int);
/*
* Start the capture stream. The playback starts according th its threshold
* ALSA Library API
*/
void startStream(void);
/*
* Stop the capture stream. The playback stops according to its threshold
* Drops the pending frames and put the capture handle to PREPARED state
* ALSA Library API
*/
void stopStream(void);
void sleep(int);
/*
* Check if the playback is running
* @return true if the state of the playback handle equals SND_PCM_STATE_RUNNING
* false otherwise
*/
bool isPlaybackActive( void );
/*
* Check if the capture is running
* @return true if the state of the capture handle equals SND_PCM_STATE_RUNNING
* false otherwise
*/
bool isCaptureActive( void );
/*
* Check if both capture and playback are running
* @return true if capture and playback are running
* false otherwise
*/
bool isStreamActive(void);
/*
* Check if both capture and playback are stopped
* @return true if capture and playback are stopped
* false otherwise
*/
bool isStreamStopped(void);
void closeStream();
/*
* Send samples to the audio device
* @params buffer The buffer containing the data to be played
* @params toCopy The number of samples, in bytes
* @return int The number of bytes played
*/
int playSamples(void* buffer, int toCopy);
int playRingTone( void* buffer, int toCopy);
int putUrgent(void* buffer, int toCopy);
/*
* Query the audio devices for number of bytes available in the hardware ring buffer
* @return int The number of bytes available
*/
int canGetMic();
int getMic(void *, int);
std::string buildDeviceTopo( std::string prefixe, int suffixe);
/*
* Get data from the capture device
* @param buffer The buffer for data
* @param toCopy The number of bytes to get
* @return int The number of bytes acquired ( 0 if an error occured)
*/
int getMic(void * buffer, int toCopy);
/*
* Concatenate two strings. Used to build a valid pcm device name.
* @param plugin the alsa PCM name
* @param card the sound card number
* @param subdevice the subdevice number
* @return std::string the concatenated string
*/
std::string buildDeviceTopo( std::string plugin, int card, int subdevice );
/*
* Scan the sound card available on the system
* @param flag To indicate whether we are looking for capture devices or playback devices
* SFL_PCM_CAPTURE
* SFL_PCM_PLAYBACK
* SFL_PCM_BOTH
* @return std::vector<std::string> The vector containing the string description of the card
*/
std::vector<std::string> getSoundCardsInfo( int flag );
void setErrorMessage(const std::string& error) { _errorMessage = error; }
std::string getErrorMessage() { return _errorMessage; }
/**
* Get the sample rate of audiolayer
* accessor only
/*
* Get the index of the audio card for capture
* @return _indexIn The index of the card used for capture
* 0 for the first available card on the system, 1 ...
*/
int getIndexIn() { return _indexIn; }
int getIndexOut() { return _indexOut; }
unsigned int getSampleRate() { return _sampleRate; }
unsigned int getFrameSize() { return _frameSize; }
int getDeviceCount();
void playSinusWave();
// NOW
//void selectPreferedApi(PaHostApiTypeId apiTypeID, int& outputDeviceIndex, int& inputDeviceIndex);
//std::vector<std::string> getAudioDeviceList(PaHostApiTypeId apiTypeID, int ioDeviceMask);
/*
* Get the index of the audio card for playback
* @return _indexOut The index of the card used for playback
* 0 for the first available card on the system, 1 ...
*/
int getIndexOut() { return _indexOut; }
/*
* Get the sample rate of the audio layer
* @return unsigned int The sample rate
* default: 44100 HZ
*/
unsigned int getSampleRate() { return _sampleRate; }
//AudioDevice* getAudioDeviceInfo(int index, int ioDeviceMask);
/*
* Get the frame size of the audio layer
* @return unsigned int The frame size
* default: 20 ms
*/
unsigned int getFrameSize() { return _frameSize; }
enum IODEVICE {InputDevice=0x01, OutputDevice=0x02 };
int getDeviceCount();
/**
* Toggle echo testing on/off
......@@ -101,23 +185,64 @@ class AudioLayer {
void toggleEchoTesting();
private:
bool open_device( std::string , std::string , int);
int write( void* , int );
int read( void*, int );
bool is_playback_active( void );
bool is_capture_active( void );
/*
* Open the specified device.
* ALSA Library API
* @param pcm_p The string name for the playback device
* pcm_c The string name for the capture device
* flag To indicate which kind of stream you want to open
* SFL_PCM_CAPTURE
* SFL_PCM_PLAYBACK
* SFL_PCM_BOTH
* @return true if successful
* false otherwise
*/
bool open_device( std::string pcm_p, std::string pcm_c, int flag);
/*
* Copy a data buffer in the internal ring buffer
* ALSA Library API
* @param buffer The data to be copied
* length The size of the buffer
* @return int The number of frames actually copied
*/
int write( void* buffer, int length);
/*
* Read data from the internal ring buffer
* ALSA Library API
* @param buffer The buffer to stock the read data
* toCopy The number of bytes to get
* @return int The number of frames actually read
*/
int read( void* buffer, int toCopy);
/*
* Recover from XRUN state for capture
* ALSA Library API
*/
void handle_xrun_state( void );
std::string get_alsa_version( void );
ManagerImpl* _manager; // augment coupling, reduce indirect access
// a audiolayer can't live without manager
/*
* Handle to manipulate capture and playback streams
* ALSA Library API
*/
snd_pcm_t* _playback_handle;
snd_pcm_t* _capture_handle;
/*
* Enable to determine if the devices are opened or not
* true if the devices are closed
* false otherwise
*/
bool device_closed;
/**
* Portaudio indexes of audio devices on which stream has been opened
* Number of audio cards on which stream has been opened
*/
int _indexIn;
int _indexOut;
......
......@@ -74,9 +74,16 @@ typedef short int16;
#define CHANNELS 2
#define SIZEBUF 1024*1024
#define PCM_PLUGHW "plughw"
#define PCM_FRONT "plug:front"
#define PCM_DEFAULT "default"
#define PCM_DMIX "plug:dmix"
#define PCM_SURROUND40 "plug:surround40"
#define PCM_SURROUND41 "plug:surround41"
#define PCM_SURROUND50 "plug:surround50"
#define PCM_SURROUND51 "plug:surround51"
#define PCM_SURROUND71 "plug:surround71"
#define PCM_IEC958 "plug:iec958"
#define SFL_PCM_BOTH 0x0021
#define SFL_PCM_PLAYBACK 0x0022
......
......@@ -555,7 +555,7 @@ ManagerImpl::playDtmf(char code)
try {
// We activate the stream if it's not active yet.
if (!audiolayer->isStreamActive()) {
audiolayer->startStream();
//audiolayer->startStream();
} else {
audiolayer->sleep(pulselen); // in milliseconds
}
......@@ -814,26 +814,21 @@ ManagerImpl::playATone(Tone::TONEID toneId) {
_telephoneTone->setCurrentTone(toneId);
_toneMutex.leaveMutex();
/*AudioLoop* audioloop = getTelephoneTone();
unsigned int nbSampling = audioloop->getSize();
_debug("Telephone tone size = %d\n", nbSampling);
SFLDataFormat buf[nbSampling];*/
//audioloop->getNext(buf, audioloop->getSize());
//audiolayer->putUrgent(buf, sizeof(SFLDataFormat)*nbSampling);
try {
AudioLayer* audiolayer = getAudioDriver();
if (audiolayer) {
_debug("Should ring back\n");
//audiolayer->playRingTone( buf, sizeof(SFLDataFormat)*nbSampling);
audiolayer->startStream();
}
} catch(...) {
_debugException("Off hold could not start audio stream");
return false;
AudioLoop* audioloop = getTelephoneTone();
unsigned int nbSampling = audioloop->getSize();
_debug("Telephone tone size = %d\n", nbSampling);
AudioLayer* audiolayer = getAudioDriver();
//int chunks = 2000;
SFLDataFormat buf[nbSampling];
audioloop->getNext(buf, audioloop->getSize());
if (audiolayer) {
audiolayer->putUrgent( buf, sizeof(SFLDataFormat)*nbSampling);
///buf += chunks;
}
else
return false;