Commit ab4cf8b8 authored by Julien Bonjean's avatar Julien Bonjean

Merge branch 'master' of http://sflphone.org/git/sflphone into work

parents 0bb402f2 eeedc470
sflphone (0.9.3-0ubuntu3) %system%; urgency=low
[ Alexandre Savard ]
* Both playback and record streams in PA_STREAM_CORKED (pulseaudio)
* Use PLUGHW device for ALSA capture
* Functional IAX and SIP recording for voicemail
* Use the less CPU-consuming interpolator algorithm for resampling
* Display in GTK GUI the codec used in conversation
* GTK GUI use ASCII instread of utf-8
* Add record menus in GTK GUI
* Put on hold when dialing a new number
* AccountID's are saved in the history
[ Emmanuel Milou ]
* Integrate DBUS C++, libiax2 in the git repository
* Update website
* Use libspeexdsp only if available on the system
* Updated .gitignore file
[Cyrille Béraud]
* Account assistant manager improvment
* Add an email request when creating a new account to receive voicemails
-- Emmanuel Milou <emmanuel.milou@savoirfairelinux.com> Sat, 14 Feb 2009 13:29:15 -0500
sflphone (0.9.3-0ubuntu2) %system%; urgency=low
[ Emmanuel Milou ]
......
......@@ -104,7 +104,7 @@ AlsaLayer::openDevice (int indexIn, int indexOut, int sampleRate, int frameSize,
ost::MutexLock lock( _mutex );
std::string pcmp = buildDeviceTopo( plugin , indexOut , 0);
std::string pcmc = buildDeviceTopo( plugin , indexIn , 0);
std::string pcmc = buildDeviceTopo( PCM_PLUGHW , indexIn , 0);
return open_device( pcmp , pcmc , stream);
}
......@@ -122,7 +122,7 @@ AlsaLayer::startStream(void)
void
AlsaLayer::stopStream(void)
{
_debug ("Stop ALSA streams\n");
_debug ("AlsaLayer::stopStream :: Stop ALSA streams\n");
stopCaptureStream ();
//stopPlaybackStream ();
......@@ -190,9 +190,13 @@ bool AlsaLayer::isCaptureActive(void) {
void AlsaLayer::stopCaptureStream (void)
{
int err;
if(_CaptureHandle){
snd_pcm_drop (_CaptureHandle);
err = snd_pcm_drop (_CaptureHandle);
_debug("AlsaLayer::stopCaptureStream snd_pcm_drop returned vaue : %i\n",err);
stop_capture ();
_debug("Wroking here !!!!!!!!!!!!!!!\n");
}
}
......@@ -373,7 +377,8 @@ AlsaLayer::open_device(std::string pcm_p, std::string pcm_c, int flag)
if(flag == SFL_PCM_BOTH || flag == SFL_PCM_PLAYBACK)
{
if((err = snd_pcm_open(&_PlaybackHandle, pcm_p.c_str(), SND_PCM_STREAM_PLAYBACK, 0 )) < 0){
// if((err = snd_pcm_open(&_PlaybackHandle, pcm_p.c_str(), SND_PCM_STREAM_PLAYBACK, 0 )) < 0){
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());
setErrorMessage( ALSA_PLAYBACK_DEVICE );
close_playback ();
......
......@@ -493,6 +493,7 @@ AudioRtpRTX::run () {
}
// _debug("stop stream for audiortp loop\n");
_debug("AudioRtpRTX::run () :: This is bad when holding a call!!!!!!!\n");
audiolayer->stopStream();
_debug("- ARTP Action: Stop call %s\n",_ca->getCallId().c_str());
//} catch(std::exception &e) {
......
......@@ -53,7 +53,7 @@ AudioStream::disconnect( void )
void
AudioStream::stream_state_callback( pa_stream* s, void* user_data UNUSED )
{
_debug("The state of the stream changed\n");
_debug("AudioStream::stream_state_callback :: The state of the stream changed\n");
assert(s);
switch(pa_stream_get_state(s)){
case PA_STREAM_CREATING:
......@@ -64,7 +64,8 @@ AudioStream::stream_state_callback( pa_stream* s, void* user_data UNUSED )
PulseLayer::streamState++;
break;
case PA_STREAM_READY:
_debug("Stream successfully created, connected to %s\n", pa_stream_get_device_name( s ));
_debug("Stream successfully created, connected to %s\n", pa_stream_get_device_name( s ));
break;
case PA_STREAM_UNCONNECTED:
_debug("Stream unconnected\n");
......@@ -78,6 +79,8 @@ AudioStream::stream_state_callback( pa_stream* s, void* user_data UNUSED )
}
pa_stream*
AudioStream::createStream( pa_context* c )
{
......@@ -99,7 +102,7 @@ AudioStream::createStream( pa_context* c )
attributes->prebuf = 10000;
attributes->minreq = 940;
pa_stream_connect_playback( s , NULL , attributes,
PA_STREAM_INTERPOLATE_TIMING,
PA_STREAM_START_CORKED,
&_volume, NULL);
}
else if( _streamType == CAPTURE_STREAM ){
......
......@@ -30,6 +30,8 @@ static void audioCallback ( pa_stream* s, size_t bytes, void* userdata )
static_cast<PulseLayer*>(userdata)->processData();
}
PulseLayer::PulseLayer(ManagerImpl* manager)
: AudioLayer( manager , PULSEAUDIO )
, context(NULL)
......@@ -38,7 +40,7 @@ static void audioCallback ( pa_stream* s, size_t bytes, void* userdata )
, record()
{
PulseLayer::streamState = 0;
_debug("Pulse audio constructor: Create context\n");
_debug("PulseLayer::Pulse audio constructor: Create context\n");
}
// Destructor
......@@ -53,7 +55,7 @@ PulseLayer::~PulseLayer (void)
void
PulseLayer::closeLayer( void )
{
_debug(" Destroy pulselayer\n");
_debug("PulseLayer::closeLayer :: Destroy pulselayer\n");
playback->disconnect();
record->disconnect();
......@@ -69,6 +71,7 @@ PulseLayer::closeLayer( void )
void
PulseLayer::connectPulseAudioServer( void )
{
_debug("PulseLayer::connectPulseAudioServer \n");
pa_context_flags_t flag = PA_CONTEXT_NOAUTOSPAWN ;
pa_threaded_mainloop_lock( m );
......@@ -94,7 +97,7 @@ PulseLayer::connectPulseAudioServer( void )
void PulseLayer::context_state_callback( pa_context* c, void* user_data )
{
_debug("The state of the context changed\n");
_debug("PulseLayer::context_state_callback ::The state of the context changed\n");
PulseLayer* pulse = (PulseLayer*)user_data;
assert(c && pulse->m);
switch(pa_context_get_state(c)){
......@@ -105,7 +108,8 @@ void PulseLayer::context_state_callback( pa_context* c, void* user_data )
break;
case PA_CONTEXT_READY:
pulse->createStreams( c );
_debug("Connection to PulseAudio server established\n");
_debug("Connection to PulseAudio server established\n");
break;
case PA_CONTEXT_TERMINATED:
_debug("Context terminated\n");
......@@ -121,6 +125,7 @@ void PulseLayer::context_state_callback( pa_context* c, void* user_data )
void PulseLayer::disconnectPulseAudioServer( void )
{
_debug(" PulseLayer::disconnectPulseAudioServer( void ) \n");
if( playback )
delete playback; playback=NULL;
......@@ -128,22 +133,29 @@ void PulseLayer::disconnectPulseAudioServer( void )
delete record; record=NULL;
}
void
PulseLayer::createStreams( pa_context* c )
void PulseLayer::createStreams( pa_context* c )
{
_debug("PulseLayer::createStreams \n");
playback = new AudioStream(c, PLAYBACK_STREAM, PLAYBACK_STREAM_NAME, _manager->getSpkrVolume());
pa_stream_set_write_callback( playback->pulseStream() , audioCallback, this);
pa_stream_set_write_callback( playback->pulseStream(), audioCallback, this);
//pa_stream_set_overflow_callback( playback->pulseStream() , overflow , this);
// pa_stream_set_suspended_callback( playback->pulseStream(), stream_suspended_callback, this);
record = new AudioStream(c, CAPTURE_STREAM, CAPTURE_STREAM_NAME , _manager->getMicVolume());
pa_stream_set_read_callback( record->pulseStream() , audioCallback, this);
//pa_stream_set_underflow_callback( record->pulseStream() , underflow , this);
// pa_stream_set_suspended_callback(record->pulseStream(), stream_suspended_callback, this);
pa_threaded_mainloop_signal(m , 0);
}
bool
PulseLayer::openDevice(int indexIn UNUSED, int indexOut UNUSED, int sampleRate, int frameSize , int stream UNUSED, std::string plugin UNUSED)
bool PulseLayer::openDevice(int indexIn UNUSED, int indexOut UNUSED, int sampleRate, int frameSize , int stream UNUSED, std::string plugin UNUSED)
{
_debug("PulseLayer::openDevice \n");
_sampleRate = sampleRate;
_frameSize = frameSize;
......@@ -166,18 +178,15 @@ PulseLayer::openDevice(int indexIn UNUSED, int indexOut UNUSED, int sampleRate,
return true;
}
void
PulseLayer::closeCaptureStream( void )
void PulseLayer::closeCaptureStream( void )
{
}
void
PulseLayer::closePlaybackStream( void )
{
void PulseLayer::closePlaybackStream( void )
{
}
int
PulseLayer::canGetMic()
int PulseLayer::canGetMic()
{
if( record )
return _micRingBuffer.AvailForGet();
......@@ -185,8 +194,7 @@ PulseLayer::canGetMic()
return 0;
}
int
PulseLayer::getMic(void *buffer, int toCopy)
int PulseLayer::getMic(void *buffer, int toCopy)
{
if( record ){
return _micRingBuffer.Get(buffer, toCopy, 100);
......@@ -195,13 +203,15 @@ PulseLayer::getMic(void *buffer, int toCopy)
return 0;
}
void
PulseLayer::startStream (void)
void PulseLayer::startStream (void)
{
flushMic();
_debug("Start stream\n");
_debug("PulseLayer::Start stream\n");
pa_threaded_mainloop_lock(m);
pa_stream_cork( record->pulseStream(), NULL, NULL, NULL);
pa_stream_cork( playback->pulseStream(), 0, NULL, NULL);
pa_stream_cork( record->pulseStream(), 0, NULL, NULL);
pa_threaded_mainloop_unlock(m);
}
......@@ -209,9 +219,13 @@ PulseLayer::startStream (void)
void
PulseLayer::stopStream (void)
{
_debug("Stop stream\n");
_debug("PulseLayer::Stop stream\n");
pa_stream_flush( playback->pulseStream(), NULL, NULL );
pa_stream_flush( record->pulseStream(), NULL, NULL );
pa_stream_cork( playback->pulseStream(), 1, NULL, NULL);
pa_stream_cork( record->pulseStream(), 1, NULL, NULL);
flushMic();
flushMain();
flushUrgent();
......@@ -219,42 +233,48 @@ PulseLayer::stopStream (void)
void
PulseLayer::underflow ( pa_stream* s UNUSED, void* userdata UNUSED )
void PulseLayer::underflow ( pa_stream* s UNUSED, void* userdata UNUSED )
{
_debug("Buffer Underflow\n");
_debug("PulseLayer::Buffer Underflow\n");
}
void
PulseLayer::overflow ( pa_stream* s, void* userdata UNUSED )
void PulseLayer::overflow ( pa_stream* s, void* userdata UNUSED )
{
//PulseLayer* pulse = (PulseLayer*) userdata;
pa_stream_drop( s );
pa_stream_trigger( s, NULL, NULL);
}
void
PulseLayer::processData( void )
void PulseLayer::stream_suspended_callback(pa_stream *s, void *userdata UNUSED )
{
}
void PulseLayer::processData( void )
{
// Handle the mic
// We check if the stream is ready
if( (record->pulseStream()) && pa_stream_get_state( record->pulseStream()) == PA_STREAM_READY)
readFromMic();
// Handle the data for the speakers
if( (playback->pulseStream()) && pa_stream_get_state( playback->pulseStream()) == PA_STREAM_READY){
_debug("PulseLayer::processData() \n");
// Handle the mic
// We check if the stream is ready
if( (record->pulseStream()) && (pa_stream_get_state( record->pulseStream()) == PA_STREAM_READY))
readFromMic();
// _debug("PulseLayer::processData() playback->pulseStream() \n");
// Handle the data for the speakers
if( (playback->pulseStream()) && (pa_stream_get_state( playback->pulseStream()) == PA_STREAM_READY)){
// If the playback buffer is full, we don't overflow it; wait for it to have free space
if( pa_stream_writable_size(playback->pulseStream()) == 0 )
return;
writeToSpeaker();
}
}
void
PulseLayer::writeToSpeaker( void )
void PulseLayer::writeToSpeaker( void )
{
/** Bytes available in the urgent ringbuffer ( reserved for DTMF ) */
int urgentAvail;
......@@ -303,6 +323,7 @@ PulseLayer::writeToSpeaker( void )
else {
bzero(out, framesPerBuffer * sizeof(SFLDataFormat));
}
pa_stream_write( playback->pulseStream() , out , toGet , NULL, 0 , PA_SEEK_RELATIVE);
pa_xfree(out);
}
......
......@@ -24,6 +24,7 @@
#include "audiostream.h"
#include <pulse/pulseaudio.h>
#include <pulse/stream.h>
#define PLAYBACK_STREAM_NAME "SFLphone out"
#define CAPTURE_STREAM_NAME "SFLphone in"
......@@ -74,7 +75,8 @@ class PulseLayer : public AudioLayer {
static void overflow ( pa_stream* s, void* userdata );
static void underflow ( pa_stream* s, void* userdata );
static void stream_state_callback( pa_stream* s, void* user_data );
static void context_state_callback( pa_context* c, void* user_data );
static void context_state_callback( pa_context* c, void* user_data );
static void stream_suspended_callback ( pa_stream* s, void* userdata );
bool isCaptureActive (void){return true;}
......@@ -127,6 +129,7 @@ class PulseLayer : public AudioLayer {
void setMicVolume( int value ) { micVolume = value; }
void processData( void );
private:
// Copy Constructor
PulseLayer(const PulseLayer& rh);
......
......@@ -114,6 +114,7 @@ Tone::genBuffer(const std::string& definition)
void
Tone::genSin(SFLDataFormat* buffer, int frequency1, int frequency2, int nb)
{
double pi2 = 6.28318520;
double var1 = pi2 * (double)frequency1 / (double)_sampleRate;
double var2 = pi2 * (double)frequency2 / (double)_sampleRate;
......
......@@ -45,7 +45,7 @@ ToneGenerator::~ToneGenerator (void) {
void
ToneGenerator::generateSin (int lowerfreq, int higherfreq, int16* ptr, int len) const {
double var1, var2;
var1 = (double)2 * (double)M_PI * (double)higherfreq / (double)_sampleRate;
var2 = (double)2 * (double)M_PI * (double)lowerfreq / (double)_sampleRate;
......
......@@ -313,6 +313,7 @@ ManagerImpl::cancelCall (const CallID& id)
bool
ManagerImpl::onHoldCall(const CallID& id)
{
_debug("*************** ON HOLD ***********************************\n");
stopTone(true);
AccountID accountid = getAccountFromCall( id );
if (accountid == AccountNULL) {
......@@ -335,6 +336,7 @@ ManagerImpl::onHoldCall(const CallID& id)
bool
ManagerImpl::offHoldCall(const CallID& id)
{
_debug("*************** OFF HOLD ***********************************\n");
stopTone(false);
AccountID accountid = getAccountFromCall( id );
if (accountid == AccountNULL) {
......
......@@ -3,6 +3,4 @@ include $(top_srcdir)/globals.mak
noinst_LTLIBRARIES = libaudiorecorder.la
libaudiorecorder_la_SOURCES = \
audiorecord.cpp \
audiodsp.h \
audiodsp.cpp
\ No newline at end of file
audiorecord.cpp
\ No newline at end of file
......@@ -44,9 +44,19 @@ AudioRecord::AudioRecord(){
byteCounter_ = 0;
recordingEnabled_ = false;
fp = 0;
nbSamplesMax_ = 3000;
createFilename();
mixBuffer_ = new SFLDataFormat[nbSamplesMax_];
micBuffer_ = new SFLDataFormat[nbSamplesMax_];
spkBuffer_ = new SFLDataFormat[nbSamplesMax_];
}
AudioRecord::~AudioRecord() {
delete [] mixBuffer_;
delete [] micBuffer_;
delete [] spkBuffer_;
}
......@@ -56,7 +66,6 @@ void AudioRecord::setSndSamplingRate(int smplRate){
void AudioRecord::setRecordingOption(FILE_TYPE type, SOUND_FORMAT format, int sndSmplRate, std::string path, std::string id){
// std::string fName;
fileType_ = type;
sndFormat_ = format;
......@@ -64,26 +73,8 @@ void AudioRecord::setRecordingOption(FILE_TYPE type, SOUND_FORMAT format, int sn
sndSmplRate_ = sndSmplRate;
call_id_ = id;
// fName = fileName_;
// fName.append("-"+call_id_);
/*
if (fileType_ == FILE_RAW){
if ( strstr(fileName_, ".raw") == NULL){
printf("AudioRecord::openFile::concatenate .raw file extension: name : %s \n", fileName_);
fName.append(".raw");
}
}
else if (fileType_ == FILE_WAV){
if ( strstr(fileName_, ".wav") == NULL){
printf("AudioRecord::openFile::concatenate .wav file extension: name : %s \n", fileName_);
fName.append(".wav");
}
}
*/
savePath_ = path + "/";
// savePath_.append(fName);
savePath_ = path + "/";
}
......@@ -362,22 +353,10 @@ void AudioRecord::closeWavFile()
_debug("AudioRecord:: Can't closeWavFile, a file has not yet been opened!\n");
return;
}
/*
_debug("AudioRecord::closeWavFile() \n");
if ( fclose( fp ) != 0)
_debug("AudioRecord::closeWavFile()::ERROR: can't close file ab \n");
fp = fopen(fileName_, "rb+");
if ( !fp ) {
_debug("AudioRecord::closeWavFile() : could not open WAV file rb+!\n");
return;
}
*/
SINT32 bytes = byteCounter_ * channels_;
fseek(fp, 40, SEEK_SET); // jump to data length
if (ferror(fp))perror("AudioRecord::closeWavFile()::ERROR: can't reach offset 40\n");
......@@ -397,11 +376,37 @@ void AudioRecord::closeWavFile()
if ( fclose( fp ) != 0)
_debug("AudioRecord::closeWavFile()::ERROR: can't close file\n");
// i = fclose(fp);
// printf("AudioRecord::closeWavFile : indicator i : %i \n",i);
}
void AudioRecord::recSpkrData(SFLDataFormat* buffer, int nSamples) {
if (recordingEnabled_) {
nbSamplesMic_ = nSamples;
for(int i = 0; i < nbSamplesMic_; i++)
micBuffer_[i] = buffer[i];
}
return;
}
void AudioRecord::recMicData(SFLDataFormat* buffer, int nSamples) {
if (recordingEnabled_) {
nbSamplesSpk_ = nSamples;
for(int i = 0; i < nbSamplesSpk_; i++)
spkBuffer_[i] = buffer[i];
}
return;
}
void AudioRecord::recData(SFLDataFormat* buffer, int nSamples) {
......@@ -412,22 +417,13 @@ void AudioRecord::recData(SFLDataFormat* buffer, int nSamples) {
return;
}
// int size = nSamples * (sizeof(SFLDataFormat));
// int size = sizeof(buffer);
// int count = sizeof(buffer) / sizeof(SFLDataFormat);
// printf("AudioRecord : sizeof(buffer) : %d \n",size);
// printf("AudioRecord : sizeof(buffer) / sizeof(SFLDataFormat) : %d \n",count);
// printf("AudioRecord : nSamples : %d \n",nSamples);
// printf("AudioRecord : buffer: %x : ", buffer);
if ( sndFormat_ == INT16 ) { // TODO change INT16 to SINT16
if ( fwrite(buffer, sizeof(SFLDataFormat), nSamples, fp) != nSamples)
_debug("AudioRecord: Could not record data! \n");
else {
// printf("Buffer : %x \n",*buffer);
fflush(fp);
// _debug("Flushing!\n");
byteCounter_ += (unsigned long)(nSamples*sizeof(SFLDataFormat));
}
}
......@@ -446,40 +442,25 @@ void AudioRecord::recData(SFLDataFormat* buffer_1, SFLDataFormat* buffer_2, int
return;
}
mixBuffer_ = new SFLDataFormat[nSamples_1];
// int size = nSamples * (sizeof(SFLDataFormat));
// int size = sizeof(buffer);
// int count = sizeof(buffer) / sizeof(SFLDataFormat);
// printf("AudioRecord : sizeof(buffer) : %d \n",size);
// printf("AudioRecord : sizeof(buffer) / sizeof(SFLDataFormat) : %d \n",count);
// printf("AudioRecord : nSamples : %d \n",nSamples);
// printf("AudioRecord : buffer: %x : ", buffer);
if ( sndFormat_ == INT16 ) { // TODO change INT16 to SINT16
for (int k=0; k<nSamples_1; k++){
// mixBuffer_[k] = ((buffer_1[k]+buffer_2[k])/2)/32767;
mixBuffer_[k] = (buffer_1[k]+buffer_2[k]);
// dsp.getRMS(mixBuffer_[k]);
if ( fwrite(&buffer_1[k], 2, 1, fp) != 1)
if ( fwrite(&mixBuffer_[k], 2, 1, fp) != 1)
_debug("AudioRecord: Could not record data!\n");
else {
// printf("Buffer : %x \n",*buffer);
fflush(fp);
// _debug("Flushing!\n");
}
}
}
byteCounter_ += (unsigned long)(nSamples_1*sizeof(SFLDataFormat));
//printf("AudioRecord::recData():: byteCounter_ : %i \n",(int)byteCounter_ );
delete [] mixBuffer_;
}
return;
}
......@@ -41,6 +41,8 @@ public:
AudioRecord();
~AudioRecord();
void setSndSamplingRate(int smplRate);
void setRecordingOption(FILE_TYPE type, SOUND_FORMAT format, int sndSmplRate, std::string path, std::string id);
......@@ -85,6 +87,21 @@ public:
*/
void stopRecording();
/**
* Record a chunk of data in an internal buffer
* @param buffer The data chunk to be recorded
* @param nSamples Number of samples (number of bytes) to be recorded
*/
void recSpkrData(SFLDataFormat* buffer, int nSamples);
/**