diff --git a/src/account.h b/src/account.h index 764d4628e1c2d780eb18b9ce4cdc23046f150f95..faf33dc162725e39c3dd4ad23985c0bb207b83c3 100644 --- a/src/account.h +++ b/src/account.h @@ -123,7 +123,8 @@ class Account{ void setRegistrationState( RegistrationState state ); - //TODO inline? + /* inline functions */ + /* They should be treated like macro definitions by the C++ compiler */ inline std::string getUsername( void ) { return _username; } inline void setUsername( std::string username) { _username = username; } diff --git a/src/audio/alsalayer.cpp b/src/audio/alsalayer.cpp index c72378229e9a7b69f83a5560312ffa7724326414..0ce2e5b785ce3ad700f328c36ab19f6bcf9ff794 100644 --- a/src/audio/alsalayer.cpp +++ b/src/audio/alsalayer.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2008 Savoir-Faire Linux inc. + * Copyright (C) 2008 2009 Savoir-Faire Linux inc. * Author: Emmanuel Milou <emmanuel.milou@savoirfairelinux.com> * * This program is free software; you can redistribute it and/or modify @@ -19,14 +19,6 @@ #include "alsalayer.h" -void* ringtoneThreadEntry( void *ptr); - -static pthread_t ringtone_thread; -bool ringtone_thread_is_running; - -pthread_mutex_t mut = PTHREAD_MUTEX_INITIALIZER; -pthread_cond_t cond = PTHREAD_COND_INITIALIZER; - // Constructor AlsaLayer::AlsaLayer( ManagerImpl* manager ) : AudioLayer( manager , ALSA ) @@ -40,21 +32,12 @@ pthread_cond_t cond = PTHREAD_COND_INITIALIZER; , IDSoundCards() { _debug(" Constructor of AlsaLayer called\n"); - - // The flag to stop the ringtone thread loop - ringtone_thread_is_running = false; } // Destructor AlsaLayer::~AlsaLayer (void) { - _debugAlsa("Close ALSA streams\n"); - closeCaptureStream(); - closePlaybackStream(); - deviceClosed = true; - - ringtone_thread_is_running = false; - //pthread_join(ringtone_thread, NULL); + closeLayer(); } void @@ -64,8 +47,6 @@ AlsaLayer::closeLayer() closeCaptureStream(); closePlaybackStream(); deviceClosed = true; - - ringtone_thread_is_running = false; } bool @@ -156,27 +137,6 @@ AlsaLayer::stopStream(void) } -void* ringtoneThreadEntry( void *ptr ) -{ - while( ringtone_thread_is_running ) - { - ( ( AlsaLayer *) ptr) -> playTones(); - //sleep(0.1); - } - - /* - pthread_mutex_lock(&mut); - while( ((AlsaLayer*)ptr)->_manager->getTelephoneTone() == NULL ) - { - pthread_cond_wait(&cond, &mut); - } - ( AlsaLayer *) ptr -> playTones(); - pthread_mutex_unlock(&mut);*/ - - return 0; -} - - void AlsaLayer::fillHWBuffer( void) { @@ -242,13 +202,6 @@ AlsaLayer::putUrgent(void* buffer, int toCopy) return nbBytes; } -void AlsaLayer::trigger_thread(void) -{ - _debug("Wake up the ringtone thread\n"); - pthread_cond_broadcast(&cond); -} - - int AlsaLayer::canGetMic() { @@ -299,13 +252,6 @@ AlsaLayer::playTones( void ) int frames; int maxBytes; - //pthread_mutex_lock(&mut); - //while(!_manager-> getTelephoneTone() && !_manager->getTelephoneFile()) - //{ - _debug("Make the ringtone thread wait\n"); - pthread_cond_wait(&cond, &mut); - //} - //frames = _periodSize ; frames = 940 ; maxBytes = frames * sizeof(SFLDataFormat) ; @@ -324,7 +270,6 @@ AlsaLayer::playTones( void ) } // free the temporary data buffer free( out ); out = 0; - //pthread_mutex_unlock(&mut); } @@ -445,18 +390,7 @@ bool AlsaLayer::alsa_set_params( snd_pcm_t *pcm_handle, int type, int rate ){ } if( type == 1 ){ - /*if( (err = snd_async_add_pcm_handler( &_AsyncHandler, pcm_handle , AlsaCallBack, this ) < 0)){ - _debugAlsa(" Unable to install the async callback handler (%s)\n", snd_strerror(err)); - return false; - }*/ - // So the loop could start when the ringtone thread entry function is reached - ringtone_thread_is_running = true; - /*if( pthread_create(&ringtone_thread, NULL, ringtoneThreadEntry, this) != 0 ) - { - _debug("Unable to start the ringtone posix thread\n"); - return false; - }*/ } snd_pcm_sw_params_free( swparams ); diff --git a/src/audio/alsalayer.h b/src/audio/alsalayer.h index c9dfa016d2cf8d61d68df15d815d7cc8f13eb088..4111d42ad9d025097bfc66a9b18facfc404e3142 100644 --- a/src/audio/alsalayer.h +++ b/src/audio/alsalayer.h @@ -21,8 +21,7 @@ #define _ALSA_LAYER_H #include "audiolayer.h" - -#include <pthread.h> +#include <alsa/asoundlib.h> class RingBuffer; class ManagerImpl; @@ -48,8 +47,6 @@ class AlsaLayer : public AudioLayer { */ ~AlsaLayer(void); - void trigger_thread(void); - void closeLayer( void ); /** diff --git a/src/audio/audiolayer.h b/src/audio/audiolayer.h index 658ac3825deaad2d14fec6c31e547d60648d4ed3..c1273ab27dada2310618333c97c5f60d661de297 100644 --- a/src/audio/audiolayer.h +++ b/src/audio/audiolayer.h @@ -22,21 +22,15 @@ #ifndef _AUDIO_LAYER_H #define _AUDIO_LAYER_H -#include "../global.h" -#include "../manager.h" +#include "global.h" #include "audiodevice.h" #include "ringbuffer.h" +#include "manager.h" #include <cc++/thread.h> // for ost::Mutex -#include <vector> -#include <alsa/asoundlib.h> #include <pulse/pulseaudio.h> -#include <iostream> -#include <istream> -#include <sstream> - #define FRAME_PER_BUFFER 160 @@ -86,8 +80,6 @@ class AudioLayer { virtual void closeLayer( void ) = 0; - virtual void trigger_thread(void)=0; - /** * Check if no devices are opened, otherwise close them. * Then open the specified devices by calling the private functions open_device diff --git a/src/audio/audiortp.cpp b/src/audio/audiortp.cpp index 85ec5fea464f198be3e410b68d8cd130dc562bb9..73dbcdfc10136ad503a16fb900d3d82f864f51b7 100644 --- a/src/audio/audiortp.cpp +++ b/src/audio/audiortp.cpp @@ -52,14 +52,16 @@ AudioRtp::~AudioRtp (void) { int AudioRtp::createNewSession (SIPCall *ca) { - //ost::MutexLock m(_threadMutex); - - // something should stop the thread before... - if ( _RTXThread != 0 ) { - _debug("! ARTP Failure: Thread already exists..., stopping it\n"); - delete _RTXThread; _RTXThread = 0; - //return -1; - } + ost::MutexLock m(_threadMutex); + + // something should stop the thread before... + if ( _RTXThread != 0 ) { + _debug("**********************************************************\n"); + _debug("! ARTP Failure: Thread already exists..., stopping it\n"); + _debug("**********************************************************\n"); + delete _RTXThread; _RTXThread = 0; + //return -1; + } // Start RTP Send/Receive threads _symmetric = Manager::instance().getConfigInt(SIGNALISATION,SYMMETRIC) ? true : false; @@ -79,7 +81,7 @@ AudioRtp::createNewSession (SIPCall *ca) { void AudioRtp::closeRtpSession () { - //ost::MutexLock m(_threadMutex); + ost::MutexLock m(_threadMutex); // This will make RTP threads finish. // _debug("Stopping AudioRTP\n"); try { @@ -88,8 +90,8 @@ AudioRtp::closeRtpSession () { _debugException("! ARTP Exception: when stopping audiortp\n"); throw; } - AudioLayer* audiolayer = Manager::instance().getAudioDriver(); - audiolayer->stopStream(); + //AudioLayer* audiolayer = Manager::instance().getAudioDriver(); + //audiolayer->stopStream(); } //////////////////////////////////////////////////////////////////////////////// @@ -99,7 +101,7 @@ AudioRtpRTX::AudioRtpRTX (SIPCall *sipcall, bool sym) : time(new ost::Time()), _ _sym(sym), micData(NULL), micDataConverted(NULL), micDataEncoded(NULL), spkrDataDecoded(NULL), spkrDataConverted(NULL), converter(NULL), _layerSampleRate(),_codecSampleRate(), _layerFrameSize(), _audiocodec(NULL) { - setCancel(cancelDeferred); + setCancel(cancelDefault); // AudioRtpRTX should be close if we change sample rate // TODO: Change bind address according to user settings. // TODO: this should be the local ip not the external (router) IP diff --git a/src/global.h b/src/global.h index 7a2a1b5793dcdb59213d5f3f684a57c864b40272..45332563dc0bbb28a0f22a777d997deafa5c32f5 100644 --- a/src/global.h +++ b/src/global.h @@ -29,6 +29,8 @@ #include <string> #include <stdlib.h> #include <sstream> +#include <map> +#include <vector> #define SFLPHONED_VERSION "0.9.2-4" /** Version number */ diff --git a/src/iaxaccount.cpp b/src/iaxaccount.cpp index 4de19c54cc995f4d39954775851299b67860451a..504a1cc7106dfa7d1c441a64b7a186fc584152bd 100644 --- a/src/iaxaccount.cpp +++ b/src/iaxaccount.cpp @@ -22,8 +22,8 @@ #include "iaxaccount.h" #include "iaxvoiplink.h" - IAXAccount::IAXAccount(const AccountID& accountID) -: Account(accountID, "iax2") +IAXAccount::IAXAccount(const AccountID& accountID) + : Account(accountID, "iax2") { _link = new IAXVoIPLink(accountID); } @@ -37,17 +37,12 @@ IAXAccount::~IAXAccount() int IAXAccount::registerVoIPLink() { - IAXVoIPLink *thislink; - _link->init(); - thislink = dynamic_cast<IAXVoIPLink*> (_link); - if (thislink) { - // Stuff needed for IAX registration - thislink->setHost(Manager::instance().getConfigString(_accountID, HOSTNAME)); - thislink->setUser(Manager::instance().getConfigString(_accountID, USERNAME)); - thislink->setPass(Manager::instance().getConfigString(_accountID, PASSWORD)); - } + // Stuff needed for IAX registration + setHostname(Manager::instance().getConfigString(_accountID, HOSTNAME)); + setUsername(Manager::instance().getConfigString(_accountID, USERNAME)); + setPassword(Manager::instance().getConfigString(_accountID, PASSWORD)); _link->sendRegister( _accountID ); diff --git a/src/iaxvoiplink.cpp b/src/iaxvoiplink.cpp index 679e2527ce887adab5dbaeefbf9ec043d17af82f..f301014b686462ba999989ae0919967024cf508b 100644 --- a/src/iaxvoiplink.cpp +++ b/src/iaxvoiplink.cpp @@ -18,15 +18,12 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #include "iaxvoiplink.h" -#include "global.h" // for _debug #include "iaxcall.h" #include "eventthread.h" #include "iaxaccount.h" - #include "manager.h" #include "audio/audiolayer.h" -//#include <iax/iax-client.h> #include <math.h> #include <dlfcn.h> @@ -41,182 +38,182 @@ #define MUSIC_ONHOLD true #define CHK_VALID_CALL if (call == NULL) { _debug("IAX: Call doesn't exists\n"); \ - return false; } + return false; } - IAXVoIPLink::IAXVoIPLink(const AccountID& accountID) + IAXVoIPLink::IAXVoIPLink(const AccountID& accountID) : VoIPLink(accountID) { - _evThread = new EventThread(this); - _regSession = NULL; - _nextRefreshStamp = 0; + _evThread = new EventThread(this); + _regSession = NULL; + _nextRefreshStamp = 0; - // to get random number for RANDOM_PORT - srand (time(NULL)); + // to get random number for RANDOM_PORT + srand (time(NULL)); - audiolayer = NULL; + audiolayer = NULL; - converter = new SamplerateConverter(); + converter = new SamplerateConverter(); - int nbSamplesMax = (int) ( converter->getFrequence() * converter->getFramesize() / 1000 ); + int nbSamplesMax = (int) ( converter->getFrequence() * converter->getFramesize() / 1000 ); - micData = new SFLDataFormat[nbSamplesMax]; - micDataConverted = new SFLDataFormat[nbSamplesMax]; - micDataEncoded = new unsigned char[nbSamplesMax]; + micData = new SFLDataFormat[nbSamplesMax]; + micDataConverted = new SFLDataFormat[nbSamplesMax]; + micDataEncoded = new unsigned char[nbSamplesMax]; - spkrDataConverted = new SFLDataFormat[nbSamplesMax]; - spkrDataDecoded = new SFLDataFormat[nbSamplesMax]; + spkrDataConverted = new SFLDataFormat[nbSamplesMax]; + spkrDataDecoded = new SFLDataFormat[nbSamplesMax]; } IAXVoIPLink::~IAXVoIPLink() { - delete _evThread; _evThread = NULL; - _regSession = NULL; // shall not delete it - terminate(); + delete _evThread; _evThread = NULL; + _regSession = NULL; // shall not delete it + terminate(); - audiolayer = NULL; + audiolayer = NULL; - delete [] micData; micData = NULL; - delete [] micDataConverted; micDataConverted = NULL; - delete [] micDataEncoded; micDataEncoded = NULL; + delete [] micData; micData = NULL; + delete [] micDataConverted; micDataConverted = NULL; + delete [] micDataEncoded; micDataEncoded = NULL; - delete [] spkrDataDecoded; spkrDataDecoded = NULL; - delete [] spkrDataConverted; spkrDataConverted = NULL; + delete [] spkrDataDecoded; spkrDataDecoded = NULL; + delete [] spkrDataConverted; spkrDataConverted = NULL; } - bool + bool IAXVoIPLink::init() { - // If it was done, don't do it again, until we call terminate() - if (_initDone) - return false; - - bool returnValue = false; - //_localAddress = "127.0.0.1"; - // port 0 is default - // iax_enable_debug(); have to enable debug when compiling iax... - int port = IAX_DEFAULT_PORTNO; - int last_port = 0; - int nbTry = 3; - - while (port != IAX_FAILURE && nbTry) { - last_port = port; - port = iax_init(port); - if ( port < 0 ) { - _debug("IAX Warning: already initialize on port %d\n", last_port); - port = RANDOM_IAX_PORT; - } else if (port == IAX_FAILURE) { - _debug("IAX Fail to start on port %d", last_port); - port = RANDOM_IAX_PORT; - } else { - _debug("IAX Info: listening on port %d\n", last_port); - _localPort = last_port; - returnValue = true; - _evThread->start(); + // If it was done, don't do it again, until we call terminate() + if (initDone()) + return false; - audiolayer = Manager::instance().getAudioDriver(); - break; + bool returnValue = false; + //_localAddress = "127.0.0.1"; + // port 0 is default + // iax_enable_debug(); have to enable debug when compiling iax... + int port = IAX_DEFAULT_PORTNO; + int last_port = 0; + int nbTry = 3; + + while (port != IAX_FAILURE && nbTry) { + last_port = port; + port = iax_init(port); + if ( port < 0 ) { + _debug("IAX Warning: already initialize on port %d\n", last_port); + port = RANDOM_IAX_PORT; + } else if (port == IAX_FAILURE) { + _debug("IAX Fail to start on port %d", last_port); + port = RANDOM_IAX_PORT; + } else { + _debug("IAX Info: listening on port %d\n", last_port); + _localPort = last_port; + returnValue = true; + _evThread->start(); + + audiolayer = Manager::instance().getAudioDriver(); + break; + } + nbTry--; + + initDone(true); } - nbTry--; - - _initDone = true; - } - if (port == IAX_FAILURE || nbTry==0) { - _debug("Fail to initialize iax\n"); + if (port == IAX_FAILURE || nbTry==0) { + _debug("Fail to initialize iax\n"); - _initDone = false; - } + initDone(false); + } - return returnValue; + return returnValue; } - void + void IAXVoIPLink::terminate() { - // If it was done, don't do it again, until we call init() - if (!_initDone) - return; + // If it was done, don't do it again, until we call init() + if (!initDone()) + return; - // iaxc_shutdown(); + // iaxc_shutdown(); - // Hangup all calls - terminateIAXCall(); + // Hangup all calls + terminateIAXCall(); - _initDone = false; + initDone(false); } - void + void IAXVoIPLink::terminateIAXCall() { - std::string reason = "Dumped Call"; - ost::MutexLock m(_callMapMutex); - CallMap::iterator iter = _callMap.begin(); - IAXCall *call; - while( iter != _callMap.end() ) { - call = dynamic_cast<IAXCall*>(iter->second); - if (call) { - _mutexIAX.enterMutex(); - iax_hangup(call->getSession(), (char*)reason.c_str()); - _mutexIAX.leaveMutex(); - call->setSession(NULL); - delete call; call = NULL; + std::string reason = "Dumped Call"; + ost::MutexLock m(_callMapMutex); + CallMap::iterator iter = _callMap.begin(); + IAXCall *call; + while( iter != _callMap.end() ) { + call = dynamic_cast<IAXCall*>(iter->second); + if (call) { + _mutexIAX.enterMutex(); + iax_hangup(call->getSession(), (char*)reason.c_str()); + _mutexIAX.leaveMutex(); + call->setSession(NULL); + delete call; call = NULL; + } + iter++; } - iter++; - } - _callMap.clear(); + _callMap.clear(); } - void + void IAXVoIPLink::getEvent() { - IAXCall* call = NULL; + IAXCall* call = NULL; - // lock iax_ stuff.. - _mutexIAX.enterMutex(); - iax_event* event = NULL; - - while ( (event = iax_get_event(IAX_NONBLOCKING)) != NULL ) { - // If we received an 'ACK', libiax2 tells apps to ignore them. - if (event->etype == IAX_EVENT_NULL) { - continue; + // lock iax_ stuff.. + _mutexIAX.enterMutex(); + iax_event* event = NULL; + + while ( (event = iax_get_event(IAX_NONBLOCKING)) != NULL ) { + // If we received an 'ACK', libiax2 tells apps to ignore them. + if (event->etype == IAX_EVENT_NULL) { + continue; + } + + //_debug ("Receive IAX Event: %d (0x%x)\n", event->etype, event->etype); + + call = iaxFindCallBySession(event->session); + + if (call) { + // We know that call, deal with it + iaxHandleCallEvent(event, call); + //_audiocodec = Manager::instance().getCodecDescriptorMap().getCodec( call -> getAudioCodec() ); + } + else if (event->session && event->session == _regSession) { + // This is a registration session, deal with it + iaxHandleRegReply(event); + } + else { + // We've got an event before it's associated with any call + iaxHandlePrecallEvent(event); + } + + iax_event_free(event); } + _mutexIAX.leaveMutex(); - //_debug ("Receive IAX Event: %d (0x%x)\n", event->etype, event->etype); - - call = iaxFindCallBySession(event->session); + // Do the doodle-moodle to send audio from the microphone to the IAX channel. + sendAudioFromMic(); - if (call) { - // We know that call, deal with it - iaxHandleCallEvent(event, call); - //_audiocodec = Manager::instance().getCodecDescriptorMap().getCodec( call -> getAudioCodec() ); - } - else if (event->session && event->session == _regSession) { - // This is a registration session, deal with it - iaxHandleRegReply(event); + // Refresh registration. + if (_nextRefreshStamp && _nextRefreshStamp - 2 < time(NULL)) { + sendRegister(""); } - else { - // We've got an event before it's associated with any call - iaxHandlePrecallEvent(event); - } - - iax_event_free(event); - } - _mutexIAX.leaveMutex(); - - // Do the doodle-moodle to send audio from the microphone to the IAX channel. - sendAudioFromMic(); - // Refresh registration. - if (_nextRefreshStamp && _nextRefreshStamp - 2 < time(NULL)) { - sendRegister(""); - } - - // thread wait 3 millisecond - _evThread->sleep(3); - free(event); + // thread wait 3 millisecond + _evThread->sleep(3); + free(event); } - void + void IAXVoIPLink::sendAudioFromMic(void) { int maxBytesToGet, availBytesFromMic, bytesAvail, nbSample, compSize; @@ -227,7 +224,7 @@ IAXVoIPLink::sendAudioFromMic(void) updateAudiolayer(); IAXCall* currentCall = getIAXCall(Manager::instance().getCurrentCallId()); - + if (!currentCall) { // Let's mind our own business. return; @@ -236,90 +233,90 @@ IAXVoIPLink::sendAudioFromMic(void) if( currentCall -> getAudioCodec() < 0 ) return; - // Just make sure the currentCall is in state to receive audio right now. - //_debug("Here we get: connectionState: %d state: %d \n", - //currentCall->getConnectionState(), - //currentCall->getState()); + // Just make sure the currentCall is in state to receive audio right now. + //_debug("Here we get: connectionState: %d state: %d \n", + //currentCall->getConnectionState(), + //currentCall->getState()); - if (currentCall->getConnectionState() != Call::Connected || - currentCall->getState() != Call::Active) { - return; - } + if (currentCall->getConnectionState() != Call::Connected || + currentCall->getState() != Call::Active) { + return; + } - ac = currentCall->getCodecMap().getCodec( currentCall -> getAudioCodec() ); - if (!ac) { - // Audio codec still not determined. - if (audiolayer) { - // To keep latency low.. - //audiolayer->flushMic(); + ac = currentCall->getCodecMap().getCodec( currentCall -> getAudioCodec() ); + if (!ac) { + // Audio codec still not determined. + if (audiolayer) { + // To keep latency low.. + //audiolayer->flushMic(); + } + return; } - return; - } - // Send sound here - if (audiolayer) { + // Send sound here + if (audiolayer) { - // we have to get 20ms of data from the mic *20/1000 = /50 - // rate/50 shall be lower than IAX__20S_48KHZ_MAX - maxBytesToGet = audiolayer->getSampleRate()* audiolayer->getFrameSize() / 1000 * sizeof(SFLDataFormat); - - // available bytes inside ringbuffer - availBytesFromMic = audiolayer->canGetMic(); + // we have to get 20ms of data from the mic *20/1000 = /50 + // rate/50 shall be lower than IAX__20S_48KHZ_MAX + maxBytesToGet = audiolayer->getSampleRate()* audiolayer->getFrameSize() / 1000 * sizeof(SFLDataFormat); - if (availBytesFromMic < maxBytesToGet) { - // We need packets full! - return; - } + // available bytes inside ringbuffer + availBytesFromMic = audiolayer->canGetMic(); - // take the lowest - bytesAvail = (availBytesFromMic < maxBytesToGet) ? availBytesFromMic : maxBytesToGet; - //_debug("available = %d, maxBytesToGet = %d\n", availBytesFromMic, maxBytesToGet); + if (availBytesFromMic < maxBytesToGet) { + // We need packets full! + return; + } - // Get bytes from micRingBuffer to data_from_mic - nbSample = audiolayer->getMic( micData, bytesAvail ) / sizeof(SFLDataFormat); + // take the lowest + bytesAvail = (availBytesFromMic < maxBytesToGet) ? availBytesFromMic : maxBytesToGet; + //_debug("available = %d, maxBytesToGet = %d\n", availBytesFromMic, maxBytesToGet); - // resample - nbSample = converter->downsampleData( micData , micDataConverted , (int)ac ->getClockRate() , (int)audiolayer->getSampleRate() , nbSample ); + // Get bytes from micRingBuffer to data_from_mic + nbSample = audiolayer->getMic( micData, bytesAvail ) / sizeof(SFLDataFormat); - // for the mono: range = 0 to IAX_FRAME2SEND * sizeof(int16) - compSize = ac->codecEncode( micDataEncoded, micDataConverted , nbSample*sizeof(int16)); + // resample + nbSample = converter->downsampleData( micData , micDataConverted , (int)ac ->getClockRate() , (int)audiolayer->getSampleRate() , nbSample ); - // Send it out! - _mutexIAX.enterMutex(); - // Make sure the session and the call still exists. - if (currentCall->getSession()) { - if ( iax_send_voice(currentCall->getSession(), currentCall->getFormat(), micDataEncoded, compSize, nbSample) == -1) { - _debug("IAX: Error sending voice data.\n"); - } + // for the mono: range = 0 to IAX_FRAME2SEND * sizeof(int16) + compSize = ac->codecEncode( micDataEncoded, micDataConverted , nbSample*sizeof(int16)); + + // Send it out! + _mutexIAX.enterMutex(); + // Make sure the session and the call still exists. + if (currentCall->getSession()) { + if ( iax_send_voice(currentCall->getSession(), currentCall->getFormat(), micDataEncoded, compSize, nbSample) == -1) { + _debug("IAX: Error sending voice data.\n"); + } + } + _mutexIAX.leaveMutex(); } - _mutexIAX.leaveMutex(); - } } - IAXCall* + IAXCall* IAXVoIPLink::getIAXCall(const CallID& id) { - Call* call = getCall(id); - if (call) { - return dynamic_cast<IAXCall*>(call); - } - return NULL; + Call* call = getCall(id); + if (call) { + return dynamic_cast<IAXCall*>(call); + } + return NULL; } - int + int IAXVoIPLink::sendRegister(AccountID id) { IAXAccount *account; bool result; result = false; - account = dynamic_cast<IAXAccount *> (Manager::instance().getAccount(id)); - if (_host.empty()) { + account = dynamic_cast<IAXAccount *> (getAccountPtr()); + if (account->getHostname().empty()) { return false; } - if (_user.empty()) { + if (account->getUsername().empty()) { return false; } @@ -338,16 +335,16 @@ IAXVoIPLink::sendRegister(AccountID id) } else { // refresh // last reg - char host[_host.length()+1]; - strcpy(host, _host.c_str()); - char user[_user.length()+1]; - strcpy(user, _user.c_str()); - char pass[_pass.length()+1]; - strcpy(pass, _pass.c_str()); + //char host[_host.length()+1]; + //strcpy(host, _host.c_str()); + //char user[_user.length()+1]; + //strcpy(user, _user.c_str()); + //char pass[_pass.length()+1]; + //strcpy(pass, _pass.c_str()); // iax_register doesn't use const char* - _debug("IAX Sending registration to %s with user %s\n", host, user); - int val = iax_register(_regSession, host, user, pass, 120); + _debug("IAX Sending registration to %s with user %s\n", account->getHostname().c_str() , account->getUsername().c_str() ); + int val = iax_register(_regSession, account->getHostname().data(), account->getUsername().data(), account->getPassword().data(), 120); _debug ("Return value: %d\n", val); // set the time-out to 15 seconds, after that, resend a registration request. // until we unregister. @@ -355,432 +352,438 @@ IAXVoIPLink::sendRegister(AccountID id) result = true; account->setRegistrationState(Trying); - } + } - // unlock - _mutexIAX.leaveMutex(); + // unlock + _mutexIAX.leaveMutex(); - return result; + return result; } - - - int + int IAXVoIPLink::sendUnregister(AccountID id) { - _mutexIAX.enterMutex(); - if (_regSession) { - /** @todo Should send a REGREL in sendUnregister()... */ + IAXAccount *account; - //iax_send_regrel(); doesn't exist yet :) - iax_destroy(_regSession); + account = dynamic_cast<IAXAccount*>(getAccountPtr()); + if(!account) + return 1; - _regSession = NULL; - } - _mutexIAX.leaveMutex(); + _mutexIAX.enterMutex(); + if (_regSession) { + /** @todo Should send a REGREL in sendUnregister()... */ + //iax_send_regrel(); doesn't exist yet :) + iax_destroy(_regSession); + _regSession = NULL; + } + _mutexIAX.leaveMutex(); - _nextRefreshStamp = 0; + _nextRefreshStamp = 0; - _debug("IAX2 send unregister\n"); - //setRegistrationState(Unregistered); + _debug("IAX2 send unregister\n"); + account->setRegistrationState(Unregistered); - return SUCCESS; + return SUCCESS; } - Call* + Call* IAXVoIPLink::newOutgoingCall(const CallID& id, const std::string& toUrl) { - IAXCall* call = new IAXCall(id, Call::Outgoing); - call->setCodecMap(Manager::instance().getCodecDescriptorMap()); - - - if (call) { - call->setPeerNumber(toUrl); + IAXCall* call = new IAXCall(id, Call::Outgoing); + call->setCodecMap(Manager::instance().getCodecDescriptorMap()); - if ( iaxOutgoingInvite(call) ) { - call->setConnectionState(Call::Progressing); - call->setState(Call::Active); - addCall(call); - } else { - delete call; call = NULL; + if (call) { + call->setPeerNumber(toUrl); + + if ( iaxOutgoingInvite(call) ) { + call->setConnectionState(Call::Progressing); + call->setState(Call::Active); + addCall(call); + } else { + delete call; call = NULL; + } } - } - return call; + return call; } - bool + bool IAXVoIPLink::answer(const CallID& id) { - IAXCall* call = getIAXCall(id); - call->setCodecMap(Manager::instance().getCodecDescriptorMap()); + IAXCall* call = getIAXCall(id); + call->setCodecMap(Manager::instance().getCodecDescriptorMap()); - CHK_VALID_CALL; + CHK_VALID_CALL; - _mutexIAX.enterMutex(); - iax_answer(call->getSession()); - _mutexIAX.leaveMutex(); + _mutexIAX.enterMutex(); + iax_answer(call->getSession()); + _mutexIAX.leaveMutex(); - call->setState(Call::Active); - call->setConnectionState(Call::Connected); - // Start audio - audiolayer->startStream(); - //audiolayer->flushMic(); + call->setState(Call::Active); + call->setConnectionState(Call::Connected); + // Start audio + audiolayer->startStream(); + //audiolayer->flushMic(); - return true; + return true; } - bool + bool IAXVoIPLink::hangup(const CallID& id) { - IAXCall* call = getIAXCall(id); - std::string reason = "Dumped Call"; - CHK_VALID_CALL; - - _mutexIAX.enterMutex(); - iax_hangup(call->getSession(), (char*) reason.c_str()); - _mutexIAX.leaveMutex(); - call->setSession(NULL); - if (Manager::instance().isCurrentCall(id)) { - // stop audio - audiolayer->stopStream(); - } - removeCall(id); - return true; + IAXCall* call = getIAXCall(id); + std::string reason = "Dumped Call"; + CHK_VALID_CALL; + + _mutexIAX.enterMutex(); + iax_hangup(call->getSession(), (char*) reason.c_str()); + _mutexIAX.leaveMutex(); + call->setSession(NULL); + if (Manager::instance().isCurrentCall(id)) { + // stop audio + audiolayer->stopStream(); + } + removeCall(id); + return true; } - bool + bool IAXVoIPLink::onhold(const CallID& id) { - IAXCall* call = getIAXCall(id); + IAXCall* call = getIAXCall(id); - CHK_VALID_CALL; + CHK_VALID_CALL; - //if (call->getState() == Call::Hold) { _debug("Call is already on hold\n"); return false; } + //if (call->getState() == Call::Hold) { _debug("Call is already on hold\n"); return false; } - _mutexIAX.enterMutex(); - iax_quelch_moh(call->getSession() , MUSIC_ONHOLD); - _mutexIAX.leaveMutex(); + _mutexIAX.enterMutex(); + iax_quelch_moh(call->getSession() , MUSIC_ONHOLD); + _mutexIAX.leaveMutex(); - call->setState(Call::Hold); - return true; + call->setState(Call::Hold); + return true; } - bool + bool IAXVoIPLink::offhold(const CallID& id) { - IAXCall* call = getIAXCall(id); + IAXCall* call = getIAXCall(id); - CHK_VALID_CALL; + CHK_VALID_CALL; - //if (call->getState() == Call::Active) { _debug("Call is already active\n"); return false; } - _mutexIAX.enterMutex(); - iax_unquelch(call->getSession()); - _mutexIAX.leaveMutex(); - audiolayer->startStream(); - call->setState(Call::Active); - return true; + //if (call->getState() == Call::Active) { _debug("Call is already active\n"); return false; } + _mutexIAX.enterMutex(); + iax_unquelch(call->getSession()); + _mutexIAX.leaveMutex(); + audiolayer->startStream(); + call->setState(Call::Active); + return true; } - bool + bool IAXVoIPLink::transfer(const CallID& id, const std::string& to) { - IAXCall* call = getIAXCall(id); + IAXCall* call = getIAXCall(id); - CHK_VALID_CALL; + CHK_VALID_CALL; - char callto[to.length()+1]; - strcpy(callto, to.c_str()); + char callto[to.length()+1]; + strcpy(callto, to.c_str()); - _mutexIAX.enterMutex(); - iax_transfer(call->getSession(), callto); - _mutexIAX.leaveMutex(); + _mutexIAX.enterMutex(); + iax_transfer(call->getSession(), callto); + _mutexIAX.leaveMutex(); - return true; + return true; - // should we remove it? - // removeCall(id); + // should we remove it? + // removeCall(id); } - bool + bool IAXVoIPLink::refuse(const CallID& id) { - IAXCall* call = getIAXCall(id); - std::string reason = "Call rejected manually."; + IAXCall* call = getIAXCall(id); + std::string reason = "Call rejected manually."; - CHK_VALID_CALL; + CHK_VALID_CALL; - _mutexIAX.enterMutex(); - iax_reject(call->getSession(), (char*) reason.c_str()); - _mutexIAX.leaveMutex(); - removeCall(id); + _mutexIAX.enterMutex(); + iax_reject(call->getSession(), (char*) reason.c_str()); + _mutexIAX.leaveMutex(); + removeCall(id); - return true; + return true; } - bool + bool IAXVoIPLink::carryingDTMFdigits(const CallID& id, char code) { - IAXCall* call = getIAXCall(id); + IAXCall* call = getIAXCall(id); - CHK_VALID_CALL; + CHK_VALID_CALL; - _mutexIAX.enterMutex(); - iax_send_dtmf(call->getSession(), code); - _mutexIAX.leaveMutex(); + _mutexIAX.enterMutex(); + iax_send_dtmf(call->getSession(), code); + _mutexIAX.leaveMutex(); - return true; + return true; } - bool + bool IAXVoIPLink::iaxOutgoingInvite(IAXCall* call) { - struct iax_session *newsession; - ost::MutexLock m(_mutexIAX); - - newsession = iax_session_new(); - if (!newsession) { - _debug("IAX Error: Can't make new session for a new call\n"); - return false; - } - call->setSession(newsession); - /* reset activity and ping "timers" */ - // iaxc_note_activity(callNo); - - std::string strNum = _user + ":" + _pass + "@" + _host + "/" + call->getPeerNumber(); + struct iax_session *newsession; + ost::MutexLock m(_mutexIAX); + std::string username, strNum; + char *lang=NULL; + int wait, audio_format_preferred, audio_format_capability; + char user[username.length()+1]; + char num[strNum.length()+1]; + IAXAccount *account; - char user[_user.length()+1]; - strcpy(user, _user.c_str()); + newsession = iax_session_new(); + if (!newsession) { + _debug("IAX Error: Can't make new session for a new call\n"); + return false; + } + call->setSession(newsession); - char num[strNum.length()+1]; - strcpy(num, strNum.c_str()); + account = dynamic_cast<IAXAccount*> (getAccountPtr()); + username = account->getUsername(); + strNum = username + ":" + account->getPassword() + "@" + account->getHostname() + "/" + call->getPeerNumber(); + strcpy(user, username.c_str()); + strcpy(num, strNum.c_str()); - char* lang = NULL; - int wait = 0; - /** @todo Make preference dynamic, and configurable */ - int audio_format_preferred = call->getFirstMatchingFormat(call->getSupportedFormat()); - int audio_format_capability = call->getSupportedFormat(); + wait = 0; + /** @todo Make preference dynamic, and configurable */ + audio_format_preferred = call->getFirstMatchingFormat(call->getSupportedFormat()); + audio_format_capability = call->getSupportedFormat(); - _debug("IAX New call: %s\n", num); - iax_call(newsession, user, user, num, lang, wait, audio_format_preferred, audio_format_capability); + _debug("IAX New call: %s\n", num); + iax_call(newsession, user, user, num, lang, wait, audio_format_preferred, audio_format_capability); - return true; + return true; } - IAXCall* + IAXCall* IAXVoIPLink::iaxFindCallBySession(struct iax_session* session) { - // access to callMap shoud use that - // the code below is like findSIPCallWithCid() - ost::MutexLock m(_callMapMutex); - IAXCall* call = NULL; - CallMap::iterator iter = _callMap.begin(); - while(iter != _callMap.end()) { - call = dynamic_cast<IAXCall*>(iter->second); - if (call && call->getSession() == session) { - return call; + // access to callMap shoud use that + // the code below is like findSIPCallWithCid() + ost::MutexLock m(_callMapMutex); + IAXCall* call = NULL; + CallMap::iterator iter = _callMap.begin(); + while(iter != _callMap.end()) { + call = dynamic_cast<IAXCall*>(iter->second); + if (call && call->getSession() == session) { + return call; + } + iter++; } - iter++; - } - return NULL; // not found + return NULL; // not found } - void + void IAXVoIPLink::iaxHandleCallEvent(iax_event* event, IAXCall* call) { - // call should not be 0 - // note activity? - // - CallID id = call->getCallId(); - - switch(event->etype) { - case IAX_EVENT_HANGUP: - if (Manager::instance().isCurrentCall(id)) { - // stop audio - audiolayer->stopStream(); - } - Manager::instance().peerHungupCall(id); - removeCall(id); - break; - - case IAX_EVENT_REJECT: - //Manager::instance().peerHungupCall(id); - if (Manager::instance().isCurrentCall(id)) { - // stop audio - audiolayer->stopStream(); - } - call->setConnectionState(Call::Connected); - call->setState(Call::Error); - Manager::instance().callFailure(id); - removeCall(id); - break; - - case IAX_EVENT_ACCEPT: - // Call accepted over there by the computer, not the user yet. - if (event->ies.format) { - call->setFormat(event->ies.format); - } - break; - - case IAX_EVENT_ANSWER: - if (call->getConnectionState() != Call::Connected){ - call->setConnectionState(Call::Connected); - call->setState(Call::Active); - - if (event->ies.format) { - // Should not get here, should have been set in EVENT_ACCEPT - call->setFormat(event->ies.format); - } - - Manager::instance().peerAnsweredCall(id); - //audiolayer->flushMic(); - audiolayer->startStream(); - // start audio here? - } else { - // deja connecté ? - } - break; - - case IAX_EVENT_BUSY: - call->setConnectionState(Call::Connected); - call->setState(Call::Busy); - Manager::instance().callBusy(id); - removeCall(id); - break; - - case IAX_EVENT_VOICE: - //_debug("Should have a decent value!!!!!! = %i\n" , call -> getAudioCodec()); - if( !audiolayer -> isCaptureActive()) - audiolayer->startStream(); - iaxHandleVoiceEvent(event, call); - break; - - case IAX_EVENT_TEXT: - break; - - case IAX_EVENT_RINGA: - call->setConnectionState(Call::Ringing); - Manager::instance().peerRingingCall(call->getCallId()); - break; - - case IAX_IE_MSGCOUNT: - break; - case IAX_EVENT_PONG: - break; - - case IAX_EVENT_URL: - break; - - // case IAX_EVENT_CNG: ?? - // break; - - case IAX_EVENT_TIMEOUT: - break; - - case IAX_EVENT_TRANSFER: - break; - - default: - _debug("Unknown event type (in call event): %d\n", event->etype); - - } + // call should not be 0 + // note activity? + // + CallID id = call->getCallId(); + + switch(event->etype) { + case IAX_EVENT_HANGUP: + if (Manager::instance().isCurrentCall(id)) { + // stop audio + audiolayer->stopStream(); + } + Manager::instance().peerHungupCall(id); + removeCall(id); + break; + + case IAX_EVENT_REJECT: + //Manager::instance().peerHungupCall(id); + if (Manager::instance().isCurrentCall(id)) { + // stop audio + audiolayer->stopStream(); + } + call->setConnectionState(Call::Connected); + call->setState(Call::Error); + Manager::instance().callFailure(id); + removeCall(id); + break; + + case IAX_EVENT_ACCEPT: + // Call accepted over there by the computer, not the user yet. + if (event->ies.format) { + call->setFormat(event->ies.format); + } + break; + + case IAX_EVENT_ANSWER: + if (call->getConnectionState() != Call::Connected){ + call->setConnectionState(Call::Connected); + call->setState(Call::Active); + + if (event->ies.format) { + // Should not get here, should have been set in EVENT_ACCEPT + call->setFormat(event->ies.format); + } + + Manager::instance().peerAnsweredCall(id); + //audiolayer->flushMic(); + audiolayer->startStream(); + // start audio here? + } else { + // deja connecté ? + } + break; + + case IAX_EVENT_BUSY: + call->setConnectionState(Call::Connected); + call->setState(Call::Busy); + Manager::instance().callBusy(id); + removeCall(id); + break; + + case IAX_EVENT_VOICE: + //_debug("Should have a decent value!!!!!! = %i\n" , call -> getAudioCodec()); + //TODO Check this method + if( !audiolayer -> isCaptureActive()) + audiolayer->startStream(); + iaxHandleVoiceEvent(event, call); + break; + + case IAX_EVENT_TEXT: + break; + + case IAX_EVENT_RINGA: + call->setConnectionState(Call::Ringing); + Manager::instance().peerRingingCall(call->getCallId()); + break; + + case IAX_IE_MSGCOUNT: + break; + case IAX_EVENT_PONG: + break; + + case IAX_EVENT_URL: + break; + + // case IAX_EVENT_CNG: ?? + // break; + + case IAX_EVENT_TIMEOUT: + break; + + case IAX_EVENT_TRANSFER: + break; + + default: + _debug("Unknown event type (in call event): %d\n", event->etype); + + } } /* Handle audio event, VOICE packet received */ - void + void IAXVoIPLink::iaxHandleVoiceEvent(iax_event* event, IAXCall* call) { - unsigned char *data; unsigned int size, max, nbInt16; int expandedSize, nbSample; AudioCodec *ac; - // If we receive datalen == 0, some things of the jitter buffer in libiax2/iax.c - // were triggered - if (!event->datalen) { - // Skip this empty packet. - //_debug("IAX: Skipping empty jitter-buffer interpolated packet\n"); - return; - } - - if (audiolayer) { - // On-the-fly codec changing (normally, when we receive a full packet) - // as per http://tools.ietf.org/id/draft-guy-iax-03.txt - // - subclass holds the voiceformat property. - if (event->subclass && event->subclass != call->getFormat()) { - call->setFormat(event->subclass); + // If we receive datalen == 0, some things of the jitter buffer in libiax2/iax.c + // were triggered + if (!event->datalen) { + // Skip this empty packet. + //_debug("IAX: Skipping empty jitter-buffer interpolated packet\n"); + return; } - //_debug("Receive: len=%d, format=%d, _receiveDataDecoded=%p\n", event->datalen, call->getFormat(), _receiveDataDecoded); - ac = call->getCodecMap().getCodec( call -> getAudioCodec() ); - data = (unsigned char*)event->data; - size = event->datalen; + if (audiolayer) { + // On-the-fly codec changing (normally, when we receive a full packet) + // as per http://tools.ietf.org/id/draft-guy-iax-03.txt + // - subclass holds the voiceformat property. + if (event->subclass && event->subclass != call->getFormat()) { + call->setFormat(event->subclass); + } + //_debug("Receive: len=%d, format=%d, _receiveDataDecoded=%p\n", event->datalen, call->getFormat(), _receiveDataDecoded); + ac = call->getCodecMap().getCodec( call -> getAudioCodec() ); - // Decode data with relevant codec - max = (int)( ac->getClockRate() * audiolayer->getFrameSize() / 1000 ); + data = (unsigned char*)event->data; + size = event->datalen; - if (size > max) { - _debug("The size %d is bigger than expected %d. Packet cropped. Ouch!\n", size, max); - size = max; - } + // Decode data with relevant codec + max = (int)( ac->getClockRate() * audiolayer->getFrameSize() / 1000 ); - expandedSize = ac->codecDecode( spkrDataDecoded , data , size ); - nbInt16 = expandedSize/sizeof(int16); + if (size > max) { + _debug("The size %d is bigger than expected %d. Packet cropped. Ouch!\n", size, max); + size = max; + } - if (nbInt16 > max) { - _debug("We have decoded an IAX VOICE packet larger than expected: %i VS %i. Cropping.\n", nbInt16, max); - nbInt16 = max; - } + expandedSize = ac->codecDecode( spkrDataDecoded , data , size ); + nbInt16 = expandedSize/sizeof(int16); - nbSample = nbInt16; - // resample - nbInt16 = converter->upsampleData( spkrDataDecoded , spkrDataConverted , ac->getClockRate() , audiolayer->getSampleRate() , nbSample); + if (nbInt16 > max) { + _debug("We have decoded an IAX VOICE packet larger than expected: %i VS %i. Cropping.\n", nbInt16, max); + nbInt16 = max; + } - audiolayer->playSamples( spkrDataConverted , nbInt16 * sizeof(SFLDataFormat), true); + nbSample = nbInt16; + // resample + nbInt16 = converter->upsampleData( spkrDataDecoded , spkrDataConverted , ac->getClockRate() , audiolayer->getSampleRate() , nbSample); - } else { - _debug("IAX: incoming audio, but no sound card open"); - } + audiolayer->playSamples( spkrDataConverted , nbInt16 * sizeof(SFLDataFormat), true); + + } else { + _debug("IAX: incoming audio, but no sound card open"); + } } /** * Handle the registration process */ - void + void IAXVoIPLink::iaxHandleRegReply(iax_event* event) { int new_voicemails; std::string account_id; - + IAXAccount *account; + + account_id = getAccountID(); + account = dynamic_cast<IAXAccount *>(Manager::instance().getAccount(account_id)); + if (event->etype == IAX_EVENT_REGREJ) { /* Authentication failed! */ _mutexIAX.enterMutex(); iax_destroy(_regSession); _mutexIAX.leaveMutex(); _regSession = NULL; - //TODO Restore that - //setRegistrationState(ErrorAuth); + // Update the account registration state + account->setRegistrationState(ErrorAuth); } - + else if (event->etype == IAX_EVENT_REGACK) { /* Authentication succeeded */ _mutexIAX.enterMutex(); // Looking for the voicemail information //if( event->ies != 0 ) - new_voicemails = processIAXMsgCount(event->ies.msgcount); - _debug("iax voicemail number notification: %i\n", new_voicemails); + //new_voicemails = processIAXMsgCount(event->ies.msgcount); + //_debug("iax voicemail number notification: %i\n", new_voicemails); // Notify the client if new voicemail waiting for the current account - account_id = getAccountID(); - Manager::instance().startVoiceMessageNotification(account_id.c_str(), new_voicemails); + //account_id = getAccountID(); + //Manager::instance().startVoiceMessageNotification(account_id.c_str(), new_voicemails); iax_destroy(_regSession); _mutexIAX.leaveMutex(); @@ -789,13 +792,13 @@ IAXVoIPLink::iaxHandleRegReply(iax_event* event) // I mean, save the timestamp, so that we re-register again in the REFRESH time. // Defaults to 60, as per draft-guy-iax-03. _nextRefreshStamp = time(NULL) + (event->ies.refresh ? event->ies.refresh : 60); - //nsetRegistrationState(Registered); + account->setRegistrationState(Registered); } } int IAXVoIPLink::processIAXMsgCount( int msgcount ) { - + // IAX sends the message count under a specific format: // 1 // 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 @@ -809,118 +812,108 @@ int IAXVoIPLink::processIAXMsgCount( int msgcount ) // Thus: // 0 <= msgcount <= 255 => msgcount new messages, 0 old messages // msgcount >= 256 => msgcount/256 old messages , msgcount%256 new messages (RULES) - + return msgcount%256; } - void + void IAXVoIPLink::iaxHandlePrecallEvent(iax_event* event) { - IAXCall* call = NULL; - CallID id; - std::string reason = "Error ringing user."; + IAXCall* call = NULL; + CallID id; + std::string reason = "Error ringing user."; - switch(event->etype) { - case IAX_EVENT_REGACK: - case IAX_EVENT_REGREJ: - _debug("IAX Registration Event in a pre-call setup\n"); - break; + switch(event->etype) { + case IAX_EVENT_REGACK: + case IAX_EVENT_REGREJ: + _debug("IAX Registration Event in a pre-call setup\n"); + break; - case IAX_EVENT_REGREQ: - // Received when someone wants to register to us!?! - // Asterisk receives and answers to that, not us, we're a phone. - _debug("Registration by a peer, don't allow it\n"); - break; + case IAX_EVENT_REGREQ: + // Received when someone wants to register to us!?! + // Asterisk receives and answers to that, not us, we're a phone. + _debug("Registration by a peer, don't allow it\n"); + break; - case IAX_EVENT_CONNECT: - // We've got an incoming call! Yikes! - _debug("> IAX_EVENT_CONNECT (receive)\n"); + case IAX_EVENT_CONNECT: + // We've got an incoming call! Yikes! + _debug("> IAX_EVENT_CONNECT (receive)\n"); - id = Manager::instance().getNewCallID(); + id = Manager::instance().getNewCallID(); + call = new IAXCall(id, Call::Incoming); - call = new IAXCall(id, Call::Incoming); + if (!call) { + _debug("! IAX Failure: unable to create an incoming call"); + return; + } - if (!call) { - _debug("! IAX Failure: unable to create an incoming call"); - return; - } + // Setup the new IAXCall + // Associate the call to the session. + call->setSession(event->session); - // Setup the new IAXCall - // Associate the call to the session. - call->setSession(event->session); + // setCallAudioLocal(call); + call->setCodecMap(Manager::instance().getCodecDescriptorMap()); + call->setConnectionState(Call::Progressing); - // setCallAudioLocal(call); - call->setCodecMap(Manager::instance().getCodecDescriptorMap()); - call->setConnectionState(Call::Progressing); + if (event->ies.calling_number) + call->setPeerNumber(std::string(event->ies.calling_number)); + if (event->ies.calling_name) + call->setPeerName(std::string(event->ies.calling_name)); - if (event->ies.calling_number) - call->setPeerNumber(std::string(event->ies.calling_number)); - if (event->ies.calling_name) - call->setPeerName(std::string(event->ies.calling_name)); + if (Manager::instance().incomingCall(call, getAccountID())) { + /** @todo Faudra considérer éventuellement le champ CODEC PREFS pour + * l'établissement du codec de transmission */ - if (Manager::instance().incomingCall(call, getAccountID())) { - /** @todo Faudra considérer éventuellement le champ CODEC PREFS pour - * l'établissement du codec de transmission */ + // Remote lists its capabilities + int format = call->getFirstMatchingFormat(event->ies.capability); + // Remote asks for preferred codec voiceformat + int pref_format = call->getFirstMatchingFormat(event->ies.format); - // Remote lists its capabilities - int format = call->getFirstMatchingFormat(event->ies.capability); - // Remote asks for preferred codec voiceformat - int pref_format = call->getFirstMatchingFormat(event->ies.format); + // Priority to remote's suggestion. In case it's a forwarding, no transcoding + // will be needed from the server, thus less latency. + if (pref_format) + format = pref_format; - // Priority to remote's suggestion. In case it's a forwarding, no transcoding - // will be needed from the server, thus less latency. - if (pref_format) - format = pref_format; + iax_accept(event->session, format); + iax_ring_announce(event->session); - iax_accept(event->session, format); - iax_ring_announce(event->session); + addCall(call); + } else { + // reject call, unable to add it + iax_reject(event->session, (char*)reason.c_str()); - addCall(call); - } else { - // reject call, unable to add it - iax_reject(event->session, (char*)reason.c_str()); + delete call; call = NULL; + } - delete call; call = NULL; - } + break; - break; + case IAX_EVENT_HANGUP: + // Remote peer hung up + call = iaxFindCallBySession(event->session); + id = call->getCallId(); - case IAX_EVENT_HANGUP: - // Remote peer hung up - call = iaxFindCallBySession(event->session); - id = call->getCallId(); + Manager::instance().peerHungupCall(id); + removeCall(id); + break; - Manager::instance().peerHungupCall(id); - removeCall(id); - break; + case IAX_EVENT_TIMEOUT: // timeout for an unknown session - case IAX_EVENT_TIMEOUT: // timeout for an unknown session + break; - break; + case IAX_IE_MSGCOUNT: + //_debug("messssssssssssssssssssssssssssssssssssssssssssssssages\n"); + break; - case IAX_IE_MSGCOUNT: - //_debug("messssssssssssssssssssssssssssssssssssssssssssssssages\n"); - break; - - default: - _debug("Unknown event type (in precall): %d\n", event->etype); - } - -} + default: + _debug("Unknown event type (in precall): %d\n", event->etype); + } - int -IAXVoIPLink::iaxCodecMapToFormat(IAXCall* call) -{ - CodecOrder map = call->getCodecMap().getActiveCodecs(); - printf("taytciatcia = %i\n", map.size()); - return 0; } - void IAXVoIPLink::updateAudiolayer( void ) { _mutexIAX.enterMutex(); diff --git a/src/iaxvoiplink.h b/src/iaxvoiplink.h index 8ad4082882f41b731a610714172167bb94e15f95..b82949f640760b474913204c596616018ece1c98 100644 --- a/src/iaxvoiplink.h +++ b/src/iaxvoiplink.h @@ -166,21 +166,7 @@ class IAXVoIPLink : public VoIPLink bool isContactPresenceSupported() { return false; } public: // iaxvoiplink only - /** - * @param host Set the host name - */ - void setHost(const std::string& host) { _host = host; } - - /** - * @param user Set the user name - */ - void setUser(const std::string& user) { _user = user; } - - /** - * @param pass Set the password - */ - void setPass(const std::string& pass) { _pass = pass; } - + void updateAudiolayer( void ); void setStunServer( const std::string &server ) {}; @@ -194,7 +180,7 @@ class IAXVoIPLink : public VoIPLink * @param msgcount The value sent by IAX in the REGACK message * @return int The number of new messages waiting for the current registered user */ - int processIAXMsgCount( int msgcount ); + int processIAXMsgCount( int msgcount ); /** @@ -253,28 +239,12 @@ class IAXVoIPLink : public VoIPLink */ bool iaxOutgoingInvite(IAXCall* call); - - /** - * Convert CodecMap to IAX format using IAX constants - * @return `format` ready to go into iax_* calls - */ - int iaxCodecMapToFormat(IAXCall* call); - /** Threading object */ EventThread* _evThread; /** registration session : 0 if not register */ struct iax_session* _regSession; - /** IAX Host */ - std::string _host; - - /** IAX User */ - std::string _user; - - /** IAX Password */ - std::string _pass; - /** Timestamp of when we should refresh the registration up with * the registrar. Values can be: EPOCH timestamp, 0 if we want no registration, 1 * to force a registration. */ diff --git a/src/managerimpl.cpp b/src/managerimpl.cpp index c8c25d2b8432821c06f587c7b17ae0d3b38fa651..0b3b46b719f59d2949c91a4ed2a91116cae15d5f 100644 --- a/src/managerimpl.cpp +++ b/src/managerimpl.cpp @@ -57,20 +57,20 @@ ManagerImpl::ManagerImpl (void) : _hasTriedToRegister(false) , _config() , _currentCallId2() - //, _currentCallMutex() + , _currentCallMutex() , _codecBuilder(NULL) , _audiodriver(NULL) , _dtmfKey(NULL) , _codecDescriptorMap() - //, _toneMutex() + , _toneMutex() , _telephoneTone(NULL) , _audiofile() , _spkr_volume(0) , _mic_volume(0) - //, _mutex() + , _mutex() , _dbus(NULL) , _waitingCall() - //, _waitingCallMutex() + , _waitingCallMutex() , _nbIncomingWaitingCall(0) , _path("") , _exist(0) @@ -79,7 +79,7 @@ ManagerImpl::ManagerImpl (void) , _firewallAddr("") , _hasZeroconf(false) , _callAccountMap() - //, _callAccountMapMutex() + , _callAccountMapMutex() , _accountMap() { @@ -158,13 +158,11 @@ void ManagerImpl::terminate() bool ManagerImpl::isCurrentCall(const CallID& callId) { - //ost::MutexLock m(_currentCallMutex); return (_currentCallId2 == callId ? true : false); } bool ManagerImpl::hasCurrentCall() { - //ost::MutexLock m(_currentCallMutex); _debug("Current call ID = %s\n", _currentCallId2.c_str()); if ( _currentCallId2 != "") { return true; @@ -174,13 +172,12 @@ ManagerImpl::hasCurrentCall() { const CallID& ManagerImpl::getCurrentCallId() { - //ost::MutexLock m(_currentCallMutex); return _currentCallId2; } void ManagerImpl::switchCall(const CallID& id ) { - //ost::MutexLock m(_currentCallMutex); + ost::MutexLock m(_currentCallMutex); _currentCallId2 = id; } @@ -403,7 +400,6 @@ ManagerImpl::saveConfig (void) ManagerImpl::initRegisterAccounts() { int status; - //TODO What the flag is for ?? bool flag = true; AccountMap::iterator iter; @@ -527,20 +523,19 @@ ManagerImpl::playDtmf(char code, bool isTalking) // Multi-thread bool ManagerImpl::incomingCallWaiting() { - //ost::MutexLock m(_waitingCallMutex); return (_nbIncomingWaitingCall > 0) ? true : false; } void ManagerImpl::addWaitingCall(const CallID& id) { - //ost::MutexLock m(_waitingCallMutex); + ost::MutexLock m(_waitingCallMutex); _waitingCall.insert(id); _nbIncomingWaitingCall++; } void ManagerImpl::removeWaitingCall(const CallID& id) { - //ost::MutexLock m(_waitingCallMutex); + ost::MutexLock m(_waitingCallMutex); // should return more than 1 if it erase a call if (_waitingCall.erase(id)) { _nbIncomingWaitingCall--; @@ -549,7 +544,6 @@ ManagerImpl::removeWaitingCall(const CallID& id) { bool ManagerImpl::isWaitingCall(const CallID& id) { - //ost::MutexLock m(_waitingCallMutex); CallIDSet::iterator iter = _waitingCall.find(id); if (iter != _waitingCall.end()) { return false; @@ -701,9 +695,9 @@ ManagerImpl::playATone(Tone::TONEID toneId) { if (!hasToPlayTone) return false; if (_telephoneTone != 0) { - //_toneMutex.enterMutex(); + _toneMutex.enterMutex(); _telephoneTone->setCurrentTone(toneId); - //_toneMutex.leaveMutex(); + _toneMutex.leaveMutex(); AudioLoop* audioloop = getTelephoneTone(); unsigned int nbSampling = audioloop->getSize(); @@ -740,16 +734,16 @@ ManagerImpl::stopTone(bool stopAudio=true) { } - //_toneMutex.enterMutex(); + _toneMutex.enterMutex(); if (_telephoneTone != 0) { _telephoneTone->setCurrentTone(Tone::TONE_NULL); } - //_toneMutex.leaveMutex(); + _toneMutex.leaveMutex(); // for ringing tone.. - //_toneMutex.enterMutex(); + _toneMutex.enterMutex(); _audiofile.stop(); - //_toneMutex.leaveMutex(); + _toneMutex.leaveMutex(); } /** @@ -786,7 +780,6 @@ ManagerImpl::congestion () { void ManagerImpl::ringback () { playATone(Tone::TONE_RINGTONE); - getAudioDriver()->trigger_thread(); } /** @@ -813,13 +806,13 @@ ManagerImpl::ringtone() int sampleRate = audiolayer->getSampleRate(); AudioCodec* codecForTone = _codecDescriptorMap.getFirstCodecAvailable(); - //_toneMutex.enterMutex(); + _toneMutex.enterMutex(); bool loadFile = _audiofile.loadFile(ringchoice, codecForTone , sampleRate); - //_toneMutex.leaveMutex(); + _toneMutex.leaveMutex(); if (loadFile) { - //_toneMutex.enterMutex(); + _toneMutex.enterMutex(); _audiofile.start(); - //_toneMutex.leaveMutex(); + _toneMutex.leaveMutex(); if(CHECK_INTERFACE( layer, ALSA )){ /*int size = _audiofile.getSize(); SFLDataFormat output[ size ]; @@ -846,7 +839,7 @@ ManagerImpl::ringtone() ManagerImpl::getTelephoneTone() { if(_telephoneTone != 0) { - //ost::MutexLock m(_toneMutex); + ost::MutexLock m(_toneMutex); return _telephoneTone->getCurrentTone(); } else { @@ -857,7 +850,7 @@ ManagerImpl::getTelephoneTone() AudioLoop* ManagerImpl::getTelephoneFile() { - //ost::MutexLock m(_toneMutex); + ost::MutexLock m(_toneMutex); if(_audiofile.isStarted()) { return &_audiofile; } else { @@ -1735,7 +1728,7 @@ int ManagerImpl::getSipPort( void ) ManagerImpl::getCallStatus(const std::string& sequenceId UNUSED) { if (!_dbus) { return false; } - //ost::MutexLock m(_callAccountMapMutex); + ost::MutexLock m(_callAccountMapMutex); CallAccountMap::iterator iter = _callAccountMap.begin(); TokenList tk; std::string code; @@ -2032,7 +2025,7 @@ ManagerImpl::associateCallToAccount(const CallID& callID, const AccountID& accou { if (getAccountFromCall(callID) == AccountNULL) { // nothing with the same ID if ( accountExists(accountID) ) { // account id exist in AccountMap - //ost::MutexLock m(_callAccountMapMutex); + ost::MutexLock m(_callAccountMapMutex); _callAccountMap[callID] = accountID; _debug("Associate Call %s with Account %s\n", callID.data(), accountID.data()); return true; @@ -2047,7 +2040,7 @@ ManagerImpl::associateCallToAccount(const CallID& callID, const AccountID& accou AccountID ManagerImpl::getAccountFromCall(const CallID& callID) { - //ost::MutexLock m(_callAccountMapMutex); + ost::MutexLock m(_callAccountMapMutex); CallAccountMap::iterator iter = _callAccountMap.find(callID); if ( iter == _callAccountMap.end()) { return AccountNULL; @@ -2059,7 +2052,7 @@ ManagerImpl::getAccountFromCall(const CallID& callID) bool ManagerImpl::removeCallAccount(const CallID& callID) { - //ost::MutexLock m(_callAccountMapMutex); + ost::MutexLock m(_callAccountMapMutex); if ( _callAccountMap.erase(callID) ) { return true; } diff --git a/src/managerimpl.h b/src/managerimpl.h index 222c7154788fd86d4cc79d2fd3ad16c048584f82..cc3411f3ade26470030f558b6cba32e18795bfdd 100644 --- a/src/managerimpl.h +++ b/src/managerimpl.h @@ -865,7 +865,7 @@ class ManagerImpl { CallID _currentCallId2; /** Protected current call access */ - //ost::Mutex _currentCallMutex; + ost::Mutex _currentCallMutex; /** Vector of CodecDescriptor */ CodecDescriptor* _codecBuilder; @@ -883,7 +883,7 @@ class ManagerImpl { ///////////////////// // Protected by Mutex ///////////////////// - //ost::Mutex _toneMutex; + ost::Mutex _toneMutex; TelephoneTone* _telephoneTone; AudioFile _audiofile; @@ -896,7 +896,7 @@ class ManagerImpl { // Multithread variable (protected by _mutex) // /** Mutex to protect access to code section */ - //ost::Mutex _mutex; + ost::Mutex _mutex; // Multithread variable (non protected) DBusManagerImpl * _dbus; @@ -905,7 +905,7 @@ class ManagerImpl { CallIDSet _waitingCall; /** Protect waiting call list, access by many voip/audio threads */ - //ost::Mutex _waitingCallMutex; + ost::Mutex _waitingCallMutex; /** Number of waiting call, synchronize with waitingcall callidvector */ unsigned int _nbIncomingWaitingCall; @@ -953,7 +953,7 @@ class ManagerImpl { CallAccountMap _callAccountMap; /** Mutex to lock the call account map (main thread + voiplink thread) */ - //ost::Mutex _callAccountMapMutex; + ost::Mutex _callAccountMapMutex; /** Associate a new CallID to a AccountID * Protected by mutex diff --git a/src/sipaccount.cpp b/src/sipaccount.cpp index 5880f927f00fd0708ed0a7f30fedea5ef140af24..61c8bfd05b2a762891c61ebd8fee8f22fd3f2dda 100644 --- a/src/sipaccount.cpp +++ b/src/sipaccount.cpp @@ -52,19 +52,13 @@ SIPAccount::~SIPAccount() int SIPAccount::registerVoIPLink() { - int status, useStun; - SIPVoIPLink *thislink; + int status; /* Retrieve the account information */ /* Stuff needed for SIP registration */ setHostname(Manager::instance().getConfigString(_accountID,HOSTNAME)); setUsername(Manager::instance().getConfigString(_accountID, USERNAME)); setPassword(Manager::instance().getConfigString(_accountID, PASSWORD)); - /* Retrieve STUN stuff */ - /* STUN configuration is attached to a voiplink because it is applied to every accounts (PJSIP limitation)*/ - thislink = dynamic_cast<SIPVoIPLink*> (_link); - if (thislink) { - } /* Start registration */ status = _link->sendRegister( _accountID ); diff --git a/src/sipaccount.h b/src/sipaccount.h index b716086fbe5fc94fe57146228d20d4605a92169d..a49af2d00864a29c674a2ac152dcd2663d75620c 100644 --- a/src/sipaccount.h +++ b/src/sipaccount.h @@ -77,22 +77,10 @@ class SIPAccount : public Account bool fullMatch(const std::string& username, const std::string& hostname); bool userMatch(const std::string& username); - inline std::string getHostname( void ) { return _hostname; } - inline void setHostname( std::string hostname) { _hostname = hostname; } - - inline std::string getPassword( void ) { return _password; } - inline void setPassword( std::string password ) { _password = password; } - - inline std::string getAlias( void ) { return _alias; } - inline void setAlias( std::string alias ) { _alias = alias; } - - inline std::string getType( void ) { return _type; } - inline void setType( std::string type ) { _type = type; } - pjsip_regc* getRegistrationInfo( void ) { return _regc; } void setRegistrationInfo( pjsip_regc *regc ) { _regc = regc; } - //TODO See if it useful + /* Registration flag */ bool isRegister() {return _bRegister;} void setRegister(bool result) {_bRegister = result;} diff --git a/src/sipvoiplink.cpp b/src/sipvoiplink.cpp index a37e68318704433019f1836d553157ab4f0910c0..e3fc11b7920e38dd1e813a486f4fdae20ac110f4 100644 --- a/src/sipvoiplink.cpp +++ b/src/sipvoiplink.cpp @@ -211,13 +211,13 @@ SIPVoIPLink::terminate() SIPVoIPLink::terminateSIPCall() { - //ost::MutexLock m(_callMapMutex); + ost::MutexLock m(_callMapMutex); CallMap::iterator iter = _callMap.begin(); SIPCall *call; while( iter != _callMap.end() ) { call = dynamic_cast<SIPCall*>(iter->second); if (call) { - //TODO terminate the sip call + // terminate the sip call delete call; call = 0; } iter++; @@ -517,17 +517,17 @@ SIPVoIPLink::onhold(const CallID& id) if (call==0) { _debug("! SIP Error: call doesn't exist\n"); return false; } - _mutexSIP.enterMutex(); // Stop sound call->setAudioStart(false); call->setState(Call::Hold); _debug("* SIP Info: Stopping AudioRTP for onhold action\n"); - _audiortp->closeRtpSession(); + //_mutexSIP.enterMutex(); + _audiortp->closeRtpSession(); + //_mutexSIP.leaveMutex(); + local_sdp = call->getLocalSDPSession(); - _mutexSIP.leaveMutex(); - if( local_sdp == NULL ){ _debug("! SIP Failure: unable to find local_sdp\n"); return false; @@ -1145,7 +1145,6 @@ std::string SIPVoIPLink::getSipTo(const std::string& to_url, std::string hostnam PJ_ASSERT_RETURN( status == PJ_SUCCESS, 1 ); // Init the callback for INVITE session: - // TODO The invite session as global ? pj_bzero(&inv_cb, sizeof (inv_cb)); inv_cb.on_state_changed = &call_on_state_changed; @@ -1171,7 +1170,7 @@ std::string SIPVoIPLink::getSipTo(const std::string& to_url, std::string hostnam _debug("UserAgent: pjsip version %s for %s initialized\n", pj_get_version(), PJ_OS_NAME); - //TODO Create the secondary thread to poll sip events + // Create the secondary thread to poll sip events _evThread->start(); /* Done! */ @@ -1435,9 +1434,6 @@ std::string SIPVoIPLink::getSipTo(const std::string& to_url, std::string hostnam SIPVoIPLink *link; pjsip_msg *msg; - _debug("UserAgent: TSX Changed! The tsx->state is %d; tsx->role is %d; code is %d; method id is %.*s.\n", - tsx->state, tsx->role, tsx->status_code, (int)tsx->method.name.slen, tsx->method.name.ptr); - if(pj_strcmp2(&tsx->method.name, "INFO") == 0) { // Receive a INFO message, ingore it! return; diff --git a/src/sipvoiplink.h b/src/sipvoiplink.h index 0aca792fc392fd6ab2a84bea7760c5d6a7870d01..03b12e6c38ba2d0dc8eae5dd73f3a9a9916f5720 100644 --- a/src/sipvoiplink.h +++ b/src/sipvoiplink.h @@ -42,7 +42,7 @@ class AudioRtp; #define RANDOM_SIP_PORT rand() % 64000 + 1024 // To set the verbosity. From 0 (min) to 6 (max) -#define PJ_LOG_LEVEL 5 +#define PJ_LOG_LEVEL 1 /** * @file sipvoiplink.h diff --git a/src/useragent.h b/src/useragent.h deleted file mode 100644 index 728b074cd70eb9fb14d09256cfabeaa36cd653c0..0000000000000000000000000000000000000000 --- a/src/useragent.h +++ /dev/null @@ -1,150 +0,0 @@ -/* - * Copyright (C) 2004-2005 Savoir-Faire Linux inc. - * Author: Yun Liu <yun.liu@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. - */ - - -#ifndef _SIPMANAGER_H -#define _SIPMANAGER_H - -#include <pjsip.h> -#include <pjlib-util.h> -#include <pjlib.h> -#include <pjnath/stun_config.h> - -//TODO Remove this include if we don't need anything from it -#include <pjsip_simple.h> - -#include <pjsip_ua.h> -#include <pjmedia/sdp.h> -#include <pjmedia/sdp_neg.h> - -#include <string> -#include <vector> - -#define PJ_LOG_LEVEL 1 - -typedef std::string AccountID; - -class SIPCall; - -class UserAgent -{ -private: - /** PJSIP Endpoint */ - pjsip_endpoint *_endpt; - pj_sock_t _sock; - //pjsip_module _appMod; - pj_caching_pool _cp; - pj_pool_t *_pool; - pj_mutex_t *_mutex; /** Mutex protection for this data */ - pjsip_module _mod; /** PJSIP module. */ - pjsip_module _options_handler; - bool _useStun; - pj_str_t _stunHost; - - - pj_thread_t *_thread; - - static UserAgent *_current; - - /* Sleep with polling */ - void busy_sleep(unsigned msec); -public: - UserAgent(); - ~UserAgent(); - - pj_status_t sipCreate(); - - /** - * This method is used to initialize the pjsip - */ - pj_status_t sipInit(); - - - void sipDestory(); - - /** Set whether it will use stun server */ - void setStunServer(const char *server); - - /** Set the port number user designated */ - void setSipPort(int port) { _regPort = port; } - - int getSipPort() { return _regPort; } - - pj_str_t getStunServer() { return _stunHost; } - - bool addAccount(AccountID id, pjsip_regc **regc, const std::string& server, const std::string& user, const std::string& passwd - , const int& timeout); - bool removeAccount(pjsip_regc *regc); - - pj_str_t buildContact(char *userName); - - bool loadSIPLocalIP(); - - - pjsip_endpoint* getEndPoint() {return _endpt;} - - std::string getLocalIP() {return _localExternAddress;} - - int getModId() {return _mod.id;} - - bool setCallAudioLocal(SIPCall* call); - - int answer(SIPCall* call); - - bool hangup(SIPCall* call); - - bool refuse(SIPCall* call); - - bool onhold(SIPCall *call); - bool offhold(SIPCall *call); - - bool transfer(SIPCall *call, const std::string& to); - - void onCallTransfered(pjsip_inv_session *inv, pjsip_rx_data *rdata); - - bool makeOutgoingCall(const std::string& to, SIPCall* call, const AccountID& id); - - bool carryingDTMFdigits(SIPCall* call, char *msgBody); - - pj_pool_t *getAppPool() {return _pool;} - static pj_bool_t mod_on_rx_request(pjsip_rx_data *rdata); - static pj_bool_t mod_on_rx_response(pjsip_rx_data *rdata UNUSED) {return PJ_SUCCESS;} - static void regc_cb(struct pjsip_regc_cbparam *param); - static void xfer_func_cb( pjsip_evsub *sub, pjsip_event *event); - static void xfer_svr_cb(pjsip_evsub *sub, pjsip_event *event); - static void call_on_media_update( pjsip_inv_session *inv UNUSED, pj_status_t status UNUSED) {} - static void call_on_state_changed( pjsip_inv_session *inv, pjsip_event *e); - static void call_on_forked(pjsip_inv_session *inv, pjsip_event *e); - static void call_on_tsx_changed(pjsip_inv_session *inv, pjsip_transaction *tsx, pjsip_event *e); - static int start_thread(void *arg); - static UserAgent* getInstance() {return _current;} - - static void set_voicemail_info( AccountID account, pjsip_msg_body *body ); -private: - - // Copy Constructor - UserAgent(const UserAgent& rh); - - // Assignment Operator - UserAgent& operator=( const UserAgent& rh); -}; - - -#endif /* _SIPMANAGER_H */ - diff --git a/src/voiplink.cpp b/src/voiplink.cpp index e4ff653d48211f0912f639bc8da37a75ada65593..77a0c95ed11f7cc05646e0baa21a311501310ab8 100644 --- a/src/voiplink.cpp +++ b/src/voiplink.cpp @@ -76,3 +76,11 @@ bool VoIPLink::clearCallMap() return true; } +Account* VoIPLink::getAccountPtr(void) +{ + Account* account; + AccountID id; + + id = getAccountID(); + return Manager::instance().getAccount(id); +} diff --git a/src/voiplink.h b/src/voiplink.h index 45f0c0e34e4f25fdd02e6574966f7fce637d6f99..4038394ccf6446663bba7e5d0d465d7cd955c2a8 100644 --- a/src/voiplink.h +++ b/src/voiplink.h @@ -27,6 +27,7 @@ #include "account.h" class AudioCodec; +class Account; /** Define AccountID type */ typedef std::string AccountID; @@ -182,6 +183,8 @@ class VoIPLink { */ inline AccountID& getAccountID(void) { return _accountID; } + Account* getAccountPtr(void); + /** * @param accountID The account identifier */ diff --git a/src/zeroconf/DNSQueryThread.cpp b/src/zeroconf/DNSQueryThread.cpp deleted file mode 100644 index a5e9dd3fd2208eb5466264ce7d5c078961a9eedc..0000000000000000000000000000000000000000 --- a/src/zeroconf/DNSQueryThread.cpp +++ /dev/null @@ -1,69 +0,0 @@ -/** - * Copyright (C) 2005 Savoir-Faire Linux inc. - * Author: Yan Morin <yan.morin@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 "DNSQueryThread.h" -#include "DNSService.h" - -/** - * Construct a DNSQueryThread and initialize the cancel to deferred - */ -DNSQueryThread::DNSQueryThread(DNSService *parent, const char *regtype) : ost::Thread() -{ - _parent = parent; - _regtype = regtype; - _serviceRef = NULL; - setCancel(cancelDeferred); -} - -/** - * Destruct a DNSQueryThread - */ -DNSQueryThread::~DNSQueryThread() -{ - if (_serviceRef) { - DNSServiceRefDeallocate(_serviceRef); - } - terminate(); - _parent = NULL; - _regtype = NULL; - _serviceRef = NULL; -} - -/** - * Running loop - */ -void -DNSQueryThread::run() { - DNSServiceErrorType theErr=0; // NULL; - DNSServiceFlags resultFlags=0; - - theErr = DNSServiceBrowse(&_serviceRef, - resultFlags, - 0, // all interfaces - _regtype, - NULL, - DNSServiceAddServicesCallback, - (void*)_parent); - - if (theErr == kDNSServiceErr_NoError) { - while(!testCancel()) { - DNSServiceProcessResult(_serviceRef); // blockage if none... - } - } -} diff --git a/src/zeroconf/DNSQueryThread.h b/src/zeroconf/DNSQueryThread.h deleted file mode 100644 index 2ea0bc2cab61d49f1493cccee103e8e8fddd9d33..0000000000000000000000000000000000000000 --- a/src/zeroconf/DNSQueryThread.h +++ /dev/null @@ -1,40 +0,0 @@ -/** - * Copyright (C) 2005 Savoir-Faire Linux inc. - * Author: Yan Morin <yan.morin@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. - */ -#ifndef __DNSSD_DNSQUERYTHREAD_H__ -#define __DNSSD_DNSQUERYTHREAD_H__ - -#include <cc++/thread.h> -#include <dns_sd.h> - -class DNSService; -class DNSQueryThread : public ost::Thread -{ -public: - DNSQueryThread(DNSService *parent, const char *regtype); - ~DNSQueryThread(); - virtual void run(); // looking for services - -private: - DNSService *_parent; // parent service - DNSServiceRef _serviceRef; // service reference - const char *_regtype; // service type and socket type (_sip._udp by example) -}; - - -#endif // __DNSSD_DNSQUERYTHREAD_H__ diff --git a/src/zeroconf/DNSService.cpp b/src/zeroconf/DNSService.cpp deleted file mode 100644 index e2919fe27d93ec7c431ec7e30cb53d1469b462f2..0000000000000000000000000000000000000000 --- a/src/zeroconf/DNSService.cpp +++ /dev/null @@ -1,237 +0,0 @@ -/** - * Copyright (C) 2005 Savoir-Faire Linux inc. - * Author: Yan Morin <yan.morin@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. - */ - - /** - * Inspired by http://braden.machacking.net/zerobrowse.cpp and - * http://developer.kde.org/documentation/library/3.4-api/dnssd/html/remoteservice_8cpp-source.html - */ -#include "DNSService.h" -#include "DNSServiceTXTRecord.h" -#include "DNSQueryThread.h" - -#include <cc++/thread.h> - -/** - * Simple Empty Constructor - */ -DNSService::DNSService() -{ - _start = false; - _regtypeList.push_back("_sip._udp"); -#ifdef USE_IAX2 - _regtypeList.push_back("_iax._udp"); -#endif - - // for the thread, the ifdef add a dynamic _regtypeList problem - for (std::list<std::string>::iterator iterThread=_regtypeList.begin(); - iterThread!=_regtypeList.end(); - iterThread++) { - _queryThread.push_back(new DNSQueryThread(this, (*iterThread).c_str())); - } -} - -/** - * Simple Empty Destructor - */ -DNSService::~DNSService() -{ - int cntThread = _queryThread.size(); - for (int iThread=0;iThread<cntThread;iThread++) { - delete _queryThread[iThread]; _queryThread[iThread] = NULL; - } -} - -/** - * Look for zeroconf services and add them to _services - */ -void -DNSService::startScanServices() -{ - for (std::vector<DNSQueryThread *>::iterator iter = _queryThread.begin();iter!=_queryThread.end();iter++) { - (*iter)->start(); - } - _start = true; -} - -/** - * Add one service to the list of actual services - * @param service Service to add to the list - */ -void DNSService::addService(const std::string &service) -{ - DNSServiceTXTRecord txtRecord; - _mutex.enterMutex(); - _services[service] = txtRecord; - // we leave before the queryService since, each - // thread will modify a DNSServiceTXTRecord of a difference services - _mutex.leaveMutex(); - notify(); - queryService(service); -} - -/** - * Remove one service to the list of actual services - * @param service Service to remove to the list - */ -void DNSService::removeService(const std::string &service) -{ - _mutex.enterMutex(); - _services.erase(service); - _mutex.leaveMutex(); - notify(); -} - -/** - * Return every services - */ -DNSServiceMap -DNSService::getServices() -{ - ost::MutexLock m(_mutex); - return _services; -} - - -/** - * Query a service and wait for the anwser - * the queryCallback will show the result - * @param service The service full adress - */ -void -DNSService::queryService(const std::string &service) -{ - DNSServiceErrorType theErr=0; - DNSServiceRef myServRef=0; - DNSServiceFlags resultFlags=0; - - theErr = DNSServiceQueryRecord(&myServRef, - resultFlags, - 0, - service.c_str(), - kDNSServiceType_TXT, - kDNSServiceClass_IN, - DNSServiceQueryRecordCallback, - (void*)this); - if (theErr == kDNSServiceErr_NoError) { - DNSServiceProcessResult(myServRef); // blockage... - DNSServiceRefDeallocate(myServRef); - } -} - -/** - * Overloadding queryService - * @param service service name - * @param regtype registred type of service - * @param domain domain (habitually local.) - */ -void -DNSService::queryService(const char *service, const char *regtype, const char *domain) -{ - char serviceName[kDNSServiceMaxDomainName+1]; - DNSServiceConstructFullName(serviceName, service, regtype, domain); - queryService(std::string(serviceName)); -} - -/** - * Add a txt record with the queryService callback answser data - * @param rdlen the length of the txt record data - * @param rdata txt record data - */ -void -DNSService::addTXTRecord(const char *fullname, uint16_t rdlen, const void *rdata) -{ - char key[256]; - - const char *value; - uint8_t valueLen; // 0 to 256 by type restriction - char valueTab[256]; - - - uint16_t keyCount = TXTRecordGetCount(rdlen, rdata); - for (int iKey=0; iKey<keyCount; iKey++) { - TXTRecordGetItemAtIndex (rdlen, rdata, iKey, 256, key, &valueLen, (const void **)(&value)); - if (value) { - bcopy(value, valueTab, valueLen); - valueTab[valueLen]='\0'; - _mutex.enterMutex(); // extra-careful - _services[fullname].addKeyValue(key, valueTab); - _mutex.leaveMutex(); - } else { - _mutex.enterMutex(); - _services[fullname].removeKey(key); - _mutex.leaveMutex(); - } - } - - notify(); -} - -void -DNSServiceAddServicesCallback(DNSServiceRef, - DNSServiceFlags flags, - uint32_t, - DNSServiceErrorType errorCode, - const char *serviceName, - const char *replyType, - const char *replyDomain, - void *context) -{ - if (errorCode==kDNSServiceErr_NoError) { - - if (flags) { - DNSService *service = (DNSService*)context; - std::string tempService; - tempService = std::string(serviceName) + "." + std::string(replyType) + std::string(replyDomain); - if (flags&kDNSServiceFlagsAdd) { -// _debug("DNSServiceAddServicesCallback call addService\n"); - service->addService(tempService); - } else { -// _debug("DNSServiceAddServicesCallback call removeService\n"); - service->removeService(tempService); - } - } - } else { - // TODO: error handling - } -} - -void -DNSServiceQueryRecordCallback( - DNSServiceRef, - DNSServiceFlags flags, - uint32_t, - DNSServiceErrorType errorCode, - const char *fullname, - uint16_t, - uint16_t, - uint16_t rdlen, - const void *rdata, - uint32_t, - void *context) -{ - if (errorCode==kDNSServiceErr_NoError) { - if (flags&kDNSServiceFlagsAdd) { -// _debug("DNSServiceQueryRecordCallback call addTXTRecord\n"); - ((DNSService *)context)->addTXTRecord(fullname, rdlen, rdata); - } else { -// _debug("DNSServiceQueryRecordCallback call removeService\n"); - ((DNSService *)context)->removeService(fullname); - } - } -} diff --git a/src/zeroconf/DNSService.h b/src/zeroconf/DNSService.h deleted file mode 100644 index b1a840bf1cf6bf5b8076d9fb79c2785f84cb6ae4..0000000000000000000000000000000000000000 --- a/src/zeroconf/DNSService.h +++ /dev/null @@ -1,92 +0,0 @@ -/** - * Copyright (C) 2005 Savoir-Faire Linux inc. - * Author: Yan Morin <yan.morin@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. - */ -#ifndef __DNSSD_DNSSERVICE_H__ -#define __DNSSD_DNSSERVICE_H__ - -#include <string> -#include <map> -#include <list> -#include <vector> - -#include <dns_sd.h> -#include <cc++/thread.h> -#include "../observer.h" - -class DNSQueryThread; -class DNSServiceTXTRecord; - -typedef std::map<std::string, DNSServiceTXTRecord> DNSServiceMap; -class DNSService : public Pattern::Subject -{ -public: - DNSService(); - ~DNSService(); - - void startScanServices(); // looking for services - void addService(const std::string &service); // adding every services - void removeService(const std::string &service); // remove a service - DNSServiceMap getServices(); // get all DNS Service - void stop(); // after the browsing loop stop - - void queryService(const std::string &service); // query the TXT record of a service - void queryService(const char *service, const char *regtype, const char *domain); - void addTXTRecord(const char *fullname, uint16_t rdlen, const void *rdata); - //void removeTXTRecord(const char *fullname); - - bool isStart() const { return _start; } - -private: - DNSServiceMap _services; //map - - std::vector<DNSQueryThread *> _queryThread; - /** - * Mutex to protect access to _services on add/erase - */ - ost::Mutex _mutex; - /** - * RegType List contains zeroconf services to register, like sip, iax2, ... - * It will be use to initialize the DNSQueryThread - */ - std::list<std::string> _regtypeList; - - bool _start; -}; - -void DNSServiceAddServicesCallback(DNSServiceRef sdRef, - DNSServiceFlags flags, - uint32_t interfaceIndex, - DNSServiceErrorType errorCode, - const char *serviceName, - const char *replyType, - const char *replyDomain, - void *context); - -void DNSServiceQueryRecordCallback(DNSServiceRef DNSServiceRef, - DNSServiceFlags flags, - uint32_t interfaceIndex, - DNSServiceErrorType errorCode, - const char *fullname, - uint16_t rrtype, - uint16_t rrclass, - uint16_t rdlen, - const void *rdata, - uint32_t ttl, - void *context); - -#endif // __DNSSD_DNSSERVICE_H__ diff --git a/src/zeroconf/DNSServiceTXTRecord.cpp b/src/zeroconf/DNSServiceTXTRecord.cpp deleted file mode 100644 index f12ed15f5b2b1f9468ffa72f8b71d3567102f5a2..0000000000000000000000000000000000000000 --- a/src/zeroconf/DNSServiceTXTRecord.cpp +++ /dev/null @@ -1,76 +0,0 @@ -/** - * Copyright (C) 2005 Savoir-Faire Linux inc. - * Author: Yan Morin <yan.morin@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 "DNSServiceTXTRecord.h" - -/** - * Simple constructor - */ -DNSServiceTXTRecord::DNSServiceTXTRecord() -{ -} - -/** - * Simple destructor - */ -DNSServiceTXTRecord::~DNSServiceTXTRecord() -{ -} - -/** - * add a pair of key/value inside the associative std::map - * @param key unique key inside the std::map - * @param value value associated to the key - */ -void -DNSServiceTXTRecord::addKeyValue(const std::string &key, const std::string &value) -{ - _map[key] = value; -} - -/** - * remove a key inside the map or do nothing if it doesn't exist - * @param key unique key inside the std::map - */ -void -DNSServiceTXTRecord::removeKey(const std::string &key) -{ - _map.erase(key); -} - -/** - * get a value from a key - * @param key unique key inside the std::map - * @return the value or empty - */ -const std::string & -DNSServiceTXTRecord::getValue(const std::string &key) -{ - return _map[key]; // return std::string("") if it's not there -} - -/** - * get a value from a key - * @param key unique key inside the std::map - * @return the value or empty - */ -const std::string & -DNSServiceTXTRecord::getValue(const char* key) -{ - return getValue(std::string(key)); -} diff --git a/src/zeroconf/DNSServiceTXTRecord.h b/src/zeroconf/DNSServiceTXTRecord.h deleted file mode 100644 index d6d2742fd6efa5091dc04f63064f3eb28e555397..0000000000000000000000000000000000000000 --- a/src/zeroconf/DNSServiceTXTRecord.h +++ /dev/null @@ -1,43 +0,0 @@ -/** - * Copyright (C) 2005 Savoir-Faire Linux inc. - * Author: Yan Morin <yan.morin@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. - */ -#ifndef __DNSSD_DNSSERVICETXTRECORD_H__ -#define __DNSSD_DNSSERVICETXTRECORD_H__ - -#include <string> -#include <map> - -typedef std::map<std::string, std::string> TXTRecordMap; -class DNSServiceTXTRecord -{ -public: - DNSServiceTXTRecord(); - ~DNSServiceTXTRecord(); - void addKeyValue(const std::string &key, const std::string &value); - void removeKey(const std::string &key); - const std::string &getValue(const std::string &key); - const std::string &getValue(const char *key); - inline void clear(void) { _map.clear(); }; - inline int size(void) { return _map.size(); }; - TXTRecordMap getTXTRecords() { return _map; } - -private: - TXTRecordMap _map; -}; - -#endif // __DNSSD_DNSSERVICETXTRECORD_H__ diff --git a/src/zeroconf/Makefile.am b/src/zeroconf/Makefile.am deleted file mode 100644 index d2ed5b4e4a56d0330b7bad354ea7f2afec291086..0000000000000000000000000000000000000000 --- a/src/zeroconf/Makefile.am +++ /dev/null @@ -1,12 +0,0 @@ -SUBDIRS = - -noinst_LTLIBRARIES = libzeroconf.la - -libzeroconf_la_SOURCES = \ - DNSQueryThread.cpp DNSQueryThread.h \ - DNSService.cpp DNSService.h \ - DNSServiceTXTRecord.cpp DNSServiceTXTRecord.h - -AM_CXXFLAGS = $(libccext2_CFLAGS) -libzeroconf_la_LIBADD = $(LIB_DNSSD) -