diff --git a/src/Makefile.am b/src/Makefile.am index 77070875f7a4720f0fa2aefd84cfa8714951ea02..014decc04471c121666f98edd6c1e36a028b80c2 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -13,10 +13,10 @@ endif SUBDIRS = audio config gui $(ZEROCONFDIR) -sflphoned_SOURCES = call.cpp eventthread.cpp main.cpp sipvoiplink.cpp voIPLink.cpp \ - sipcall.cpp managerimpl.cpp \ - observer.cpp \ - account.cpp sipaccount.cpp aixaccount.cpp accountcreator.cpp aixvoiplink.cpp +sflphoned_SOURCES = eventthread.cpp main.cpp voIPLink.cpp \ + managerimpl.cpp observer.cpp \ + account.cpp sipaccount.cpp iaxaccount.cpp accountcreator.cpp iaxvoiplink.cpp \ + sipvoiplink.cpp call.cpp sipcall.cpp sflphoned_CXXFLAGS = -DPREFIX=\"$(prefix)\" -DPROGSHAREDIR=\"${datadir}/sflphone\" $(ZEROCONFFLAGS) @@ -38,6 +38,8 @@ libsflphone_la_LIBADD = \ libsflphone_la_SOURCES = noinst_LTLIBRARIES = libsflphone.la -noinst_HEADERS = managerimpl.h manager.h global.h observer.h eventthread.h sipvoiplink.h user_cfg.h \ - call.h voIPLink.h sipcall.h \ - account.h sipaccount.h aixaccount.h accountcreator.h aixvoiplink.h +noinst_HEADERS = managerimpl.h manager.h global.h observer.h eventthread.h user_cfg.h \ + voIPLink.h \ + account.h sipaccount.h iaxaccount.h accountcreator.h iaxvoiplink.h \ + sipvoiplink.h call.h sipcall.h + diff --git a/src/account.cpp b/src/account.cpp index 20cb189460aa7348929e4deb2275e7750f949d36..a34da5011336d93a18f8daf92d65d0fdb5cefdbb 100644 --- a/src/account.cpp +++ b/src/account.cpp @@ -24,6 +24,7 @@ Account::Account(const AccountID& accountID) : _accountID(accountID) _link = 0; _shouldInitOnStart = false; + _shouldRegisterOnStart = false; _enabled = false; _registered = false; } diff --git a/src/account.h b/src/account.h index 3cbdc738877ccd2e4aca98ac199cf8f78e9886a8..a2ab5f6932659818b34e4eb29bd87d3aa43342e4 100644 --- a/src/account.h +++ b/src/account.h @@ -28,6 +28,8 @@ typedef std::string AccountID; #define AccountNULL "" #define CONFIG_ACCOUNT_TYPE "Account.type" #define CONFIG_ACCOUNT_ENABLE "Account.enable" +#define CONFIG_ACCOUNT_AUTO_REGISTER "Account.autoregister" + /** @author Yan Morin @@ -39,13 +41,13 @@ class Account{ public: Account(const AccountID& accountID); - ~Account(); + virtual ~Account(); /** * Load the default properties for the account */ virtual void initConfig(Conf::ConfigTree& config) = 0; - + virtual void loadConfig() = 0; /** * Get the voiplink pointer @@ -77,6 +79,18 @@ public: */ virtual bool terminate() = 0; + /** + * Tell if we should init the account on start + * @return true if we must init the link + */ + bool shouldInitOnStart() {return _shouldInitOnStart; } + + /** + * Tell if we should init the account on start + * @return true if we must init the link + */ + bool shouldRegisterOnStart() {return _shouldRegisterOnStart; } + private: /** * Create a unique voIPLink() depending on the protocol @@ -102,6 +116,12 @@ protected: */ bool _shouldInitOnStart; + /** + * Tells if we should register automatically on startup + * Modified by the configuration + */ + bool _shouldRegisterOnStart; + /** * Tells if the link is enabled or not * Modified by init/terminate diff --git a/src/accountcreator.cpp b/src/accountcreator.cpp index b013d09bfff229ebd3d793dbf8a3ad8d1d86399a..4bb4404c06320f1bab366a37e8df6e88889a55a2 100644 --- a/src/accountcreator.cpp +++ b/src/accountcreator.cpp @@ -18,7 +18,7 @@ */ #include "accountcreator.h" #include "sipaccount.h" -#include "aixaccount.h" +#include "iaxaccount.h" AccountCreator::AccountCreator() { @@ -37,8 +37,8 @@ AccountCreator::createAccount(AccountType type, AccountID accountID) return new SIPAccount(accountID); break; - case AIX_ACCOUNT: - return new AIXAccount(accountID); + case IAX_ACCOUNT: + return new IAXAccount(accountID); break; } return 0; diff --git a/src/accountcreator.h b/src/accountcreator.h index b38d78b0263a3d397909f1e84b415c2ec61f72bc..cb156358b19e136a9ed540eccce5bf12299572e8 100644 --- a/src/accountcreator.h +++ b/src/accountcreator.h @@ -33,7 +33,7 @@ public: /** * Public account type */ - enum AccountType {SIP_ACCOUNT, AIX_ACCOUNT }; + enum AccountType {SIP_ACCOUNT, IAX_ACCOUNT }; /** * Create a new account or null diff --git a/src/aixaccount.cpp b/src/aixaccount.cpp deleted file mode 100644 index f918a21fcc7aaa681ee678000cc9c453b48e9fa5..0000000000000000000000000000000000000000 --- a/src/aixaccount.cpp +++ /dev/null @@ -1,95 +0,0 @@ -/* - * Copyright (C) 2006 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 2 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 "aixaccount.h" -#include "aixvoiplink.h" - -AIXAccount::AIXAccount(const AccountID& accountID) - : Account(accountID) -{ - createVoIPLink(); -} - - -AIXAccount::~AIXAccount() -{ -} - -/* virtual Account function implementation */ -bool -AIXAccount::createVoIPLink() -{ - if (!_link) { - _link = new AIXVoIPLink(); - } - return (_link != 0 ? true : false); -} - -bool -AIXAccount::registerAccount() -{ - if (_link && !_registered) { - _registered = (_link->setRegister() >= 0) ? true : false; - } - return _registered; -} - -bool -AIXAccount::unregisterAccount() -{ - if (_link && _registered) { - _registered = (_link->setUnregister() == 0) ? false : true; - } - return !_registered; -} - -bool -AIXAccount::init() -{ - if (_link && !_enabled) { - _link->init(); - _enabled = true; - return true; - } - return false; -} - -bool -AIXAccount::terminate() -{ - if (_link && _enabled) { - _link->terminate(); - _enabled = false; - return true; - } - return false; -} - -void -AIXAccount::initConfig(Conf::ConfigTree& config) -{ - std::string section(_accountID); - std::string type_str("string"); - std::string type_int("int"); - - config.addConfigTreeItem(section, Conf::ConfigTreeItem(CONFIG_ACCOUNT_TYPE, "AIX", type_str)); - config.addConfigTreeItem(section, Conf::ConfigTreeItem(CONFIG_ACCOUNT_ENABLE, "1", type_int)); - config.addConfigTreeItem(section, Conf::ConfigTreeItem("AIX.Proxy", "", type_str)); - -} - diff --git a/src/audio/audiortp.cpp b/src/audio/audiortp.cpp index d4af191490db6293444d865050ab1d0b36bb3e3a..98d0fbc59d4e91d0720e8644cef1b7ba7e39c5c0 100644 --- a/src/audio/audiortp.cpp +++ b/src/audio/audiortp.cpp @@ -49,7 +49,7 @@ AudioRtp::~AudioRtp (void) { } int -AudioRtp::createNewSession (SipCall *ca) { +AudioRtp::createNewSession (SIPCall *ca) { ost::MutexLock m(_threadMutex); // something should stop the thread before... @@ -90,7 +90,7 @@ AudioRtp::closeRtpSession () { //////////////////////////////////////////////////////////////////////////////// // AudioRtpRTX Class // //////////////////////////////////////////////////////////////////////////////// -AudioRtpRTX::AudioRtpRTX (SipCall *sipcall, AudioLayer* driver, bool sym) { +AudioRtpRTX::AudioRtpRTX (SIPCall *sipcall, AudioLayer* driver, bool sym) { setCancel(cancelDeferred); time = new ost::Time(); _ca = sipcall; @@ -108,7 +108,7 @@ AudioRtpRTX::AudioRtpRTX (SipCall *sipcall, AudioLayer* driver, bool sym) { // TODO: Change bind address according to user settings. // TODO: this should be the local ip not the external (router) IP - std::string localipConfig = "0.0.0.0"; // _ca->getLocalIp(); + std::string localipConfig = _ca->getLocalIp(); // _ca->getLocalIp(); ost::InetHostAddress local_ip(localipConfig.c_str()); //_debug("AudioRtpRTX ctor : Local IP:port %s:%d\tsymmetric:%d\n", local_ip.getHostname(), _ca->getLocalAudioPort(), _sym); @@ -159,9 +159,9 @@ AudioRtpRTX::initAudioRtpSession (void) if (_ca == 0) { return; } //_debug("Init audio RTP session\n"); - ost::InetHostAddress remote_ip(_ca->getRemoteSdpAudioIp()); + ost::InetHostAddress remote_ip(_ca->getRemoteIp().c_str()); if (!remote_ip) { - _debug("AudioRTP Thread Error: Target IP address [%s] is not correct!\n", _ca->getRemoteSdpAudioIp()); + _debug("AudioRTP Thread Error: Target IP address [%s] is not correct!\n", _ca->getRemoteIp().data()); return; } @@ -178,12 +178,12 @@ AudioRtpRTX::initAudioRtpSession (void) } if (!_sym) { - if ( !_sessionRecv->addDestination(remote_ip, (unsigned short) _ca->getRemoteSdpAudioPort()) ) { - _debug("AudioRTP Thread Error: could not connect to port %d\n", _ca->getLocalAudioPort()); + if ( !_sessionRecv->addDestination(remote_ip, (unsigned short) _ca->getRemoteAudioPort()) ) { + _debug("AudioRTP Thread Error: could not connect to port %d\n", _ca->getRemoteAudioPort()); return; } - if (!_sessionSend->addDestination (remote_ip, (unsigned short) _ca->getRemoteSdpAudioPort())) { - _debug("AudioRTP Thread Error: could not connect to port %d\n", _ca->getRemoteSdpAudioPort()); + if (!_sessionSend->addDestination (remote_ip, (unsigned short) _ca->getRemoteAudioPort())) { + _debug("AudioRTP Thread Error: could not connect to port %d\n", _ca->getRemoteAudioPort()); return; } @@ -202,7 +202,7 @@ AudioRtpRTX::initAudioRtpSession (void) //_debug("AudioRTP Thread: Added session destination %s:%d\n", remote_ip.getHostname(), (unsigned short) _ca->getRemoteSdpAudioPort()); - if (!_session->addDestination (remote_ip, (unsigned short) _ca->getRemoteSdpAudioPort())) { + if (!_session->addDestination (remote_ip, (unsigned short) _ca->getRemoteAudioPort())) { return; } @@ -451,6 +451,7 @@ AudioRtpRTX::run () { audiolayer->flushMic(); audiolayer->startStream(); _start.post(); + _debug("AudioRTP Start\n"); while (!testCancel()) { //////////////////////////// // Send session @@ -471,11 +472,11 @@ AudioRtpRTX::run () { audiolayer->stopStream(); } catch(std::exception &e) { _start.post(); - _debug("AudioRTP Thread, run: %s\n", e.what()); + _debug("AudioRTP Stop: %s\n", e.what()); throw; } catch(...) { _start.post(); - _debugException("AudioRTP Thread, run()"); + _debugException("AudioRTP Stop"); throw; } delete [] data_for_speakers_stereo; data_for_speakers_stereo = 0; diff --git a/src/audio/audiortp.h b/src/audio/audiortp.h index aab5eaa425cd3b4247c085bca519ee82394eaf75..5a787ee802d905efe1819a3254cec1ae55682756 100644 --- a/src/audio/audiortp.h +++ b/src/audio/audiortp.h @@ -29,21 +29,21 @@ #define RTP_FRAMES2SEND 160 class AudioLayer; -class SipCall; +class SIPCall; /////////////////////////////////////////////////////////////////////////////// // Two pair of sockets /////////////////////////////////////////////////////////////////////////////// class AudioRtpRTX : public ost::Thread, public ost::TimerPort { public: - AudioRtpRTX (SipCall *, AudioLayer*, bool); + AudioRtpRTX (SIPCall *, AudioLayer*, bool); ~AudioRtpRTX(); ost::Time *time; // For incoming call notification virtual void run (); private: - SipCall* _ca; + SIPCall* _ca; AudioLayer* _audioDevice; ost::RTPSession *_sessionSend; ost::RTPSession *_sessionRecv; @@ -72,7 +72,7 @@ public: AudioRtp(); ~AudioRtp(); - int createNewSession (SipCall *); + int createNewSession (SIPCall *); void closeRtpSession (); private: diff --git a/src/call.cpp b/src/call.cpp index 38332db002c852c0c406aab9565f77a8f9a0400e..f483ed883a3b90104fc44a5bca4885ad6826c639 100644 --- a/src/call.cpp +++ b/src/call.cpp @@ -1,271 +1,61 @@ -/** - * Copyright (C) 2004-2005 Savoir-Faire Linux inc. +/* + * Copyright (C) 2004-2006 Savoir-Faire Linux inc. * Author: Yan Morin <yan.morin@savoirfairelinux.com> - * Author: Laurielle Lea <laurielle.lea@savoirfairelinux.com> - * + * Author : Laurielle Lea <laurielle.lea@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 2 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 <iostream> - #include "call.h" -#include "voIPLink.h" - -Call::Call (CALLID id, Call::CallType type, VoIPLink* voiplink) -{ - _state = NotExist; - _type = Null; - _id = id; - _type = type; - _voIPLink = voiplink; - _flagNotAnswered = true; - - switch (_type) { - case Outgoing: - _voIPLink->newOutgoingCall(_id); - break; - case Incoming: - _voIPLink->newIncomingCall(_id); - break; - default: - break; - } -} -Call::~Call (void) +Call::Call(const CallID& id, Call::CallType type) : _id(id), _type(type) { + _connectionState = Call::Disconnected; + _callState = Call::Inactive; } -CALLID -Call::getId (void) -{ - return _id; -} -void -Call::setId (CALLID id) +Call::~Call() { - _id = id; } void -Call::setVoIPLink (VoIPLink* voIPLink) -{ - _voIPLink = voIPLink; -} - -VoIPLink* -Call::getVoIPLink (void) -{ - return _voIPLink; -} - -std::string -Call::getCallerIdName (void) +Call::setConnectionState(ConnectionState state) { - return _callerIdName; + ost::MutexLock m(_callMutex); + _connectionState = state; } -void -Call::setCallerIdName (const std::string& callerId_name) +Call::ConnectionState +Call::getConnectionState() { - _callerIdName = callerId_name; + ost::MutexLock m(_callMutex); + return _connectionState; } -std::string -Call::getCallerIdNumber (void) -{ - return _callerIdNumber; -} void -Call::setCallerIdNumber (const std::string& callerId_number) +Call::setState(CallState state) { - _callerIdNumber = callerId_number; + ost::MutexLock m(_callMutex); + _callState = state; } Call::CallState -Call::getState (void) -{ - return _state; -} - -void -Call::setState (Call::CallState state) -{ - _state = state; -} - -Call::CallType -Call::getType (void) +Call::getState() { - return _type; + ost::MutexLock m(_callMutex); + return _callState; } -void -Call::setType (Call::CallType type) -{ - _type = type; -} - -bool -Call::isBusy (void) -{ - if (isAnswered() or isOffHold() or isOnMute() or isOffMute()) { - return true; - } else { - return false; - } -} -bool -Call::isOnHold (void) -{ - return (_state == OnHold) ? true : false; -} - -bool -Call::isOffHold (void) -{ - return (_state == OffHold) ? true : false; -} - -bool -Call::isOnMute (void) -{ - return (_state == MuteOn) ? true : false; -} - -bool -Call::isOffMute (void) -{ - return (_state == MuteOff) ? true : false; -} - -bool -Call::isTransfered (void) -{ - return (_state == Transfered) ? true : false; -} - -bool -Call::isHungup (void) -{ - return (_state == Hungup) ? true : false; -} - -bool -Call::isRinging (void) -{ - return (_state == Ringing) ? true : false; -} - -bool -Call::isRefused (void) -{ - return (_state == Refused) ? true : false; -} - - -bool -Call::isAnswered (void) -{ - return (_state == Answered) ? true : false; -} - -bool -Call::isNotAnswered (void) -{ - return (_state == Error || _state == NotExist || _state == Busy) ? true : false; -} - -bool -Call::isProgressing (void) -{ - return (_state == Progressing) ? true : false; -} - -bool -Call::isOutgoingType (void) -{ - return (_type == Outgoing) ? true : false; -} - -bool -Call::isIncomingType (void) -{ - return (_type == Incoming) ? true : false; -} - -int -Call::outgoingCall(const std::string& to) -{ - return _voIPLink->outgoingInvite(_id, to); -} - -int -Call::hangup (void) -{ - int i = _voIPLink->hangup(_id); - setState(Hungup); - return i; -} - -int -Call::cancel (void) -{ - int i = _voIPLink->cancel(_id); - setState(Hungup); - return i; -} - -int -Call::answer (void) -{ - _flagNotAnswered = false; - int i = _voIPLink->answer(_id); - setState(Answered); - return i; -} - -int -Call::onHold (void) -{ - int i = _voIPLink->onhold(_id); - setState(OnHold); - return i; -} - -int -Call::offHold (void) -{ - int i = _voIPLink->offhold(_id); - setState(OffHold); - return i; -} - -int -Call::transfer (const std::string& to) -{ - int i = _voIPLink->transfer(_id, to); - setState(Transfered); - return i; -} - -int -Call::refuse (void) -{ - int i = _voIPLink->refuse(_id); - return i; -} diff --git a/src/call.h b/src/call.h index d6cf60513f750c296819cf0248313aabf48e5399..1f260825e7dbc7b3adc34568b393f9dfbac1c4f7 100644 --- a/src/call.h +++ b/src/call.h @@ -1,120 +1,109 @@ -/** - * Copyright (C) 2004-2005 Savoir-Faire Linux inc. +/* + * Copyright (C) 2004-2006 Savoir-Faire Linux inc. * Author: Yan Morin <yan.morin@savoirfairelinux.com> - * Author: Laurielle Lea <laurielle.lea@savoirfairelinux.com> - * + * Author : Laurielle Lea <laurielle.lea@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 2 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 __CALL_H__ -#define __CALL_H__ +#ifndef CALL_H +#define CALL_H #include <string> +#include <cc++/thread.h> // for mutex + +//TODO: remove this, it's only for call ID +typedef std::string CallID; + +/** + @author Yan Morin <yan.morin@gmail.com> + A call is the base classes for protocol-based calls +*/ +class Call{ +public: + enum CallType {Incoming, Outgoing}; + enum ConnectionState {Disconnected, Trying, Progressing, Ringing, Connected }; + enum CallState {Inactive, Active, Hold, Busy, Refused, Error}; -typedef unsigned int CALLID; + /** + * Constructor of a call + * @param id Unique identifier of the call + * @param type set definitely this call as incoming/outgoing + */ + Call(const CallID& id, Call::CallType type); + virtual ~Call(); + /** + * Return a reference on the call id + * @return call id + */ + CallID& getCallId() {return _id; } -class VoIPLink; + /** + * Set the peer number (destination on outgoing) + * not protected by mutex (when created) + * @param number peer number + */ + void setPeerNumber(const std::string& number) { _peerNumber = number; } + const std::string& getPeerNumber() { return _peerNumber; } -class Call { -public: - enum CallType { - Null = 0, - Incoming, - Outgoing - }; + /** + * Set the peer name (caller in ingoing) + * not protected by mutex (when created) + * @param number peer number + */ + void setPeerName(const std::string& name) { _peerName = name; } + const std::string& getPeerName() { return _peerName; } + + /** + * Set the connection state of the call (protected by mutex) + */ + void setConnectionState(ConnectionState state); + /** + * get the connection state of the call (protected by mutex) + */ + ConnectionState getConnectionState(); - enum CallState { - NotExist = 0, - Busy, - OnHold, - OffHold, - MuteOn, - MuteOff, - Transfered, - Hungup, - Answered, - Ringing, - Progressing, - Refused, // for refuse incoming ringing call - Error // when a error occur - }; + /** + * Set the state of the call (protected by mutex) + */ + void setState(CallState state); + /** + * get the call state of the call (protected by mutex) + */ + CallState getState(); - // Constructor - Call(CALLID id, CallType type, VoIPLink* voiplink); - // Destructor - ~Call(void); - +protected: + /** Protect every attribute that can be changed by two threads */ + ost::Mutex _callMutex; - // Handle call-id - CALLID getId (void); - void setId (CALLID id); - - // Accessor and modifior of VoIPLink - VoIPLink* getVoIPLink(void); - void setVoIPLink (VoIPLink* voIPLink); - - // Handle id name and id number - std::string getCallerIdName (void); - void setCallerIdName (const std::string& callerId_name); - std::string getCallerIdNumber (void); - void setCallerIdNumber (const std::string& callerId_number); - - // Handle state - CallState getState (void); - void setState (CallState state); - - // Handle type of call (incoming or outoing) - enum CallType getType (void); - void setType (enum CallType type); +private: + /** Unique ID of the call */ + CallID _id; - bool isNotAnswered(void); - bool isBusy (void); - bool isOnHold (void); - bool isOffHold (void); - bool isOnMute (void); - bool isOffMute (void); - bool isTransfered (void); - bool isHungup (void); - bool isRinging (void); - bool isRefused (void); - bool isAnswered (void); - bool isProgressing (void); - bool isOutgoingType (void); - bool isIncomingType (void); - - int outgoingCall (const std::string& to); - int hangup (void); - int cancel (void); - int answer (void); - int onHold (void); - int offHold (void); - int transfer (const std::string& to); - int refuse (void); - void setFlagNotAnswered(bool value) { _flagNotAnswered = value; } - bool getFlagNotAnswered() const { return _flagNotAnswered; } + /** Type of the call */ + CallType _type; + /** Disconnected/Progressing/Trying/Ringing/Connected */ + ConnectionState _connectionState; + /** Inactive/Active/Hold/Busy/Refused/Error */ + CallState _callState; -private: - VoIPLink *_voIPLink; - CALLID _id; - enum CallState _state; - enum CallType _type; - std::string _callerIdName; - std::string _callerIdNumber; + /** Name of the peer */ + std::string _peerName; - bool _flagNotAnswered; + /** Number of the peer */ + std::string _peerNumber; }; -#endif // __CALL_H__ +#endif diff --git a/src/eventthread.cpp b/src/eventthread.cpp index 6e445ab232c3adda875de21ae6842ca0743dd7f9..7edc957062885343e4a99961ca21c25cafe1150e 100644 --- a/src/eventthread.cpp +++ b/src/eventthread.cpp @@ -19,11 +19,11 @@ */ #include "eventthread.h" -#include "sipvoiplink.h" +#include "voIPLink.h" -EventThread::EventThread (SipVoIPLink* sip) : Thread () +EventThread::EventThread (VoIPLink* link) : Thread () { - _sipthread = sip; + _linkthread = link; setCancel(cancelDeferred); } @@ -39,7 +39,7 @@ void EventThread::run (void) { while(!testCancel()) { - _sipthread->getEvent(); + _linkthread->getEvent(); } } diff --git a/src/eventthread.h b/src/eventthread.h index 7508b1cfc33effb6911cb74ec83c028efaf7ff42..a9eba59aeaeecd8a2c22ccbf2bfc130b8797b606 100644 --- a/src/eventthread.h +++ b/src/eventthread.h @@ -1,4 +1,4 @@ -/** +/* * Copyright (C) 2004-2005 Savoir-Faire Linux inc. * Author: Yan Morin <yan.morin@savoirfairelinux.com> * Author : Laurielle Lea <laurielle.lea@savoirfairelinux.com> @@ -23,16 +23,23 @@ #include <cc++/thread.h> - -class SipVoIPLink; +class VoIPLink; +/** + * General thread to listen events continuously + */ class EventThread : public ost::Thread { public: - EventThread (SipVoIPLink*); + /** + * Build a thread that call getEvents + */ + EventThread (VoIPLink*); ~EventThread (void); virtual void run (); + private: - SipVoIPLink* _sipthread; + /** VoIPLink is the object being called by getEvents() method */ + VoIPLink* _linkthread; }; #endif // __EVENT_THREAD_H__ diff --git a/src/gui/guiframework.cpp b/src/gui/guiframework.cpp index d0a84605d0c85e73cc18b7852f3fb1c3128f88a0..49150ab4950f07992ab258dad3d5d87a3b3dd9cf 100644 --- a/src/gui/guiframework.cpp +++ b/src/gui/guiframework.cpp @@ -1,5 +1,5 @@ -/** - * Copyright (C) 2004-2005 Savoir-Faire Linux inc. +/* + * Copyright (C) 2004-2006 Savoir-Faire Linux inc. * Author: Yan Morin <yan.morin@savoirfairelinux.com> * Author: Laurielle Lea <laurielle.lea@savoirfairelinux.com> * @@ -30,10 +30,10 @@ GuiFramework::GuiFramework () GuiFramework::~GuiFramework (void) {} -int -GuiFramework::outgoingCall(const std::string&, const std::string& to) +bool +GuiFramework::outgoingCall(const std::string& account, const CallID& id, const std::string& to) { - return Manager::instance().outgoingCall(to); + return Manager::instance().outgoingCall(account, id, to); } bool @@ -42,64 +42,40 @@ GuiFramework::sendTextMessage(const std::string& account, const std::string& to, return Manager::instance().sendTextMessage(account, to, message); } -int -GuiFramework::hangupCall (CALLID id) +bool +GuiFramework::hangupCall (const CallID& id) { - if (Manager::instance().hangupCall(id) == 0) { - return 1; - } else { - return 0; - } + return Manager::instance().hangupCall(id); } -int -GuiFramework::cancelCall (CALLID id) +bool +GuiFramework::cancelCall (const CallID& id) { - if (Manager::instance().cancelCall(id) == 0) { - return 1; - } else { - return 0; - } + return Manager::instance().cancelCall(id); } -int -GuiFramework::answerCall (CALLID id) +bool +GuiFramework::answerCall(const CallID& id) { - if (Manager::instance().answerCall(id) == 0) { - return 1; - } else { - return 0; - } + return Manager::instance().answerCall(id); } -int -GuiFramework::onHoldCall (CALLID id) +bool +GuiFramework::onHoldCall(const CallID& id) { - if (Manager::instance().onHoldCall(id) == 0) { - return 1; - } else { - return 0; - } + return Manager::instance().onHoldCall(id); } -int -GuiFramework::offHoldCall (CALLID id) +bool +GuiFramework::offHoldCall(const CallID& id) { - if (Manager::instance().offHoldCall(id) == 0) { - return 1; - } else { - return 0; - } + return Manager::instance().offHoldCall(id); } -int -GuiFramework::transferCall (CALLID id, const std::string& to) +bool +GuiFramework::transferCall(const CallID& id, const std::string& to) { - if (Manager::instance().transferCall(id, to) == 0) { - return 1; - } else { - return 0; - } + return Manager::instance().transferCall(id, to); } void @@ -107,20 +83,17 @@ GuiFramework::mute() { Manager::instance().mute(); } + void GuiFramework::unmute() { Manager::instance().unmute(); } -int -GuiFramework::refuseCall (CALLID id) +bool +GuiFramework::refuseCall (const CallID& id) { - if (Manager::instance().refuseCall(id) == 0) { - return 1; - } else { - return 0; - } + return Manager::instance().refuseCall(id); } bool @@ -130,19 +103,19 @@ GuiFramework::saveConfig (void) } bool -GuiFramework::registerVoIPLink (void) +GuiFramework::registerVoIPLink(const AccountID& accountId) { - return Manager::instance().registerVoIPLink(); + return Manager::instance().registerVoIPLink(accountId); } bool -GuiFramework::unregisterVoIPLink (void) +GuiFramework::unregisterVoIPLink (const AccountID& accountId) { - return Manager::instance().unregisterVoIPLink(); + return Manager::instance().unregisterVoIPLink(accountId); } bool -GuiFramework::sendDtmf (CALLID id, char code) +GuiFramework::sendDtmf (const CallID& id, char code) { return Manager::instance().sendDtmf(id, code); } @@ -202,7 +175,7 @@ GuiFramework::getCallStatus(const std::string& sequenceId) return Manager::instance().getCallStatus(sequenceId); } -CALLID +const CallID& GuiFramework::getCurrentId() { return Manager::instance().getCurrentCallId(); diff --git a/src/gui/guiframework.h b/src/gui/guiframework.h index 18242b499899f0ea4dae66cb805661143e0385dc..9a45ac5ca019e3b79cbf1bc070780bc6076c1cf0 100644 --- a/src/gui/guiframework.h +++ b/src/gui/guiframework.h @@ -1,5 +1,5 @@ -/** - * Copyright (C) 2004-2005 Savoir-Faire Linux inc. +/* + * Copyright (C) 2004-2006 Savoir-Faire Linux inc. * Author: Yan Morin <yan.morin@savoirfairelinux.com> * Author: Laurielle Lea <laurielle.lea@savoirfairelinux.com> * @@ -26,7 +26,8 @@ #include <string> #include "server/argtokenizer.h" #include "../observer.h" -#include "../call.h" +#include "../call.h" // for callid2 +#include "../account.h" // for account class GuiFramework { public: @@ -34,43 +35,45 @@ public: virtual ~GuiFramework (void); /* Parent class to child class */ - virtual int incomingCall (CALLID id, const std::string& accountId, const std::string& from) = 0; - virtual void peerAnsweredCall (CALLID id) = 0; - virtual void peerRingingCall (CALLID id) = 0; - virtual void peerHungupCall (CALLID id) = 0; - virtual void incomingMessage(const std::string& message) = 0; + virtual bool incomingCall (const AccountID& accountId, const CallID& id, const std::string& from) = 0; + + virtual void peerAnsweredCall (const CallID& id) = 0; + virtual void peerRingingCall (const CallID& id) = 0; + virtual void peerHungupCall (const CallID& id) = 0; + virtual void incomingMessage(const AccountID& accountId, const std::string& message) = 0; virtual void displayStatus (const std::string& status) = 0; virtual void displayConfigError (const std::string& error) = 0; - virtual void displayTextMessage (CALLID id, const std::string& message) = 0; - virtual void displayErrorText (CALLID id, const std::string& message) = 0; + virtual void displayTextMessage (const CallID& id, const std::string& message) = 0; + virtual void displayErrorText (const CallID& id, const std::string& message) = 0; virtual void displayError (const std::string& error) = 0; virtual void startVoiceMessageNotification (void) {} virtual void stopVoiceMessageNotification (void) {} - virtual void sendVoiceNbMessage(const std::string& nb_msg) = 0; + virtual void sendVoiceNbMessage(const AccountID& accountId, const std::string& nb_msg) = 0; virtual void setup() = 0; virtual void sendMessage(const std::string& code, const std::string& seqId, TokenList& arg) = 0; virtual void sendCallMessage(const std::string& code, - const std::string& sequenceId, CALLID id, TokenList arg) = 0; - virtual void sendRegistrationState(bool state) = 0; - virtual void callFailure(CALLID id) = 0; + const std::string& sequenceId, const CallID& id, TokenList arg) = 0; + virtual void sendRegistrationState(const AccountID& accountid, bool state) = 0; + virtual void callFailure(const CallID& id) = 0; /* Child class to parent class */ - int outgoingCall(const std::string& account, const std::string& to); - bool sendTextMessage(const std::string& account, const std::string& to, const std::string& message); - int hangupCall (CALLID id); - int cancelCall (CALLID id); - int answerCall (CALLID id); - int onHoldCall (CALLID id); - int offHoldCall (CALLID id); - int transferCall (CALLID id, const std::string& to); + bool outgoingCall(const AccountID& account, const CallID& id, const std::string& to); + bool answerCall(const CallID& id); + + bool sendTextMessage(const AccountID& accountId, const std::string& to, const std::string& message); + bool hangupCall (const CallID& id); + bool cancelCall (const CallID& id); + bool onHoldCall (const CallID& id); + bool offHoldCall (const CallID& id); + bool transferCall (const CallID& id, const std::string& to); void mute (); void unmute (); - int refuseCall (CALLID id); + bool refuseCall (const CallID& id); bool saveConfig(void); - bool registerVoIPLink(void); - bool unregisterVoIPLink(void); - bool sendDtmf (CALLID id, char code); + bool registerVoIPLink(const AccountID& accountId); + bool unregisterVoIPLink(const AccountID& accountId); + bool sendDtmf (const CallID& id, char code); bool playDtmf (char code); bool playTone (); bool stopTone (); @@ -92,7 +95,7 @@ public: bool setSwitch(const std::string& switchName); bool hasLoadedSetup(); - CALLID getCurrentId(); + const CallID& getCurrentId(); bool getRegistrationState(std::string& stateCode, std::string& stateMessage); protected: diff --git a/src/gui/qt/ConfigurationPanel.ui.h b/src/gui/qt/ConfigurationPanel.ui.h index a6ee2f33799eaafaa6762cbc1403c3c9a83a6ee4..fe7c445f705fae42709610012e54c487184114fb 100644 --- a/src/gui/qt/ConfigurationPanel.ui.h +++ b/src/gui/qt/ConfigurationPanel.ui.h @@ -1,4 +1,4 @@ -/** +/* * Copyright (C) 2004-2006 Savoir-Faire Linux inc. * Author: Yan Morin <yan.morin@savoirfairelinux.com> * Author: Jean-Philippe Barrette-LaPierre @@ -133,43 +133,41 @@ ConfigurationPanel::generate() .get(AUDIO_SECTION, AUDIO_RINGTONE)); + QString account = ACCOUNT_DEFAULT_NAME; + QString type = ConfigurationManager::instance().get(account, ACCOUNT_TYPE); + QString active = ConfigurationManager::instance().get(account, ACCOUNT_ENABLE); + // For signalisations tab + autoregister->setChecked(ConfigurationManager::instance() + .get(account,ACCOUNT_AUTO_REGISTER).toUInt()); + fullName->setText(ConfigurationManager::instance() - .get(SIGNALISATION_SECTION, - SIGNALISATION_FULL_NAME)); + .get(account,SIGNALISATION_FULL_NAME)); userPart->setText(ConfigurationManager::instance() - .get(SIGNALISATION_SECTION, - SIGNALISATION_USER_PART)); + .get(account,SIGNALISATION_USER_PART)); username->setText(ConfigurationManager::instance() - .get(SIGNALISATION_SECTION, - SIGNALISATION_AUTH_USER_NAME)); + .get(account,SIGNALISATION_AUTH_USER_NAME)); password->setText(ConfigurationManager::instance() - .get(SIGNALISATION_SECTION, - SIGNALISATION_PASSWORD)); + .get(account,SIGNALISATION_PASSWORD)); hostPart->setText(ConfigurationManager::instance() - .get(SIGNALISATION_SECTION, - SIGNALISATION_HOST_PART)); + .get(account,SIGNALISATION_HOST_PART)); sipproxy->setText(ConfigurationManager::instance() - .get(SIGNALISATION_SECTION, - SIGNALISATION_PROXY)); - autoregister->setChecked(ConfigurationManager::instance() - .get(SIGNALISATION_SECTION, - SIGNALISATION_AUTO_REGISTER).toUInt()); + .get(account,SIGNALISATION_PROXY)); + STUNserver->setText(ConfigurationManager::instance() + .get(account,SIGNALISATION_STUN_SERVER)); + ((QRadioButton*)stunButtonGroup->find(ConfigurationManager::instance() + .get(account,SIGNALISATION_USE_STUN).toUInt()))->setChecked(true); + + sendDTMFas->setCurrentItem(ConfigurationManager::instance() + .get(SIGNALISATION_SECTION, + SIGNALISATION_SEND_DTMF_AS).toUInt()); playTones->setChecked(ConfigurationManager::instance() .get(SIGNALISATION_SECTION, SIGNALISATION_PLAY_TONES).toUInt()); pulseLength->setValue(ConfigurationManager::instance() .get(SIGNALISATION_SECTION, SIGNALISATION_PULSE_LENGTH).toUInt()); - sendDTMFas->setCurrentItem(ConfigurationManager::instance() - .get(SIGNALISATION_SECTION, - SIGNALISATION_SEND_DTMF_AS).toUInt()); - STUNserver->setText(ConfigurationManager::instance() - .get(SIGNALISATION_SECTION, - SIGNALISATION_STUN_SERVER)); - ((QRadioButton*)stunButtonGroup->find(ConfigurationManager::instance() - .get(SIGNALISATION_SECTION, - SIGNALISATION_USE_STUN).toUInt()))->setChecked(true); + QRadioButton* device = static_cast< QRadioButton * >(DriverChoice->find(ConfigurationManager::instance() .get(AUDIO_SECTION, @@ -185,27 +183,32 @@ ConfigurationPanel::generate() // For saving settings at application 'save' void ConfigurationPanel::saveSlot() { - ConfigurationManager::instance().set(SIGNALISATION_SECTION, + QString account = ACCOUNT_DEFAULT_NAME; + ConfigurationManager::instance().set(account, SIGNALISATION_FULL_NAME, fullName->text()); - ConfigurationManager::instance().set(SIGNALISATION_SECTION, + ConfigurationManager::instance().set(account, SIGNALISATION_USER_PART, userPart->text()); - ConfigurationManager::instance().set(SIGNALISATION_SECTION, + ConfigurationManager::instance().set(account, SIGNALISATION_AUTH_USER_NAME, username->text()); - ConfigurationManager::instance().set(SIGNALISATION_SECTION, + ConfigurationManager::instance().set(account, SIGNALISATION_PASSWORD, password->text()); - ConfigurationManager::instance().set(SIGNALISATION_SECTION, + ConfigurationManager::instance().set(account, SIGNALISATION_HOST_PART, hostPart->text()); - ConfigurationManager::instance().set(SIGNALISATION_SECTION, + ConfigurationManager::instance().set(account, SIGNALISATION_PROXY, sipproxy->text()); - ConfigurationManager::instance().set(SIGNALISATION_SECTION, - SIGNALISATION_AUTO_REGISTER, + ConfigurationManager::instance().set(account, + ACCOUNT_AUTO_REGISTER, QString::number(autoregister->isChecked())); + ConfigurationManager::instance().set(account, + SIGNALISATION_STUN_SERVER, + STUNserver->text()); + ConfigurationManager::instance().set(SIGNALISATION_SECTION, SIGNALISATION_PULSE_LENGTH, QString::number(pulseLength->value())); @@ -215,9 +218,6 @@ void ConfigurationPanel::saveSlot() ConfigurationManager::instance().set(SIGNALISATION_SECTION, SIGNALISATION_SEND_DTMF_AS, QString::number(sendDTMFas->currentItem())); - ConfigurationManager::instance().set(SIGNALISATION_SECTION, - SIGNALISATION_STUN_SERVER, - STUNserver->text()); if (codec1->currentText() != NULL) { ConfigurationManager::instance().set(AUDIO_SECTION, @@ -292,7 +292,8 @@ void ConfigurationPanel::changeTabSlot() void ConfigurationPanel::useStunSlot(int id) { - ConfigurationManager::instance().set(SIGNALISATION_SECTION, + QString account = ACCOUNT_DEFAULT_NAME; + ConfigurationManager::instance().set(account, SIGNALISATION_USE_STUN, QString::number(id)); } diff --git a/src/gui/qt/Session.cpp b/src/gui/qt/Session.cpp index 02d80a6e1eb0502874b2eeb6de3649fe29aaff81..9491565ac684411d26cf1f1d2aab5cb1e14cd492 100644 --- a/src/gui/qt/Session.cpp +++ b/src/gui/qt/Session.cpp @@ -176,6 +176,6 @@ Session::getAccount(const QString &name) const Account Session::getDefaultAccount() const { - return Account(mId, QString("mydefaultaccount")); + return Account(mId, QString("SIP0")); } diff --git a/src/gui/qt/globals.h b/src/gui/qt/globals.h index 6d446339806df99f15f6c0c004cf1cdcbe6656fc..80565bebd616ed9a650761af2180689955c38452 100644 --- a/src/gui/qt/globals.h +++ b/src/gui/qt/globals.h @@ -32,7 +32,6 @@ #define AUDIO_CODEC3 "Codecs.codec3" #define AUDIO_RINGTONE "Rings.ringChoice" - #define SIGNALISATION_SECTION "VoIPLink" #define SIGNALISATION_FULL_NAME "SIP.fullName" #define SIGNALISATION_USER_PART "SIP.userPart" @@ -40,12 +39,16 @@ #define SIGNALISATION_PASSWORD "SIP.password" #define SIGNALISATION_HOST_PART "SIP.hostPart" #define SIGNALISATION_PROXY "SIP.proxy" -#define SIGNALISATION_AUTO_REGISTER "SIP.autoregister" +#define SIGNALISATION_STUN_SERVER "STUN.STUNserver" +#define SIGNALISATION_USE_STUN "STUN.useStun" #define SIGNALISATION_PLAY_TONES "DTMF.playTones" #define SIGNALISATION_PULSE_LENGTH "DTMF.pulseLength" #define SIGNALISATION_SEND_DTMF_AS "DTMF.sendDTMFas" -#define SIGNALISATION_STUN_SERVER "STUN.STUNserver" -#define SIGNALISATION_USE_STUN "STUN.useStun" + +#define ACCOUNT_DEFAULT_NAME "SIP0" +#define ACCOUNT_TYPE "Account.type" +#define ACCOUNT_ENABLE "Account.enable" +#define ACCOUNT_AUTO_REGISTER "Account.autoregister" #define PREFERENCES_SECTION "Preferences" #define PREFERENCES_THEME "Themes.skinChoice" diff --git a/src/gui/server/guiserverimpl.cpp b/src/gui/server/guiserverimpl.cpp index 50f99f8796293bfa5bbf262223e47176eb38ac3d..a050875fb8410b848879c27294c3159534042481 100644 --- a/src/gui/server/guiserverimpl.cpp +++ b/src/gui/server/guiserverimpl.cpp @@ -48,12 +48,13 @@ GUIServerImpl::exec() { * remove */ void -GUIServerImpl::insertSubCall(CALLID id, SubCall& subCall) { - _callMap[id] = subCall; +GUIServerImpl::insertSubCall(const CallID& id, const CallID& seq) { + + _callMap[id] = seq; } void -GUIServerImpl::removeSubCall(CALLID id) { +GUIServerImpl::removeSubCall(const CallID& id) { _callMap.erase(id); } @@ -61,32 +62,21 @@ GUIServerImpl::removeSubCall(CALLID id) { * Retreive the sequenceId or send default sequenceId */ std::string -GUIServerImpl::getSequenceIdFromId(CALLID id) { +GUIServerImpl::getSequenceIdFromId(const CallID& id) { CallMap::iterator iter = _callMap.find(id); if (iter != _callMap.end()) { - return iter->second.sequenceId(); + return iter->second; } return _getEventsSequenceId; } -/** - * Retreive the string callid from the id - */ -std::string -GUIServerImpl::getCallIdFromId(CALLID id) { - CallMap::iterator iter = _callMap.find(id); - if (iter != _callMap.end()) { - return iter->second.callId(); - } - throw std::runtime_error(_("No match for this id")); -} bool GUIServerImpl::getCurrentCallId(std::string& callId) { bool returnValue = false; try { - CALLID id = GuiFramework::getCurrentId(); - if (id!=0) { - callId = getCallIdFromId(id); + CallID id = GuiFramework::getCurrentId(); + if (id != "") { + callId = id; returnValue = true; } } catch(...) { @@ -95,19 +85,6 @@ GUIServerImpl::getCurrentCallId(std::string& callId) { return returnValue; } -CALLID -GUIServerImpl::getIdFromCallId(const std::string& callId) -{ - CallMap::iterator iter = _callMap.begin(); - while (iter != _callMap.end()) { - if (iter->second.callId()==callId) { - return iter->first; - } - iter++; - } - throw std::runtime_error(_("No match for this CallId")); -} - bool GUIServerImpl::getEvents(const std::string& sequenceId) { @@ -165,96 +142,45 @@ GUIServerImpl::outgoingCall(const std::string& seq, const std::string& callid, const std::string& to) { - CALLID serverCallId = GuiFramework::outgoingCall(account, to); - if ( serverCallId ) { - SubCall subcall(seq, callid); - insertSubCall(serverCallId, subcall); - return true; - } else { - return false; - } + insertSubCall(callid, seq); + return GuiFramework::outgoingCall(account, callid, to); } bool GUIServerImpl::answerCall(const std::string& callId) { - try { - CALLID id = getIdFromCallId(callId); - if (GuiFramework::answerCall(id)) { - return true; - } - } catch(...) { - return false; - } - return false; + return GuiFramework::answerCall(callId); } bool GUIServerImpl::refuseCall(const std::string& callId) { - try { - CALLID id = getIdFromCallId(callId); - if (GuiFramework::refuseCall(id)) { - return true; - } - } catch(...) { - return false; - } - return false; + return GuiFramework::refuseCall(callId); } bool GUIServerImpl::transferCall(const std::string& callId, const std::string& to) { - try { - CALLID id = getIdFromCallId(callId); - if (GuiFramework::transferCall(id, to)) { - return true; - } - } catch(...) { - return false; - } - return false; + return GuiFramework::transferCall(callId, to); } bool GUIServerImpl::holdCall(const std::string& callId) { - try { - CALLID id = getIdFromCallId(callId); - if (GuiFramework::onHoldCall(id)) { - return true; - } - } catch(...) { - return false; - } - return false; + return GuiFramework::onHoldCall(callId); } bool GUIServerImpl::unholdCall(const std::string& callId) { - try { - CALLID id = getIdFromCallId(callId); - if (GuiFramework::offHoldCall(id)) { - return true; - } - } catch(...) { - return false; - } - return false; + return GuiFramework::offHoldCall(callId); } bool GUIServerImpl::hangupCall(const std::string& callId) { - try { - CALLID id = getIdFromCallId(callId); - if (GuiFramework::hangupCall(id)) { - _callMap.erase(id); - return true; - } - } catch(...) { - return false; + if ( GuiFramework::hangupCall(callId) ) { + removeSubCall(callId); + return true; } return false; } @@ -267,12 +193,10 @@ bool GUIServerImpl::hangupAll() { bool result = true; - CALLID id; CallMap::iterator iter = _callMap.begin(); // try to hangup every call, even if one fail while(iter!=_callMap.end()) { - id = iter->first; - if (!GuiFramework::hangupCall(id)) { + if (!GuiFramework::hangupCall(iter->first)) { result = false; } iter++; @@ -284,14 +208,7 @@ GUIServerImpl::hangupAll() bool GUIServerImpl::dtmfCall(const std::string& callId, const std::string& dtmfKey) { - try { - CALLID id = getIdFromCallId(callId); - char code = dtmfKey[0]; - return GuiFramework::sendDtmf(id, code); - } catch(...) { - return false; - } - return false; + return GuiFramework::sendDtmf(callId, dtmfKey[0]); } /** @@ -307,62 +224,60 @@ GUIServerImpl::version() } -int -GUIServerImpl::incomingCall (CALLID id, const std::string& accountId, const std::string& from) +bool +GUIServerImpl::incomingCall(const AccountID& accountId, const CallID& id, const std::string& from) { TokenList arg; - std::ostringstream callId; - callId << "s" << id; - arg.push_back(callId.str()); + arg.push_back(id); arg.push_back(accountId); arg.push_back(from); arg.push_back("call"); - SubCall subcall(_getEventsSequenceId, callId.str()); - - insertSubCall(id, subcall); - - _requestManager.sendResponse(ResponseMessage("001", _getEventsSequenceId,arg)); + insertSubCall(id, _getEventsSequenceId); + _requestManager.sendResponse(ResponseMessage("001", _getEventsSequenceId, arg)); return 0; } void -GUIServerImpl::incomingMessage(const std::string& message) { - _requestManager.sendResponse(ResponseMessage("030", _getEventsSequenceId, message)); +GUIServerImpl::incomingMessage(const std::string& account, const std::string& message) { + TokenList arg; + arg.push_back(account); + arg.push_back(message); + _requestManager.sendResponse(ResponseMessage("030", _getEventsSequenceId, arg)); } void -GUIServerImpl::peerAnsweredCall (CALLID id) +GUIServerImpl::peerAnsweredCall (const CallID& id) { CallMap::iterator iter = _callMap.find(id); if ( iter != _callMap.end() ) { - _requestManager.sendResponse(ResponseMessage("200", iter->second.sequenceId(), _("Established"))); + _requestManager.sendResponse(ResponseMessage("200", iter->second, _("Established"))); } } void -GUIServerImpl::peerRingingCall (CALLID id) +GUIServerImpl::peerRingingCall (const CallID& id) { CallMap::iterator iter = _callMap.find(id); if ( iter != _callMap.end() ) { - _requestManager.sendResponse(ResponseMessage("151", iter->second.sequenceId(), _("Ringing"))); + _requestManager.sendResponse(ResponseMessage("151", iter->second, _("Ringing"))); } } void -GUIServerImpl::peerHungupCall (CALLID id) +GUIServerImpl::peerHungupCall (const CallID& id) { CallMap::iterator iter = _callMap.find(id); if ( iter != _callMap.end() ) { TokenList tk; - tk.push_back(iter->second.callId()); + tk.push_back(id); tk.push_back("hangup"); _requestManager.sendResponse(ResponseMessage("002", _getEventsSequenceId,tk)); // remove this call... - _callMap.erase(id); + removeSubCall(id); } } @@ -385,36 +300,23 @@ GUIServerImpl::displayConfigError (const std::string& error) } void -GUIServerImpl::displayTextMessage (CALLID id, const std::string& message) +GUIServerImpl::displayTextMessage (const CallID& id, const std::string& message) { - try { - std::string callId = getCallIdFromId(id); - TokenList tk; - tk.push_back(callId); - tk.push_back(message); - tk.push_back("Text message"); - _requestManager.sendResponse(ResponseMessage("102", _getEventsSequenceId, tk)); - } catch(...) { - TokenList tk; - tk.push_back(message); - tk.push_back("Text message"); - _requestManager.sendResponse(ResponseMessage("103", _getEventsSequenceId, tk)); - } + TokenList tk; + tk.push_back(id); + tk.push_back(message); + tk.push_back("Text message"); + _requestManager.sendResponse(ResponseMessage("102", _getEventsSequenceId, tk)); } void -GUIServerImpl::displayErrorText (CALLID id, const std::string& message) +GUIServerImpl::displayErrorText (const CallID& id, const std::string& message) { - try { - std::string callId = getCallIdFromId(id); - TokenList tk; - tk.push_back(callId); - tk.push_back(message); - tk.push_back("Error"); - _requestManager.sendResponse(ResponseMessage("104", _getEventsSequenceId, tk)); - } catch(...) { - displayError(message); - } + TokenList tk; + tk.push_back(id); + tk.push_back(message); + tk.push_back("Error"); + _requestManager.sendResponse(ResponseMessage("104", _getEventsSequenceId, tk)); } void @@ -427,18 +329,25 @@ GUIServerImpl::displayError (const std::string& error) } void -GUIServerImpl::sendVoiceNbMessage(const std::string& nb_msg) +GUIServerImpl::sendVoiceNbMessage(const AccountID& accountId, const std::string& nb_msg) { - _requestManager.sendResponse(ResponseMessage("020", _getEventsSequenceId, nb_msg)); + TokenList tk; + tk.push_back(accountId); + tk.push_back(nb_msg); + _requestManager.sendResponse(ResponseMessage("020", _getEventsSequenceId, tk)); } void -GUIServerImpl::sendRegistrationState(bool state) +GUIServerImpl::sendRegistrationState(const AccountID& accountid, bool state) { + TokenList tk; + tk.push_back(accountid); if (state == true) { - _requestManager.sendResponse(ResponseMessage("003", _getEventsSequenceId, _("Registration succeed"))); + tk.push_back(_("Registration succeed")); + _requestManager.sendResponse(ResponseMessage("003", _getEventsSequenceId, tk)); } else { - _requestManager.sendResponse(ResponseMessage("004", _getEventsSequenceId, _("Registration failed"))); + tk.push_back(_("Registration failed")); + _requestManager.sendResponse(ResponseMessage("004", _getEventsSequenceId, tk)); } } void @@ -455,12 +364,11 @@ GUIServerImpl::sendMessage(const std::string& code, const std::string& seqId, To void GUIServerImpl::sendCallMessage(const std::string& code, const std::string& sequenceId, - CALLID id, + const CallID& id, TokenList arg) { try { - std::string callid = getCallIdFromId(id); - arg.push_front(callid); + arg.push_front(id); _requestManager.sendResponse(ResponseMessage(code, sequenceId, arg)); } catch(...) { // no callid found @@ -474,14 +382,15 @@ GUIServerImpl::update() } void -GUIServerImpl::callFailure(CALLID id) +GUIServerImpl::callFailure(const CallID& id) { CallMap::iterator iter = _callMap.find(id); if ( iter != _callMap.end() ) { TokenList tk; - tk.push_back(iter->second.callId()); + tk.push_back(id); tk.push_back("Wrong number"); - _requestManager.sendResponse(ResponseMessage("504", iter->second.sequenceId(), tk)); + _requestManager.sendResponse(ResponseMessage("504", iter->second, tk)); + removeSubCall(id); } } diff --git a/src/gui/server/guiserverimpl.h b/src/gui/server/guiserverimpl.h index f237a3f3d0b19ccb9728796f4497795acad7077b..8b2a8ab8dae8cefd2b64d6f643ec4fafa2963198 100644 --- a/src/gui/server/guiserverimpl.h +++ b/src/gui/server/guiserverimpl.h @@ -23,14 +23,13 @@ #include <string> #include <map> -#include "subcall.h" #include "requestmanager.h" /** Session port for the daemon, default is DEFAULT_SESSION_PORT */ #define DEFAULT_SESSION_PORT 3999 -typedef std::map<CALLID, SubCall> CallMap; +typedef std::map<CallID, std::string> CallMap; class GUIServerImpl : public GuiFramework { public: @@ -42,26 +41,26 @@ public: // exec loop int exec(void); - int incomingCall(CALLID id, const std::string& accountId, const std::string& from); - void incomingMessage(const std::string& message); + bool incomingCall(const AccountID& accountId, const CallID& id, const std::string& from); + void incomingMessage(const AccountID& accountId, const std::string& message); - void peerAnsweredCall (CALLID id); - void peerRingingCall (CALLID id); - void peerHungupCall (CALLID id); + void peerAnsweredCall (const CallID& id); + void peerRingingCall (const CallID& id); + void peerHungupCall (const CallID& id); void displayStatus (const std::string& status); void displayConfigError(const std::string& error); - void displayTextMessage (CALLID id, const std::string& message); - void displayErrorText (CALLID id, const std::string& message); + void displayTextMessage (const CallID& id, const std::string& message); + void displayErrorText (const CallID& id, const std::string& message); void displayError (const std::string& error); - void sendVoiceNbMessage(const std::string& nb_msg); - void sendRegistrationState(bool state); + void sendVoiceNbMessage(const AccountID& accountid, const std::string& nb_msg); + void sendRegistrationState(const AccountID& accountid, bool state); void setup(); void sendMessage(const std::string& code, const std::string& seqId, TokenList& arg); void sendCallMessage(const std::string& code, const std::string& sequenceId, - CALLID id, TokenList arg); - void callFailure(CALLID id); + const CallID& id, TokenList arg); + void callFailure(const CallID& id); bool getEvents(const std::string& sequenceId); bool sendGetEventsEnd(); @@ -90,17 +89,13 @@ public: }; private: - void insertSubCall(CALLID id, SubCall& subCall); - void removeSubCall(CALLID id); - std::string getSequenceIdFromId(CALLID id); - std::string getCallIdFromId(CALLID id); - CALLID getIdFromCallId(const std::string& callId); - + void insertSubCall(const CallID& id, const std::string& seq); + void removeSubCall(const CallID& id); + std::string getSequenceIdFromId(const CallID& id); /** * This callMap is necessary because - * ManagerImpl use callid-int - * and the client use a callid-string + * because we want to retreive the seq associate to a call id * and also a sequence number */ CallMap _callMap; diff --git a/src/gui/server/request.cpp b/src/gui/server/request.cpp index c4d84edfc6790a005edbeb14701c106275092475..124ec473a79a0f8e669e914b606dfa767ec58192 100644 --- a/src/gui/server/request.cpp +++ b/src/gui/server/request.cpp @@ -32,19 +32,19 @@ RequestCall::execute() } ResponseMessage -RequestTextMessage::execute() +RequestAnswer::execute() { - if ( GUIServer::instance().sendTextMessage(_account, _destination, _message) ) { - return message("200", "Sending message"); + if ( GUIServer::instance().answerCall(_callId) ) { + return message("200", _("OK")); } return message("500","Server Error"); } ResponseMessage -RequestAnswer::execute() +RequestTextMessage::execute() { - if ( GUIServer::instance().answerCall(_callId) ) { - return message("200", _("OK")); + if ( GUIServer::instance().sendTextMessage(_account, _destination, _message) ) { + return message("200", "Sending message"); } return message("500","Server Error"); } diff --git a/src/gui/server/requestconfig.cpp b/src/gui/server/requestconfig.cpp index 5ce1f5431a01ae13cef5a9254af925dcb63e8d5d..134a26ab7b89b1688eaf4344493e71072eb96655 100644 --- a/src/gui/server/requestconfig.cpp +++ b/src/gui/server/requestconfig.cpp @@ -242,20 +242,42 @@ RequestVolumeMic::execute() } } +RequestRegister::RequestRegister(const std::string &sequenceId, const TokenList& argList) : RequestGlobal(sequenceId,argList) +{ + TokenList::iterator iter = _argList.begin(); + if (iter != _argList.end()) { + _accountId = *iter; + _argList.pop_front(); + } else { + throw RequestConstructorException(); + } +} + ResponseMessage RequestRegister::execute() { - if (GUIServer::instance().registerVoIPLink()) { + if (GUIServer::instance().registerVoIPLink(_accountId)) { return message("200", _("OK")); } else { return message("500",_("Registration sending failed")); } } +RequestUnregister::RequestUnregister(const std::string &sequenceId, const TokenList& argList) : RequestGlobal(sequenceId,argList) +{ + TokenList::iterator iter = _argList.begin(); + if (iter != _argList.end()) { + _accountId = *iter; + _argList.pop_front(); + } else { + throw RequestConstructorException(); + } +} + ResponseMessage RequestUnregister::execute() { - if (GUIServer::instance().unregisterVoIPLink()) { + if (GUIServer::instance().unregisterVoIPLink(_accountId)) { return message("200", _("OK")); } else { return message("500",_("Unregistration sending failed")); diff --git a/src/gui/server/requestconfig.h b/src/gui/server/requestconfig.h index c34cbb8202ddd77a08526c6d2550134067bd5a69..2edd772625abd0f487f040079bce5929d5f496a3 100644 --- a/src/gui/server/requestconfig.h +++ b/src/gui/server/requestconfig.h @@ -112,14 +112,18 @@ private: class RequestRegister : public RequestGlobal { public: - RequestRegister(const std::string &sequenceId, const TokenList& argList) : RequestGlobal(sequenceId, argList) {} + RequestRegister(const std::string &sequenceId, const TokenList& argList); ResponseMessage execute(); +private: + std::string _accountId; }; class RequestUnregister : public RequestGlobal { public: - RequestUnregister(const std::string &sequenceId, const TokenList& argList) : RequestGlobal(sequenceId, argList) {} + RequestUnregister(const std::string &sequenceId, const TokenList& argList); ResponseMessage execute(); +private: + std::string _accountId; }; class RequestSwitch : public RequestGlobal { public: diff --git a/src/aixaccount.h b/src/iaxvoiplink.cpp similarity index 64% rename from src/aixaccount.h rename to src/iaxvoiplink.cpp index d5d54e289b792129da6d64f4d96ae9c7fa2f86ec..7b0729d5acc1e8b3cd268db4b418ed63e4bb1a42 100644 --- a/src/aixaccount.h +++ b/src/iaxvoiplink.cpp @@ -16,32 +16,16 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ -#ifndef AIXACCOUNT_H -#define AIXACCOUNT_H +#include "iaxvoiplink.h" -#include "account.h" - -/** - @author Yan Morin <yan.morin@gmail.com> - An AIX Account specify AIX specific functions and objects (AIXCall/AIXVoIPLink) -*/ -class AIXAccount : public Account +IAXVoIPLink::IAXVoIPLink(const AccountID& accountID) + : VoIPLink(accountID) { -public: - AIXAccount(const AccountID& accountID); +} - ~AIXAccount(); - /* virtual Account function implementation */ - void initConfig(Conf::ConfigTree& config); - bool registerAccount(); - bool unregisterAccount(); - bool init(); - bool terminate(); +IAXVoIPLink::~IAXVoIPLink() +{ +} -private: - /* virtual Account function implementation */ - bool createVoIPLink(); -}; -#endif diff --git a/src/iaxvoiplink.h b/src/iaxvoiplink.h new file mode 100644 index 0000000000000000000000000000000000000000..fddd03a88a0e20f64825972220263a55c406b073 --- /dev/null +++ b/src/iaxvoiplink.h @@ -0,0 +1,59 @@ +/* + * Copyright (C) 2006 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 2 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 IAXVOIPLINK_H +#define IAXVOIPLINK_H + +#include "voIPLink.h" + +class AudioCodec; + +/** + @author Yan Morin <yan.morin@gmail.com> + VoIPLink contains a thread that listen to external events and + contains IAX Call related functions +*/ +class IAXVoIPLink : public VoIPLink +{ +public: + IAXVoIPLink(const AccountID& accountID); + + ~IAXVoIPLink(); + + void getEvent (void) { } + bool init (void) { return false; } + bool checkNetwork (void) { return false; } + void terminate (void) { } + + bool setRegister (void) { return false; } + bool setUnregister (void) { return false; } + + Call* newOutgoingCall(const CallID& id, const std::string& toUrl) {return 0; } + bool answer(const CallID& id) {return false;} + + bool hangup(const CallID& id) { return false; } + bool cancel(const CallID& id) { return false; } + bool onhold(const CallID& id) { return false; } + bool offhold(const CallID& id) { return false; } + bool transfer(const CallID& id, const std::string& to) { return false; } + bool refuse (const CallID& id) { return false; } + bool carryingDTMFdigits(const CallID& id, char code) { return false; } + bool sendMessage(const std::string& to, const std::string& body) { return false; } +}; + +#endif diff --git a/src/main.cpp b/src/main.cpp index fafad62cf8d4fc47ffadc77df73882c8e4abbe7c..bb74946f9c2904fc30614a687fb2f3fdfaf4340e 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -22,7 +22,7 @@ #include <cstring> #include <iostream> -#include "config.h" +//#include "config.h" #include "global.h" #include "user_cfg.h" diff --git a/src/managerimpl.cpp b/src/managerimpl.cpp index 6cb14fb00a6aaace0429caa100c86b091246c62c..3085ce1c8de60a116c303da573c9b907b3a71091 100644 --- a/src/managerimpl.cpp +++ b/src/managerimpl.cpp @@ -39,7 +39,6 @@ #include "accountcreator.h" // create new account #include "voIPLink.h" -#include "call.h" #include "user_cfg.h" #include "gui/guiframework.h" @@ -54,8 +53,6 @@ #define fill_config_int(name, value) \ (_config.addConfigTreeItem(section, Conf::ConfigTreeItem(std::string(name), std::string(value), type_int))) -#define DFT_VOIP_LINK 0 - ManagerImpl::ManagerImpl (void) { // Init private variables @@ -73,19 +70,18 @@ ManagerImpl::ManagerImpl (void) _setupLoaded = false; _gui = NULL; + // sound _audiodriverPA = NULL; _dtmfKey = 0; - - // Initialize after by init() -> initVolume() - _spkr_volume = 0; - _mic_volume = 0; - _mic_volume_before_mute = 0; + _spkr_volume = 0; // Initialize after by init() -> initVolume() + _mic_volume = 0; // Initialize after by init() -> initVolume() + _mic_volume_before_mute = 0; // Call - _currentCallId = 0; _nbIncomingWaitingCall=0; _registerState = UNREGISTERED; _hasTriedToRegister = false; + // initialize random generator for call id srand (time(NULL)); @@ -156,8 +152,6 @@ ManagerImpl::init() _dtmfKey = new DTMF(sampleRate, outChannel); } - _debugInit("Adding new VoIP Link"); - // initRegisterVoIP was here, but we doing it after the gui loaded... // the stun detection is long, so it's a better idea to do it after getEvents initZeroconf(); @@ -169,16 +163,6 @@ void ManagerImpl::terminate() unloadAccountMap(); - _debug("Removing calls\n"); - _mutex.enterMutex(); - for(CallVector::iterator pos = _callVector.begin(); - pos != _callVector.end(); - pos++) { - delete *pos; *pos = NULL; - } - _callVector.clear(); - _mutex.leaveMutex(); - _debug("Unload DTMF Key\n"); delete _dtmfKey; @@ -189,230 +173,165 @@ void ManagerImpl::terminate() delete _telephoneTone; _telephoneTone = 0; } -void -ManagerImpl::setGui(GuiFramework* gui) -{ - _gui = gui; -} - -/** - * Multi Thread with _mutex for callVector - */ -Call * -ManagerImpl::pushBackNewCall(CALLID id, Call::CallType type) -{ - ost::MutexLock m(_mutex); - - Call* call = new Call(id, type, getAccountLink(ACCOUNT_SIP0)); - // Set the wanted voip-link (first of the list) - _callVector.push_back(call); - return call; -} - -/** - * Multi Thread with _mutex for callVector - */ -Call* -ManagerImpl::getCall(CALLID id) -{ - //_debug("%10d: Getting call\n", id); - Call* call = NULL; - unsigned int size = _callVector.size(); - for (unsigned int i = 0; i < size; i++) { - call = _callVector.at(i); - if (call && call->getId() == id) { - break; - } else { - call = NULL; - } - } - return call; +bool +ManagerImpl::isCurrentCall(const CallID& callId) { + ost::MutexLock m(_currentCallMutex); + return (_currentCallId2 == callId ? true : false); } -/** - * Multi Thread with _mutex for callVector - */ -void -ManagerImpl::deleteCall (CALLID id) -{ - //_debug("%10d: Deleting call\n", id); - CallVector::iterator iter = _callVector.begin(); - while(iter!=_callVector.end()) { - Call *call = *iter; - if (call != NULL && call->getId() == id) { - if (call->getFlagNotAnswered() && call->isIncomingType() && call->getState() != Call::NotExist) { - decWaitingCall(); - } - delete (*iter); *iter = NULL; - call = NULL; - _callVector.erase(iter); - return; - } - iter++; +bool +ManagerImpl::hasCurrentCall() { + ost::MutexLock m(_currentCallMutex); + if ( _currentCallId2 != "") { + return true; } + return false; } -void -ManagerImpl::setCurrentCallId(CALLID id) -{ - //_debug("%10d: Setting current callid, old one was: %d\n", id, _currentCallId); - _currentCallId = id; +const CallID& +ManagerImpl::getCurrentCallId() { + ost::MutexLock m(_currentCallMutex); + return _currentCallId2; } void -ManagerImpl::removeCallFromCurrent(CALLID id) -{ - if ( _currentCallId == id ) { - //_debug("%10d: Setting current callid, old one was: %d\n", 0, _currentCallId); - _currentCallId = 0; - } +ManagerImpl::switchCall(const CallID& id ) { + ost::MutexLock m(_currentCallMutex); + _currentCallId2 = id; } /////////////////////////////////////////////////////////////////////////////// // Management of events' IP-phone user /////////////////////////////////////////////////////////////////////////////// -/** - * Main thread - */ -int -ManagerImpl::outgoingCall (const std::string& to) -{ - CALLID id = generateNewCallId(); - _debug("%10d: Outgoing Call\n", id); - Call *call = pushBackNewCall(id, Call::Outgoing); - ost::MutexLock m(_mutex); - call->setState(Call::Progressing); - call->setCallerIdNumber(to); - if (call->outgoingCall(to) == 0) { - return id; +/* Main Thread */ +bool +ManagerImpl::outgoingCall(const std::string& accountid, const CallID& id, const std::string& to) +{ + if (!accountExists(accountid)) { + _debug("Outgoing Call: account doesn't exist\n"); + return false; + } + if (getAccountFromCall(id) != AccountNULL) { + _debug("Outgoing Call: call id already exists\n"); + return false; + } + _debug("Adding Outgoing Call %s on account %s\n", id.data(), accountid.data()); + if ( getAccountLink(accountid)->newOutgoingCall(id, to) ) { + associateCallToAccount( id, accountid ); + switchCall(id); + return true; } else { - return 0; + _debug("An error occur, the call was not created\n"); } + return false; } -/** - * Main thread - */ -bool -ManagerImpl::sendTextMessage(const std::string&, const std::string& to, const std::string& message) +//THREAD=Main : for outgoing Call +bool +ManagerImpl::answerCall(const CallID& id) { - return getAccountLink(ACCOUNT_SIP0)->sendMessage(to, message); -} + stopTone(); -/** - * User action (main thread) - * Every Call - */ -int -ManagerImpl::hangupCall (CALLID id) -{ - _debug("%10d: Hangup Call\n", id); - stopTone(); - ost::MutexLock m(_mutex); - Call* call = getCall(id); - if (call == NULL) { - return -1; - } - int result = -1; - if (call->getState() != Call::Error) { - result = call->hangup(); + AccountID accountid = getAccountFromCall( id ); + if (accountid == AccountNULL) { + _debug("Answering Call: Call doesn't exists\n"); + return false; } - deleteCall(id); - // current call id or no line selected - if (id == _currentCallId || _currentCallId == 0) { - removeCallFromCurrent(id); + + if (!getAccountLink(accountid)->answer(id)) { + // error when receiving... + removeCallAccount(id); + return false; } - return result; + + // if it was waiting, it's waiting no more + removeWaitingCall(id); + switchCall(id); + return true; } -/** - * User action (main thread) - * Every Call - * -1 : call not found - * 0 : already in this state... - */ -int -ManagerImpl::cancelCall (CALLID id) +//THREAD=Main +bool +ManagerImpl::sendTextMessage(const AccountID& accountId, const std::string& to, const std::string& message) { - _debug("%10d: Cancel Call\n", id); - ost::MutexLock m(_mutex); - Call* call = getCall(id); - if (call == NULL) { - return -1; + if (accountExists(accountId)) { + return getAccountLink(accountId)->sendMessage(to, message); } - int result = call->cancel(); - deleteCall(id); - stopTone(); - return result; + return false; } -/** - * User action (main thread) - * Incoming Call - */ -int -ManagerImpl::answerCall (CALLID id) +//THREAD=Main +bool +ManagerImpl::hangupCall(const CallID& id) { - _debug("%10d: Answer Call\n", id); - ost::MutexLock m(_mutex); - Call* call = getCall(id); - if (call == NULL) { - return -1; - } - if (call->getFlagNotAnswered()) { - decWaitingCall(); - call->setFlagNotAnswered(false); - } - if (call->getState() != Call::OnHold) { - switchCall(id); + stopTone(); + + AccountID accountid = getAccountFromCall( id ); + if (accountid == AccountNULL) { + _debug("Hangup Call: Call doesn't exists\n"); + return false; } - stopTone(); // before answer, don't stop the audio stream after open it - return call->answer(); + + bool returnValue = getAccountLink(accountid)->hangup(id); + removeCallAccount(id); + switchCall(""); + + return returnValue; } -/** - * User action (main thread) - * Every Call - * @return 0 if it fails, -1 if not present - */ -int -ManagerImpl::onHoldCall (CALLID id) +//THREAD=Main +bool +ManagerImpl::cancelCall (const CallID& id) { - _debug("%10d: On Hold Call\n", id); - ost::MutexLock m(_mutex); - Call* call = getCall(id); - if (call == NULL) { - return -1; - } - removeCallFromCurrent(id); - if ( call->getState() == Call::OnHold || call->isNotAnswered()) { - return 1; + stopTone(); + AccountID accountid = getAccountFromCall( id ); + if (accountid == AccountNULL) { + _debug("Cancel Call: Call doesn't exists\n"); + return false; } - return call->onHold(); + + bool returnValue = getAccountLink(accountid)->cancel(id); + // it could be a waiting call? + removeWaitingCall(id); + removeCallAccount(id); + switchCall(""); + + return returnValue; } -/** - * User action (main thread) - * Every Call - */ -int -ManagerImpl::offHoldCall (CALLID id) +//THREAD=Main +bool +ManagerImpl::onHoldCall(const CallID& id) { - _debug("%10d: Off Hold Call\n", id); - ost::MutexLock m(_mutex); stopTone(); - Call* call = getCall(id); - if (call == 0) { - return -1; + AccountID accountid = getAccountFromCall( id ); + if (accountid == AccountNULL) { + _debug("On Hold Call: Call doesn't exists\n"); + return false; } - if (call->getState() == Call::OffHold) { - return 1; + + bool returnValue = getAccountLink(accountid)->onhold(id); + removeWaitingCall(id); + switchCall(""); + + return returnValue; +} + +//THREAD=Main +bool +ManagerImpl::offHoldCall(const CallID& id) +{ + stopTone(); + AccountID accountid = getAccountFromCall( id ); + if (accountid == AccountNULL) { + _debug("OffHold Call: Call doesn't exists\n"); + return false; } - setCurrentCallId(id); - int returnValue = call->offHold(); - // start audio if it's ok - if (returnValue != -1) { + bool returnValue = getAccountLink(accountid)->offhold(id); + switchCall(id); + + if (returnValue) { try { getAudioDriver()->startStream(); } catch(...) { @@ -422,37 +341,32 @@ ManagerImpl::offHoldCall (CALLID id) return returnValue; } -/** - * User action (main thread) - * Every Call - */ -int -ManagerImpl::transferCall (CALLID id, const std::string& to) +//THREAD=Main +bool +ManagerImpl::transferCall(const CallID& id, const std::string& to) { - _debug("%10d: Transfer Call to %s\n", id, to.c_str()); - ost::MutexLock m(_mutex); - Call* call = getCall(id); - if (call == 0) { - return -1; + stopTone(); + AccountID accountid = getAccountFromCall( id ); + if (accountid == AccountNULL) { + _debug("Transfer Call: Call doesn't exists\n"); + return false; } - removeCallFromCurrent(id); - return call->transfer(to); + bool returnValue = getAccountLink(accountid)->transfer(id, to); + removeWaitingCall(id); + removeCallAccount(id); + switchCall(""); + + return returnValue; } -/** - * User action (main thread) - * All Call - */ +//THREAD=Main void ManagerImpl::mute() { _mic_volume_before_mute = _mic_volume; setMicVolume(0); } -/** - * User action (main thread) - * All Call - */ +//THREAD=Main void ManagerImpl::unmute() { if ( _mic_volume == 0 ) { @@ -460,34 +374,24 @@ ManagerImpl::unmute() { } } -/** - * User action (main thread) - * Call Incoming - */ -int -ManagerImpl::refuseCall (CALLID id) +//THREAD=Main : Call:Incoming +bool +ManagerImpl::refuseCall (const CallID& id) { - _debug("%10d: Refuse Call\n", id); - ost::MutexLock m(_mutex); - Call *call = getCall(id); - if (call == NULL) { - return -1; - } - - if ( call->getState() != Call::Progressing ) { - return -1; - } - - int refuse = call->refuse(); - removeCallFromCurrent(id); - deleteCall(id); stopTone(); - return refuse; + AccountID accountid = getAccountFromCall( id ); + if (accountid == AccountNULL) { + _debug("OffHold Call: Call doesn't exists\n"); + return false; + } + bool returnValue = getAccountLink(accountid)->refuse(id); + removeWaitingCall(id); + removeCallAccount(id); + switchCall(""); + return returnValue; } -/** - * User action (main thread) - */ +//THREAD=Main bool ManagerImpl::saveConfig (void) { @@ -499,73 +403,67 @@ ManagerImpl::saveConfig (void) return _setupLoaded; } -/** - * Main Thread - */ +//THREAD=Main bool ManagerImpl::initRegisterVoIPLink() { - int returnValue = true; - _debugInit("Initiate VoIP Link Registration\n"); - if (_hasTriedToRegister == false) { - if ( getAccount(ACCOUNT_SIP0)->init() ) { - // we call here, because it's long... - // If network is available and exosip is start.. - if (getConfigInt(SIGNALISATION, AUTO_REGISTER) && _exist == 1) { - registerVoIPLink(); - _hasTriedToRegister = true; + _debugInit("Initiate VoIP Links Registration\n"); + AccountMap::iterator iter = _accountMap.begin(); + while( iter != _accountMap.end() ) { + if ( iter->second) { + iter->second->loadConfig(); + if ( iter->second->shouldInitOnStart() ) { + iter->second->init(); + if (iter->second->shouldRegisterOnStart()) { + iter->second->registerAccount(); + } } - } else { - returnValue = false; } + iter++; } - return returnValue; + return true; } - -/** - * Initialize action (main thread) - * Note that Registration is only send if STUN is not activated - * @return true if setRegister is call without failure, else return false - */ +//THREAD=Main bool -ManagerImpl::registerVoIPLink (void) +ManagerImpl::registerVoIPLink(const AccountID& accountId) { _debug("Register VoIP Link\n"); int returnValue = false; - returnValue = getAccount(ACCOUNT_SIP0)->registerAccount(); - if (returnValue) { - _registerState = REGISTERED; - } else { - _registerState = FAILED; + if (accountExists( accountId ) ) { + returnValue = getAccount(accountId)->registerAccount(); } return returnValue; } -/** - * Terminate action (main thread) - * @return true if the unregister method is send correctly - */ +//THREAD=Main bool -ManagerImpl::unregisterVoIPLink (void) +ManagerImpl::unregisterVoIPLink(const AccountID& accountId) { _debug("Unregister VoIP Link\n"); - return getAccount(ACCOUNT_SIP0)->unregisterAccount(); + int returnValue = false; + if (accountExists( accountId ) ) { + returnValue = getAccount(accountId)->registerAccount(); + } + return returnValue; } -/** - * User action (main thread) - */ +//THREAD=Main bool -ManagerImpl::sendDtmf (CALLID id, char code) +ManagerImpl::sendDtmf(const CallID& id, char code) { + AccountID accountid = getAccountFromCall( id ); + if (accountid == AccountNULL) { + _debug("Send DTMF: call doesn't exists\n"); + return false; + } + int sendType = getConfigInt(SIGNALISATION, SEND_DTMF_AS); - int returnValue = false; + bool returnValue = false; switch (sendType) { case 0: // SIP INFO playDtmf(code); - getAccountLink(ACCOUNT_SIP0)->carryingDTMFdigits(id, code); - returnValue = true; + returnValue = getAccountLink(accountid)->carryingDTMFdigits(id, code); break; case 1: // Audio way @@ -578,10 +476,7 @@ ManagerImpl::sendDtmf (CALLID id, char code) return returnValue; } -/** - * User action (main thread) - * Or sip event (dtmf body submit) - */ +//THREAD=Main | VoIPLink bool ManagerImpl::playDtmf(char code) { @@ -595,7 +490,6 @@ ManagerImpl::playDtmf(char code) // numbers of int = length in milliseconds / 1000 (number of seconds) // = number of seconds * SAMPLING_RATE by SECONDS - AudioLayer* audiolayer = getAudioDriver(); // fast return, no sound, so no dtmf @@ -634,264 +528,158 @@ ManagerImpl::playDtmf(char code) return returnValue; } -/////////////////////////////////////////////////////////////////////////////// -// Management of event peer IP-phone -//////////////////////////////////////////////////////////////////////////////// -/** - * Multi-thread - */ + + +// Multi-thread bool ManagerImpl::incomingCallWaiting() { - ost::MutexLock m(_incomingCallMutex); + ost::MutexLock m(_waitingCallMutex); return (_nbIncomingWaitingCall > 0) ? true : false; } void -ManagerImpl::incWaitingCall() { - ost::MutexLock m(_incomingCallMutex); +ManagerImpl::addWaitingCall(const CallID& id) { + ost::MutexLock m(_waitingCallMutex); + _waitingCall.insert(id); _nbIncomingWaitingCall++; - //_debug("incWaitingCall: %d\n", _nbIncomingWaitingCall); -} - -void -ManagerImpl::decWaitingCall() { - ost::MutexLock m(_incomingCallMutex); - _nbIncomingWaitingCall--; - //_debug("decWaitingCall: %d\n", _nbIncomingWaitingCall); } - -/** - * SipEvent Thread - * Set the call info for incoming call - */ void -ManagerImpl::callSetInfo(CALLID id, const std::string& name, const std::string& number) -{ - ost::MutexLock m(_mutex); - Call* call = getCall(id); - if (call != 0) { - call->setCallerIdName(name); - call->setCallerIdNumber(number); +ManagerImpl::removeWaitingCall(const CallID& id) { + ost::MutexLock m(_waitingCallMutex); + // should return more than 1 if it erase a call + if (_waitingCall.erase(id)) { + _nbIncomingWaitingCall--; } } -/** - * SipEvent Thread - * ask if it can close the call - */ bool -ManagerImpl::callCanBeClosed(CALLID id) { - bool returnValue = false; - ost::MutexLock m(_mutex); - Call* call = getCall(id); - if (call != NULL && call->getState() != Call::Progressing) { - returnValue = true; +ManagerImpl::isWaitingCall(const CallID& id) { + ost::MutexLock m(_waitingCallMutex); + CallIDSet::iterator iter = _waitingCall.find(id); + if (iter != _waitingCall.end()) { + return false; } - return returnValue; + return true; } -/** - * SipEvent Thread - * ask if it can answer the call - */ -bool -ManagerImpl::callCanBeAnswered(CALLID id) { - bool returnValue = false; - ost::MutexLock m(_mutex); - Call* call = getCall(id); - if (call != NULL && ( call->getFlagNotAnswered() || - (call->getState()!=Call::OnHold && call->getState()!=Call::OffHold) )) { - returnValue = true; - } - return returnValue; -} -/** - * SipEvent Thread - * ask if it can start the sound thread - */ -bool -ManagerImpl::callIsOnHold(CALLID id) { - bool returnValue = false; - ost::MutexLock m(_mutex); - Call* call = getCall(id); - if (call != NULL && (call->getState()==Call::OnHold)) { - returnValue = true; - } - return returnValue; -} -/** - * SipEvent Thread - */ -int -ManagerImpl::incomingCall (CALLID id, const std::string& name, const std::string& number) +/////////////////////////////////////////////////////////////////////////////// +// Management of event peer IP-phone +//////////////////////////////////////////////////////////////////////////////// +// SipEvent Thread +bool +ManagerImpl::incomingCall(Call* call, const AccountID& accountId) { - _debug("%10d: Incoming call\n", id); - ost::MutexLock m(_mutex); - Call* call = getCall(id); - if (call == NULL) { - return -1; - } - call->setType(Call::Incoming); - call->setState(Call::Progressing); - - if ( _currentCallId == 0 ) { - call->setFlagNotAnswered(false); + _debug("Incoming call\n"); + associateCallToAccount(call->getCallId(), accountId); + if ( !hasCurrentCall() ) { + call->setConnectionState(Call::Ringing); ringtone(); - switchCall(id); + switchCall(call->getCallId()); } else { - incWaitingCall(); + addWaitingCall(call->getCallId()); } - // TODO: Account not yet implemented - std::string accountId = "acc1"; - std::string from = name; call->setCallerIdName(name); - call->setCallerIdNumber(number); + std::string from = call->getPeerName(); + std::string number = call->getPeerNumber(); + if ( !number.empty() ) { from.append(" <"); from.append(number); from.append(">"); } - return _gui->incomingCall(id, accountId, from); + _gui->incomingCall(accountId, call->getCallId(), from); + + return true; } -/** - * SipEvent Thread - * for outgoing message, send by SipEvent - */ -void -ManagerImpl::incomingMessage(const std::string& message) { +//THREAD=VoIP +void +ManagerImpl::incomingMessage(const AccountID& accountId, const std::string& message) { if (_gui) { - _gui->incomingMessage(message); + _gui->incomingMessage(accountId, message); } } -/** - * SipEvent Thread - * for outgoing call, send by SipEvent - */ -void -ManagerImpl::peerAnsweredCall (CALLID id) +//THREAD=VoIP CALL=Outgoing +void +ManagerImpl::peerAnsweredCall(const CallID& id) { - _debug("%10d: Peer Answered Call\n", id); - ost::MutexLock m(_mutex); - Call* call = getCall(id); - if (call != 0) { - call->setFlagNotAnswered(false); - call->setState(Call::Answered); - + if (isCurrentCall(id)) { stopTone(); - // switch current call - switchCall(id); - if (_gui) _gui->peerAnsweredCall(id); } + if (_gui) _gui->peerAnsweredCall(id); } -/** - * SipEvent Thread - * for outgoing call, send by SipEvent - */ -int -ManagerImpl::peerRingingCall (CALLID id) +//THREAD=VoIP Call=Outgoing +void +ManagerImpl::peerRingingCall(const CallID& id) { - _debug("%10d: Peer Ringing Call\n", id); - ost::MutexLock m(_mutex); - Call* call = getCall(id); - if (call != 0) { - call->setState(Call::Ringing); - - // ring + if (isCurrentCall(id)) { ringback(); - if (_gui) _gui->peerRingingCall(id); } - return 1; + if (_gui) _gui->peerRingingCall(id); } -/** - * SipEvent Thread - * for outgoing call, send by SipEvent - */ -int -ManagerImpl::peerHungupCall (CALLID id) +//THREAD=VoIP Call=Outgoing/Ingoing +void +ManagerImpl::peerHungupCall(const CallID& id) { - _debug("%10d: Peer Hungup Call\n", id); - ost::MutexLock m(_mutex); - Call* call = getCall(id); - if ( call == NULL ) { - return -1; + AccountID accountid = getAccountFromCall( id ); + if (accountid == AccountNULL) { + _debug("peerHungupCall: Call doesn't exists\n"); + return; } - if ( _currentCallId == id ) { + if (isCurrentCall(id)) { stopTone(); + switchCall(""); } - - if (_gui) _gui->peerHungupCall(id); - deleteCall(id); - call->setState(Call::Hungup); - - removeCallFromCurrent(id); - return 1; + removeWaitingCall(id); + removeCallAccount(id); } -/** - * Multi Thread - */ +//THREAD=VoIP void -ManagerImpl::callBusy(CALLID id) { - _debug("%10d: Call is busy\n", id); - playATone(Tone::TONE_BUSY); - ost::MutexLock m(_mutex); - Call* call = getCall(id); - if (call != 0) { - call->setState(Call::Busy); +ManagerImpl::callBusy(const CallID& id) { + _debug("Call busy\n"); + if (isCurrentCall(id) ) { + playATone(Tone::TONE_BUSY); + switchCall(""); } - deleteCall(id); - call->setState(Call::Hungup); - - removeCallFromCurrent(id); + removeCallAccount(id); + removeWaitingCall(id); } -/** - * Multi Thread - */ +//THREAD=VoIP void -ManagerImpl::callFailure(CALLID id) { - _debug("%10d: Call failed\n", id); - playATone(Tone::TONE_BUSY); - _mutex.enterMutex(); - Call* call = getCall(id); - if (call != 0) { - call->setState(Call::Error); - } - _mutex.leaveMutex(); +ManagerImpl::callFailure(const CallID& id) +{ + _debug("Call failed\n"); + if (isCurrentCall(id) ) { + playATone(Tone::TONE_BUSY); + switchCall(""); + } if (_gui) { _gui->callFailure(id); } - deleteCall(id); - call->setState(Call::Hungup); - - removeCallFromCurrent(id); + removeCallAccount(id); + removeWaitingCall(id); } -/** - * SipEvent Thread - * for outgoing call, send by SipEvent - */ +//THREAD=VoIP void -ManagerImpl::displayTextMessage (CALLID id, const std::string& message) +ManagerImpl::displayTextMessage(const CallID& id, const std::string& message) { if(_gui) { - _gui->displayTextMessage(id, message); + _gui->displayTextMessage(id, message); } } -/** - * SipEvent Thread - * for outgoing call, send by SipEvent - */ +//THREAD=VoIP void -ManagerImpl::displayErrorText (CALLID id, const std::string& message) +ManagerImpl::displayErrorText(const CallID& id, const std::string& message) { if(_gui) { _gui->displayErrorText(id, message); @@ -900,10 +688,7 @@ ManagerImpl::displayErrorText (CALLID id, const std::string& message) } } -/** - * SipEvent Thread - * for outgoing call, send by SipEvent - */ +//THREAD=VoIP void ManagerImpl::displayError (const std::string& error) { @@ -912,22 +697,16 @@ ManagerImpl::displayError (const std::string& error) } } -/** - * SipEvent Thread - * for outgoing call, send by SipEvent - */ +//THREAD=VoIP void -ManagerImpl::displayStatus (const std::string& status) +ManagerImpl::displayStatus(const std::string& status) { if(_gui) { _gui->displayStatus(status); } } -/** - * SipEvent Thread - * for outgoing call, send by SipEvent - */ +//THREAD=VoIP void ManagerImpl::displayConfigError (const std::string& message) { @@ -936,42 +715,32 @@ ManagerImpl::displayConfigError (const std::string& message) } } -/** - * SipEvent Thread - * for outgoing call, send by SipEvent - */ +//THREAD=VoIP void -ManagerImpl::startVoiceMessageNotification (const std::string& nb_msg) +ManagerImpl::startVoiceMessageNotification(const AccountID& accountId, const std::string& nb_msg) { - if (_gui) _gui->sendVoiceNbMessage(nb_msg); + if (_gui) _gui->sendVoiceNbMessage(accountId, nb_msg); } -/** - * SipEvent Thread - * for outgoing call, send by SipEvent - */ +//THREAD=VoIP void -ManagerImpl::stopVoiceMessageNotification (void) +ManagerImpl::stopVoiceMessageNotification(const AccountID& accountId) { - if (_gui) _gui->sendVoiceNbMessage(std::string("0")); + if (_gui) _gui->sendVoiceNbMessage(accountId, std::string("0")); } -/** - * SipEvent Thread - */ +//THREAD=VoIP void -ManagerImpl::registrationSucceed() +ManagerImpl::registrationSucceed(const AccountID& accountid) { - if (_gui) _gui->sendRegistrationState(true); + if (_gui) _gui->sendRegistrationState(accountid, true); } -/** - * SipEvent Thread - */ +//THREAD=VoIP void -ManagerImpl::registrationFailed() +ManagerImpl::registrationFailed(const AccountID& accountid) { - if (_gui) _gui->sendRegistrationState(false); + if (_gui) _gui->sendRegistrationState(accountid, false); } /** @@ -1109,7 +878,7 @@ ManagerImpl::getTelephoneFile() * By AudioRTP thread */ void -ManagerImpl::notificationIncomingCall (void) { +ManagerImpl::notificationIncomingCall(void) { AudioLayer* audiolayer = getAudioDriver(); if (audiolayer != 0) { @@ -1123,7 +892,6 @@ ManagerImpl::notificationIncomingCall (void) { tone.getNext(buf, tone.getSize()); audiolayer->putUrgent(buf, sizeof(int16)*nbInt16); } - } /** @@ -1158,37 +926,30 @@ ManagerImpl::getStunInfo (StunAddress4& stunSvrAddr, int port) } bool -ManagerImpl::useStun (void) -{ - if (getConfigInt(SIGNALISATION, USE_STUN)) { - return true; - } else { - return false; +ManagerImpl::behindNat(int port) +{ + StunAddress4 stunSvrAddr; + stunSvrAddr.addr = 0; + + // Stun server + std::string svr = getConfigString(SIGNALISATION, STUN_SERVER); + + // Convert char* to StunAddress4 structure + bool ret = stunParseServerName ((char*)svr.data(), stunSvrAddr); + if (!ret) { + _debug("SIP: Stun server address (%s) is not valid\n", svr.data()); + return 0; } + + // Firewall address + //_debug("STUN server: %s\n", svr.data()); + return getStunInfo(stunSvrAddr, port); } + /////////////////////////////////////////////////////////////////////////////// // Private functions /////////////////////////////////////////////////////////////////////////////// - -/** - * Multi Thread - */ -CALLID -ManagerImpl::generateNewCallId (void) -{ - CALLID random_id = (unsigned)rand(); - - // Check if already a call with this id exists - _mutex.enterMutex(); - while (getCall(random_id) != NULL && random_id != 0) { - random_id = rand(); - } - _mutex.leaveMutex(); - // If random_id is not attributed, returns it. - return random_id; -} - /** * Initialization: Main Thread * @return 1: ok @@ -1357,7 +1118,7 @@ ManagerImpl::initZeroconf(void) void ManagerImpl::initVolume() { - _debugInit("Initiate Volume\n"); + _debugInit("Initiate Volume"); setSpkrVolume(getConfigInt(AUDIO, VOLUME_SPKR)); setMicVolume(getConfigInt(AUDIO, VOLUME_MICRO)); } @@ -1453,58 +1214,68 @@ ManagerImpl::getEvents() { return true; } +// TODO: rewrite this /** * Main Thread */ bool ManagerImpl::getCallStatus(const std::string& sequenceId) { - // TODO: implement account - std::string accountId = "acc1"; + if (!_gui) { return false; } + ost::MutexLock m(_callAccountMapMutex); + CallAccountMap::iterator iter = _callAccountMap.begin(); + TokenList tk; std::string code; std::string status; - TokenList tk; - Call* call; - - if (_gui!=NULL) { - ost::MutexLock m(_mutex); - CallVector::iterator iter = _callVector.begin(); - while(iter!=_callVector.end()){ - call = (*iter); - switch( call->getState() ) { - case Call::Progressing: code="110"; status="Trying"; break; - case Call::Ringing: code="111"; status = "Ringing"; break; - case Call::Answered: code="112"; status = "Established"; break; - case Call::Busy: code="113"; status = "Busy"; break; - case Call::OnHold: code="114"; status = "Held"; break; - case Call::OffHold: code="115"; status = "Unheld"; break; - default: code="125"; status="Other"; + std::string destination; + std::string number; + + while (iter != _callAccountMap.begin()) + { + Call* call = getAccountLink(iter->second)->getCall(iter->first); + Call::ConnectionState state = call->getConnectionState(); + if (state != Call::Connected) { + switch(state) { + case Call::Trying: code="110"; status = "Trying"; break; + case Call::Ringing: code="111"; status = "Ringing"; break; + case Call::Progressing: code="125"; status = "Progressing"; break; + case Call::Disconnected: code="125"; status = "Disconnected"; break; + default: code=""; status= ""; } - - // No Congestion - // No Wrong Number - // 116 <CSeq> <call-id> <acc> <destination> Busy - std::string destination = call->getCallerIdName(); - std::string number = call->getCallerIdNumber(); - if (number!="") { - destination.append(" <"); - destination.append(number); - destination.append(">"); + } else { + switch (call->getState()) { + case Call::Active: code="112"; status = "Established"; break; + case Call::Hold: code="114"; status = "Held"; break; + case Call::Busy: code="113"; status = "Busy"; break; + case Call::Refused: code="125"; status = "Refused"; break; + case Call::Error: code="125"; status = "Error"; break; + case Call::Inactive: code="125"; status = "Inactive"; break; } - tk.push_back(accountId); - tk.push_back(destination); - tk.push_back(status); - _gui->sendCallMessage(code, sequenceId, (*iter)->getId(), tk); - iter++; - tk.clear(); } + + // No Congestion + // No Wrong Number + // 116 <CSeq> <call-id> <acc> <destination> Busy + destination = call->getPeerName(); + number = call->getPeerNumber(); + if (number!="") { + destination.append(" <"); + destination.append(number); + destination.append(">"); + } + tk.push_back(iter->second); + tk.push_back(destination); + tk.push_back(status); + _gui->sendCallMessage(code, sequenceId, iter->first, tk); + tk.clear(); + + iter++; } + return true; } -/** - * Main Thread - */ +//THREAD=Main bool ManagerImpl::getConfigAll(const std::string& sequenceId) { @@ -1521,18 +1292,14 @@ ManagerImpl::getConfigAll(const std::string& sequenceId) return returnValue; } -/** - * Main Thread - */ +//THREAD=Main bool ManagerImpl::getConfig(const std::string& section, const std::string& name, TokenList& arg) { return _config.getConfigTreeItemToken(section, name, arg); } -/** - * Main Thread - */ +//THREAD=Main // throw an Conf::ConfigTreeItemException if not found int ManagerImpl::getConfigInt(const std::string& section, const std::string& name) @@ -1545,9 +1312,7 @@ ManagerImpl::getConfigInt(const std::string& section, const std::string& name) return 0; } -/** - * Main Thread - */ +//THREAD=Main std::string ManagerImpl::getConfigString(const std::string& section, const std::string& name) @@ -1560,18 +1325,14 @@ name) return ""; } -/** - * Main Thread - */ +//THREAD=Main bool ManagerImpl::setConfig(const std::string& section, const std::string& name, const std::string& value) { return _config.setConfigTreeItem(section, name, value); } -/** - * Main Thread - */ +//THREAD=Main bool ManagerImpl::setConfig(const std::string& section, const std::string& name, int value) { @@ -1580,9 +1341,7 @@ ManagerImpl::setConfig(const std::string& section, const std::string& name, int return _config.setConfigTreeItem(section, name, valueStream.str()); } -/** - * Main Thread - */ +//THREAD=Main bool ManagerImpl::getConfigList(const std::string& sequenceId, const std::string& name) { @@ -1634,9 +1393,7 @@ ManagerImpl::getConfigList(const std::string& sequenceId, const std::string& nam return returnValue; } -/** - * User request Main Thread (list) - */ +//THREAD=Main bool ManagerImpl::getAudioDeviceList(const std::string& sequenceId, int ioDeviceMask) { @@ -1672,6 +1429,7 @@ ManagerImpl::getAudioDeviceList(const std::string& sequenceId, int ioDeviceMask) return returnValue; } +//THREAD=Main bool ManagerImpl::getCountryTones(const std::string& sequenceId) { @@ -1687,6 +1445,7 @@ ManagerImpl::getCountryTones(const std::string& sequenceId) return true; } +//THREAD=Main void ManagerImpl::sendCountryTone(const std::string& sequenceId, int index, const std::string& name) { TokenList tk; @@ -1695,9 +1454,7 @@ ManagerImpl::sendCountryTone(const std::string& sequenceId, int index, const std _gui->sendMessage("100", sequenceId, tk); } -/** - * User action : main thread - */ +//THREAD=Main bool ManagerImpl::getDirListing(const std::string& sequenceId, const std::string& path, int *nbFile) { TokenList tk; @@ -1726,21 +1483,8 @@ ManagerImpl::getDirListing(const std::string& sequenceId, const std::string& pat } } -/** - * Multi Thread - */ -void -ManagerImpl::switchCall(CALLID id) -{ - // we can only switch the current call id if we - // it's not selected yet.. - if (_currentCallId == 0 ) { - setCurrentCallId(id); - } -} - -/** - * Main Thread - Gui +//THREAD=Main +/* * Experimental... */ bool @@ -1781,7 +1525,7 @@ ManagerImpl::setSwitch(const std::string& switchName) { // ACCOUNT handling bool -ManagerImpl::associateCallToAccount(CALLID callID, const AccountID& accountID) +ManagerImpl::associateCallToAccount(const CallID& callID, const AccountID& accountID) { if (getAccountFromCall(callID) == AccountNULL) { // nothing with the same ID if ( accountExists(accountID) ) { // account id exist in AccountMap @@ -1797,7 +1541,7 @@ ManagerImpl::associateCallToAccount(CALLID callID, const AccountID& accountID) } AccountID -ManagerImpl::getAccountFromCall(const CALLID callID) +ManagerImpl::getAccountFromCall(const CallID& callID) { ost::MutexLock m(_callAccountMapMutex); CallAccountMap::iterator iter = _callAccountMap.find(callID); @@ -1809,7 +1553,7 @@ ManagerImpl::getAccountFromCall(const CALLID callID) } bool -ManagerImpl::removeCallAccount(CALLID callID) +ManagerImpl::removeCallAccount(const CallID& callID) { ost::MutexLock m(_callAccountMapMutex); if ( _callAccountMap.erase(callID) ) { @@ -1818,15 +1562,19 @@ ManagerImpl::removeCallAccount(CALLID callID) return false; } -CALLID +CallID ManagerImpl::getNewCallID() { - CALLID random_id = (unsigned)rand(); + std::ostringstream random_id("s"); + random_id << (unsigned)rand(); + // when it's not found, it return "" - while (getAccountFromCall(random_id) != AccountNULL) { - random_id = rand(); + while (getAccountFromCall(random_id.str()) != AccountNULL) { + random_id.clear(); + random_id << "s"; + random_id << (unsigned)rand(); } - return random_id; + return random_id.str(); } short @@ -1837,7 +1585,7 @@ ManagerImpl::loadAccountMap() _accountMap[ACCOUNT_SIP0] = AccountCreator::createAccount(AccountCreator::SIP_ACCOUNT, ACCOUNT_SIP0); nbAccount++; - _accountMap[ACCOUNT_AIX0] = AccountCreator::createAccount(AccountCreator::AIX_ACCOUNT, ACCOUNT_AIX0); + _accountMap[ACCOUNT_IAX0] = AccountCreator::createAccount(AccountCreator::IAX_ACCOUNT, ACCOUNT_IAX0); nbAccount++; return nbAccount; @@ -1907,7 +1655,7 @@ bool ManagerImpl::testCallAccountMap() if ( removeCallAccount(1) != false ) { _debug("TEST: removeCallAccount with empty list failed\n"); } - CALLID newid = getNewCallID(); + CallID newid = getNewCallID(); if ( associateCallToAccount(newid, "acc0") == false ) { _debug("TEST: associateCallToAccount with new CallID empty list failed\n"); } @@ -1917,7 +1665,7 @@ bool ManagerImpl::testCallAccountMap() if ( getAccountFromCall( newid ) != "acc0" ) { _debug("TEST: getAccountFromCall don't return the good account id\n"); } - CALLID secondnewid = getNewCallID(); + CallID secondnewid = getNewCallID(); if ( associateCallToAccount(secondnewid, "xxxx") == true ) { _debug("TEST: associateCallToAccount with unknown account id failed\n"); } diff --git a/src/managerimpl.h b/src/managerimpl.h index 7e37bc9f56285865a4e6872d3a8c859ce17cee51..e47b2a4cca91c13f6996eb071a5faee744d84bc6 100644 --- a/src/managerimpl.h +++ b/src/managerimpl.h @@ -25,16 +25,17 @@ #include <string> #include <vector> +#include <set> #include <map> #include <cc++/thread.h> #include "stund/stun.h" -#include "call.h" #include "observer.h" #include "config/config.h" + #include "account.h" +#include "call.h" -//#include "audio/audiodevice.h" #include "audio/tonelist.h" // for Tone::TONEID declaration #include "audio/audiofile.h" #include "audio/dtmf.h" @@ -42,44 +43,40 @@ class AudioLayer; class CodecDescriptor; - class GuiFramework; - class TelephoneTone; - class VoIPLink; #ifdef USE_ZEROCONF class DNSService; #endif -#define NOTIFICATION_LEN 250 // Status -#define CONNECTED_STATUS "Connected" -#define LOGGED_IN_STATUS "Logged in" -#define RINGING_STATUS "Ringing" -#define TRYING_STATUS "Trying ..." -#define HANGUP_STATUS "Hang up" -#define ONHOLD_STATUS "On hold ..." -#define TRANSFER_STATUS "Transfer to:" -#define MUTE_ON_STATUS "Mute on" -#define ENTER_NUMBER_STATUS "Enter Phone Number:" +//#define CONNECTED_STATUS "Connected" +//#define LOGGED_IN_STATUS "Logged in" +//#define RINGING_STATUS "Ringing" +//#define TRYING_STATUS "Trying ..." +//#define HANGUP_STATUS "Hang up" +//#define ONHOLD_STATUS "On hold ..." +//#define TRANSFER_STATUS "Transfer to:" +//#define MUTE_ON_STATUS "Mute on" +//#define ENTER_NUMBER_STATUS "Enter Phone Number:" -/* - * Define a type for a list of call +/** + * Define a type for a AccountMap container */ -typedef std::vector< Call* > CallVector; - +typedef std::map<AccountID, Account*> AccountMap; + /** * Define a type for a CallID to AccountID Map inside ManagerImpl */ -typedef std::map<CALLID, AccountID> CallAccountMap; +typedef std::map<CallID, AccountID> CallAccountMap; /** - * Define a type for a AccountMap container + * Define a type for CallID vector (waiting list, incoming not answered) */ -typedef std::map<AccountID, Account*> AccountMap; - +typedef std::set<CallID> CallIDSet; + /** * To send multiple string */ @@ -91,87 +88,107 @@ public: ~ManagerImpl (void); // Init a new VoIPLink, audio codec and audio driver + /** + * Initialisation of thread (sound) and map + */ void init (void); + + /** + * Terminate all thread (sound, link) and clear map + */ void terminate (void); - // Set the graphic user interface - void setGui (GuiFramework* gui); + /** + * Set the graphic user interface : only GuiServer right now + * @param gui A GuiFramework gui implmentation + */ + void setGui (GuiFramework* gui) { _gui = gui; } // Accessor to audiodriver - // it's multi-thread and use mutex internally + // it's multi-thread and use mutex internally AudioLayer* getAudioDriver(void) const { return _audiodriverPA ;} - // Codec Descriptor + /** + * Get a descriptor map of codec available + */ CodecDescriptorMap& getCodecDescriptorMap(void) {return _codecDescriptorMap;} - /* - * Attribute a new random id for a new call - * and check if it's already attributed to existing calls. - * If not exists, returns 'id' otherwise return 0 - */ - CALLID generateNewCallId (void); - - /* - * Add a new call at the end of the CallVector with identifiant 'id' - */ - Call* pushBackNewCall (CALLID id, Call::CallType type); - void callSetInfo(CALLID id, const std::string& name, const std::string& number); - bool callCanBeAnswered(CALLID id); - bool callCanBeClosed(CALLID id); - bool callIsOnHold(CALLID id); - - /* + /** * Functions which occur with a user's action */ - int outgoingCall (const std::string& to); - int hangupCall (CALLID id); - int cancelCall (CALLID id); - int answerCall (CALLID id); - int onHoldCall (CALLID id); - int offHoldCall (CALLID id); - int transferCall (CALLID id, const std::string& to); + bool outgoingCall(const AccountID& accountId, const CallID& id, const std::string& to); + bool answerCall(const CallID& id); + bool hangupCall(const CallID& id); + bool cancelCall(const CallID& id); + bool onHoldCall(const CallID& id); + bool offHoldCall(const CallID& id); + bool transferCall(const CallID& id, const std::string& to); void mute(); void unmute(); - int refuseCall (CALLID id); + bool refuseCall(const CallID& id); + /** Save config on file */ bool saveConfig (void); - bool registerVoIPLink (void); - bool unregisterVoIPLink (void); + /** + * Initialize action (main thread) + * @param accountId Account to register + * @return true if setRegister is call without failure, else return false + */ + bool registerVoIPLink(const AccountID& accountId); + /** + * Unregister an account + * @param accountId Account to unregister + * @return true if the unregister method is send correctly + */ + bool unregisterVoIPLink(const AccountID& accountId); - bool sendTextMessage(const std::string& account, const std::string& to, const std::string& message); + bool sendTextMessage(const AccountID& accountId, const std::string& to, const std::string& message); - /** + /* * Handle choice of the DTMF-send-way * * @param id: callid of the line. * @param code: pressed key. */ - bool sendDtmf (CALLID id, char code); - bool playDtmf (char code); + bool sendDtmf(const CallID& id, char code); + bool playDtmf(char code); bool playTone (); void stopTone(); - CALLID getCurrentCallId() { ost::MutexLock m(_mutex); return _currentCallId; } - - int incomingCall (CALLID id, const std::string& name, const std::string& number); - void peerAnsweredCall (CALLID id); - int peerRingingCall (CALLID id); - int peerHungupCall (CALLID id); - void incomingMessage(const std::string& message); - - void displayTextMessage (CALLID id, const std::string& message); - void displayErrorText (CALLID id, const std::string& message); - void displayError (const std::string& error); - void displayStatus (const std::string& status); + + // From links + /** + * When receiving a new incoming call, add it to the callaccount map + * and notify user + * @param call A call pointer + * @param accountid an account id + * @return true if the call was added correctly + */ + bool incomingCall(Call* call, const AccountID& accountId); + void peerAnsweredCall(const CallID& id); + void peerRingingCall(const CallID& id); + void peerHungupCall(const CallID& id); + void incomingMessage(const AccountID& accountId, const std::string& message); + + void displayTextMessage (const CallID& id, const std::string& message); + void displayErrorText (const CallID& id, const std::string& message); + void displayError(const std::string& error); + void displayStatus(const std::string& status); void displayConfigError(const std::string& message); - void startVoiceMessageNotification (const std::string& nb_msg); - void stopVoiceMessageNotification (void); + void startVoiceMessageNotification(const AccountID& accountId, const std::string& nb_msg); + void stopVoiceMessageNotification(const AccountID& accountId); - void registrationSucceed(); - void registrationFailed(); + /** Notify the user that registration succeeded */ + void registrationSucceed(const AccountID& accountId); + /** Notify the user that registration succeeded */ + void registrationFailed(const AccountID& accountId); // configuration function requests + /** Start events thread*/ + // TODO: receive account name bool getEvents(); + + // bool getZeroconf(const std::string& sequenceId); bool attachZeroconfEvents(const std::string& sequenceId, Pattern::Observer& observer); bool detachZeroconfEvents(Pattern::Observer& observer); @@ -182,30 +199,33 @@ public: bool setConfig(const std::string& section, const std::string& name, int value); bool getConfigList(const std::string& sequenceId, const std::string& name); void selectAudioDriver(void); + /** Set Audio Driver with switchName == audiodriver */ bool setSwitch(const std::string& switchName); // configuration function for extern // throw an Conf::ConfigTreeItemException if not found + /** Get a int from the config tree */ int getConfigInt(const std::string& section, const std::string& name); + /** Get a string from the config tree */ std::string getConfigString(const std::string& section, const std::string& name); - /* + /** * Handle audio sounds heard by a caller while they wait for their * connection to a called party to be completed. */ void ringback (); - /* + /** * Handle played music when an incoming call occurs */ void ringtone (); void congestion (); - void callBusy(CALLID id); - void callFailure(CALLID id); + void callBusy(const CallID& id); + void callFailure(const CallID& id); - // return 0 if no tone (init before calling this function) + /** @return 0 if no tone (init before calling this function) */ AudioLoop* getTelephoneTone(); - // return 0 if the wav is stopped + /** @return 0 if the wav is stopped */ AudioLoop* getTelephoneFile(); /** @@ -213,20 +233,12 @@ public: * new call, not anwsered or refused */ bool incomingCallWaiting(void); - /* + /** * Notification of incoming call when you are already busy */ - void notificationIncomingCall (void); + void notificationIncomingCall(void); + - /* - * Get information about firewall - * @param stunSvrAddr: stun server - * @param port port number to open to test the connection - * @return true if the connection is successful - */ - bool getStunInfo(StunAddress4& stunSvrAddr, int port); - bool useStun (void); - /* * Inline functions to manage volume control * Read by main thread and AudioLayer thread @@ -237,20 +249,40 @@ public: unsigned short getMicVolume(void) { return _mic_volume; } void setMicVolume(unsigned short mic_vol) { _mic_volume = mic_vol; } + // Manage information about firewall /* - * Manage information about firewall + * Get information about firewall + * @param stunSvrAddr: stun server + * @param port port number to open to test the connection + * @return true if the connection is successful */ + bool getStunInfo(StunAddress4& stunSvrAddr, int port); + inline int getFirewallPort (void) { return _firewallPort; } inline void setFirewallPort (int port) { _firewallPort = port; } inline std::string getFirewallAddress (void) { return _firewallAddr; } - /* + /** + * If you are behind a NAT, you have to use STUN server, specified in + * STUN configuration(you can change this one by default) to give you an + * public IP address and assign a port number. + * Note: Set firewall port/address retreive + * @param port : on which port we want to listen to + * + * Return true if we are behind a NAT (without error) + */ + bool behindNat(int port); + + /** * Init default values for the different fields */ void initConfigFile (void); + + /** + * Tell if the setup was already loaded + */ bool hasLoadedSetup() { return _setupLoaded; } - enum REGISTRATION_STATE { UNREGISTERED, REGISTERED, @@ -259,6 +291,24 @@ public: REGISTRATION_STATE getRegistrationState() { return _registerState; } + /** Return a new random callid that is not present in the list + * @return a brand new callid + */ + CallID getNewCallID(); + + /** + * Get the current call id + * @return the call id or "" + */ + const CallID& getCurrentCallId(); + + /** + * Check if a call is the current one + * @param id the new callid + * @return if the id is the current call + */ + bool isCurrentCall(const CallID& callId); + private: /** * Create .PROGNAME directory in home user and create @@ -304,14 +354,24 @@ private: bool getCountryTones(const std::string& sequenceId); void sendCountryTone(const std::string& sequenceId, int index, const std::string& name); - /* - * Erase the Call(id) from the CallVector - * Protected by other function by _mutex lock + /** + * Tell if there is a current call processed + * @return true if there is a current call + */ + bool hasCurrentCall(); + + /** + * Switch of current call id + * @param id the new callid */ - void deleteCall (CALLID id); - Call* getCall (CALLID id); - void setCurrentCallId(CALLID id); - void removeCallFromCurrent(CALLID id); + void switchCall(const CallID& id); + + /** Current Call ID */ + CallID _currentCallId2; + + /** Protected current call access */ + ost::Mutex _currentCallMutex; + /* * Play one tone @@ -347,45 +407,41 @@ private: short _spkr_volume; short _mic_volume; short _mic_volume_before_mute; - - // // End of sound variable - // + // Multithread variable (protected by _mutex) // /** Mutex to protect access to code section */ ost::Mutex _mutex; - /* Vector of calls */ - CallVector _callVector; - // Current callid : protected implicitely by function using _mutex - CALLID _currentCallId; - // functions that set mutex: - // terminate, pushBackNewCall, generateNewCallId, outgoingCall (after gen/push) - // hangupCall, cancelCall, answerCall, onHoldCall, offHoldCall, transferCall, refuseCall, - // callSetInfo, callCanBeClosed, callCanBeAnswered, callIsOnHold, incomingCall, - // peerAnsweredCall, peerRingingCall, peerHunguCall, callBusy, callFailure - // getCallStatus, getCurrentCallId - // functions that are called by those functions - // getCall, deleteCall, stopTone, switchCall, decWaitingCall, setCurrentCallId, getAudioDriver, ringtone, incWaitingCall - - // warning, incomingCallWaiting | incWaitingCall | decWaitingCall are prtected by _incomingCallMutex - // // Multithread variable (non protected) // GuiFramework* _gui; + /** Waiting Call Vectors */ + CallIDSet _waitingCall; + /** Protect waiting call list, access by many voip/audio threads */ + ost::Mutex _waitingCallMutex; + /** Number of waiting call, synchronize with waitingcall callidvector */ + unsigned int _nbIncomingWaitingCall; /** - * Multithreaded - * Incomings Call: + * Add incoming callid to the waiting list + * @param id CallID to add */ - ost::Mutex _incomingCallMutex; - unsigned int _nbIncomingWaitingCall; - void incWaitingCall(void); - void decWaitingCall(void); - + void addWaitingCall(const CallID& id); + /** + * Remove incoming callid to the waiting list + * @param id CallID to remove + */ + void removeWaitingCall(const CallID& id); + /** + * Tell if a call is waiting and should be remove + * @param id CallID to test + * @return true if the call is waiting + */ + bool isWaitingCall(const CallID& id); /** * Path of the ConfigFile @@ -401,13 +457,10 @@ private: // return false if exosip or the network checking failed bool initRegisterVoIPLink(); // true if we tried to register Once - bool _hasTriedToRegister; + bool _hasTriedToRegister; // Register state REGISTRATION_STATE _registerState; - - void switchCall(CALLID id); - // tell if we have zeroconf is enabled int _hasZeroconf; @@ -417,8 +470,6 @@ private: DNSService *_DNSService; #endif -// CALLID - /** Map to associate a CallID to the good account */ CallAccountMap _callAccountMap; /** Mutex to lock the call account map (main thread + voiplink thread) */ @@ -430,26 +481,21 @@ private: * @param accountID the known accountID present in accountMap * @return true if the new association is create */ - bool associateCallToAccount(CALLID callID, const AccountID& accountID); + bool associateCallToAccount(const CallID& callID, const AccountID& accountID); /** Return the AccountID from a CallID * Protected by mutex * @param callID the CallID in the list * @return the accountID associated or "" if the callID is not found */ - AccountID getAccountFromCall(const CALLID callID); + AccountID getAccountFromCall(const CallID& callID); /** Remove a CallID/AccountID association * Protected by mutex * @param callID the CallID to remove * @return true if association is removed */ - bool removeCallAccount(CALLID callID); - - /** Return a new random callid that is not present in the list - * @return a brand new callid - */ - CALLID getNewCallID(); + bool removeCallAccount(const CallID& callID); /** Contains a list of account (sip, aix, etc) and their respective voiplink/calls */ AccountMap _accountMap; diff --git a/src/sipaccount.cpp b/src/sipaccount.cpp index 153d2d172fc9556edff9e1ac16d0666eefb05618..54d9d5cfad2a38e32703ad8e88526500a8f44126 100644 --- a/src/sipaccount.cpp +++ b/src/sipaccount.cpp @@ -18,14 +18,14 @@ */ #include "sipaccount.h" #include "sipvoiplink.h" +#include "manager.h" #define SIP_FULL_NAME "SIP.fullName" #define SIP_USER_PART "SIP.userPart" -#define SIP_AUTH_USER_NAME "SIP.username" +#define SIP_AUTH_NAME "SIP.username" #define SIP_PASSWORD "SIP.password" #define SIP_HOST_PART "SIP.hostPart" #define SIP_PROXY "SIP.proxy" -#define SIP_AUTO_REGISTER "SIP.autoregister" #define SIP_STUN_SERVER "STUN.STUNserver" #define SIP_USE_STUN "STUN.useStun" @@ -46,7 +46,8 @@ bool SIPAccount::createVoIPLink() { if (!_link) { - _link = new SipVoIPLink(); + //_link = new SipVoIPLink(); + _link = new SIPVoIPLink(_accountID); } return (_link != 0 ? true : false); } @@ -55,7 +56,14 @@ bool SIPAccount::registerAccount() { if (_link && !_registered) { - _registered = (_link->setRegister() >= 0) ? true : false; + SIPVoIPLink* tmplink = dynamic_cast<SIPVoIPLink*> (_link); + if (tmplink) { + tmplink->setProxy(Manager::instance().getConfigString(_accountID,SIP_PROXY)); + tmplink->setUserPart(Manager::instance().getConfigString(_accountID,SIP_USER_PART)); + tmplink->setAuthName(Manager::instance().getConfigString(_accountID,SIP_AUTH_NAME)); + tmplink->setPassword(Manager::instance().getConfigString(_accountID,SIP_PASSWORD)); + } + _registered = _link->setRegister(); } return _registered; } @@ -64,7 +72,7 @@ bool SIPAccount::unregisterAccount() { if (_link && _registered) { - _registered = (_link->setUnregister() == 0) ? false : true; + _registered = _link->setUnregister(); } return !_registered; } @@ -73,6 +81,13 @@ bool SIPAccount::init() { if (_link && !_enabled) { + _link->setFullName(Manager::instance().getConfigString(_accountID,SIP_FULL_NAME)); + _link->setHostName(Manager::instance().getConfigString(_accountID,SIP_HOST_PART)); + int useStun = Manager::instance().getConfigInt(_accountID,SIP_USE_STUN); + SIPVoIPLink* tmplink = dynamic_cast<SIPVoIPLink*> (_link); + if (tmplink) { + tmplink->setUseStun( useStun!=0 ? true : false); + } _link->init(); _enabled = true; return true; @@ -102,10 +117,18 @@ SIPAccount::initConfig(Conf::ConfigTree& config) config.addConfigTreeItem(section, Conf::ConfigTreeItem(CONFIG_ACCOUNT_ENABLE,"1", type_int)); config.addConfigTreeItem(section, Conf::ConfigTreeItem(SIP_FULL_NAME, "", type_str)); config.addConfigTreeItem(section, Conf::ConfigTreeItem(SIP_USER_PART, "", type_str)); - config.addConfigTreeItem(section, Conf::ConfigTreeItem(SIP_AUTH_USER_NAME, "", type_str)); + config.addConfigTreeItem(section, Conf::ConfigTreeItem(SIP_HOST_PART, "", type_str)); + config.addConfigTreeItem(section, Conf::ConfigTreeItem(SIP_AUTH_NAME, "", type_str)); + config.addConfigTreeItem(section, Conf::ConfigTreeItem(SIP_PASSWORD, "", type_str)); config.addConfigTreeItem(section, Conf::ConfigTreeItem(SIP_PROXY, "", type_str)); - config.addConfigTreeItem(section, Conf::ConfigTreeItem(SIP_AUTO_REGISTER, "1", type_int)); + config.addConfigTreeItem(section, Conf::ConfigTreeItem(CONFIG_ACCOUNT_AUTO_REGISTER, "1", type_int)); config.addConfigTreeItem(section, Conf::ConfigTreeItem(SIP_STUN_SERVER, "stun.fwdnet.net:3478", type_str)); config.addConfigTreeItem(section, Conf::ConfigTreeItem(SIP_USE_STUN, "0", type_int)); } +void +SIPAccount::loadConfig() +{ + _shouldInitOnStart = Manager::instance().getConfigInt(_accountID, CONFIG_ACCOUNT_ENABLE) ? true : false; + _shouldRegisterOnStart = Manager::instance().getConfigInt(_accountID, CONFIG_ACCOUNT_AUTO_REGISTER) ? true : false; +} diff --git a/src/sipaccount.h b/src/sipaccount.h index 157c0ad51863f5defe0bcca5aad72baba527b493..c5da7b18fe833a28525af96b300d5dfcac390e8c 100644 --- a/src/sipaccount.h +++ b/src/sipaccount.h @@ -30,10 +30,11 @@ class SIPAccount : public Account public: SIPAccount(const AccountID& accountID); - ~SIPAccount(); + virtual ~SIPAccount(); /* virtual Account function implementation */ void initConfig(Conf::ConfigTree& config); + void loadConfig(); bool registerAccount(); bool unregisterAccount(); bool init(); diff --git a/src/sipcall.cpp b/src/sipcall.cpp index 36997919e07add582bba505b6ffb5b81f4be1bbe..f9e56662987407c7579b88668bbf3d9d361da449 100644 --- a/src/sipcall.cpp +++ b/src/sipcall.cpp @@ -1,270 +1,107 @@ -/** - * Copyright (C) 2004-2005 Savoir-Faire Linux inc. +/* + * Copyright (C) 2004-2006 Savoir-Faire Linux inc. * Author: Yan Morin <yan.morin@savoirfairelinux.com> - * Author: Laurielle Lea <laurielle.lea@savoirfairelinux.com> - * - * Portions Copyright (C) 2002,2003 Aymeric Moizard <jack@atosc.org> + * Author : Laurielle Lea <laurielle.lea@savoirfairelinux.com> * - * This 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 2, - * or (at your option) any later version. + * 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 2 of the License, or + * (at your option) any later version. * - * This 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. + * 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 dpkg; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * 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 <osipparser2/sdp_message.h> -#include <string.h> // strcpy - -// For AF_INET -#include <sys/socket.h> -#include <sstream> - -#include "global.h" -#include "audio/audiocodec.h" -#include "audio/codecDescriptor.h" #include "sipcall.h" +#include "global.h" // for _debug +#include <sstream> // for media buffer -SipCall::SipCall (CALLID id, CodecDescriptorMap& codecMap) : _localIp("127.0.0.1"), _codecMap(codecMap) -{ - _id = id; // Same id of Call object - _cid = 0; // call id, from the sipvoiplink - _did = 0; // dialog id - _tid = 0; // transaction id - - _standby = false; - _status_code = 0; - - alloc(); // char* allocation - _audiocodec = 0; - - _local_audio_port = 0; - _remote_sdp_audio_port = 0; - _local_sendrecv = 0; /* _SENDRECV, _SENDONLY, _RECVONLY */ - _remote_sendrecv = 0; - - _reinvite = false; -} - - -SipCall::~SipCall (void) -{ - dealloc(); - //delete _audiocodec; don't delete it, the Manager will do it... - _audiocodec = 0; -} - -void -SipCall::setLocalAudioPort (int newport) -{ - _local_audio_port = newport; -} - -int -SipCall::getLocalAudioPort (void) -{ - return _local_audio_port; -} - -void -SipCall::setId (CALLID id) -{ - _id = id; -} - -CALLID -SipCall::getId (void) -{ - return _id; -} - -void -SipCall::setDid (int did) -{ - _did = did; -} - -int -SipCall::getDid (void) -{ - return _did; -} - -void -SipCall::setCid (int cid) -{ - _cid = cid; -} - -int -SipCall::getCid (void) -{ - return _cid; -} +#define _SENDRECV 0 +#define _SENDONLY 1 +#define _RECVONLY 2 -void -SipCall::setTid (int tid) +SIPCall::SIPCall(const CallID& id, Call::CallType type) : Call(id, type), + _localIPAddress(""), _remoteIPAddress("") { - _tid = tid; + _cid = 0; + _did = 0; + _tid = 0; + _audioCodec = 0; + _localAudioPort = 0; + _localExternalAudioPort = 0; + _remoteAudioPort = 0; } -int -SipCall::getTid (void) +SIPCall::~SIPCall() { - return _tid; } -int -SipCall::getRemoteSdpAudioPort (void) +CodecDescriptorMap& +SIPCall::getCodecMap() { - return _remote_sdp_audio_port; + return _codecMap; } -char* -SipCall::getRemoteSdpAudioIp (void) +/** + * Answer incoming call correclty before telling the user + * @param event eXosip Event + */ +bool +SIPCall::SIPCallInvite(eXosip_event_t *event) { - return _remote_sdp_audio_ip; -} - -// newIncomingCall is called when the IP-Phone user receives a new call. -int -SipCall::newIncomingCall (eXosip_event_t *event) { - - _cid = event->cid; - _did = event->did; - _tid = event->tid; - if (_did < 1 && _cid < 1) { - return -1; /* not enough information for this event?? */ + _debug("SIP Failure: Invalid cid and did\n"); + return false; } - osip_strncpy (_textinfo, event->textinfo, 255); - if (event->response != NULL) { - _status_code = event->response->status_code; - snprintf (_reason_phrase, 49, "%s", event->response->reason_phrase); - _debug(" Status: code:%1$d reason:%2$s\n", _status_code, _reason_phrase); + if (event->request == NULL) { + _debug("SIP Failure: No request into the event\n"); + return false; } - strcpy(_remote_uri, ""); - _name = ""; - _number = ""; - if (event->request != NULL) { - char *tmp = NULL; - - osip_from_to_str(event->request->from, &tmp); - if (tmp != NULL) { - snprintf (_remote_uri, 255, "%s", tmp); - osip_free (tmp); - - // Get the name/number - osip_from_t *from; - osip_from_init(&from); - osip_from_parse(from, _remote_uri); - char *name = osip_from_get_displayname(from); - if ( name != NULL ) { - _name = name; - } - osip_uri_t* url = osip_from_get_url(from); - if ( url != NULL && url->username != NULL) { - _number = url->username; - } - osip_from_free(from); - } - } - _debug(" Name: %s\n", _name.c_str()); - _debug(" Number: %s\n", _number.c_str()); - _debug(" Remote URI: %s\n", _remote_uri); + setCid(event->cid); + setDid(event->did); + setTid(event->tid); - /* negotiate payloads */ - sdp_message_t *remote_sdp = NULL; - if (event->request != NULL) { - eXosip_lock(); - remote_sdp = eXosip_get_sdp_info (event->request); - eXosip_unlock(); + setPeerInfoFromRequest(event); + + sdp_message_t* remote_sdp = getRemoteSDPFromRequest(event); + if (remote_sdp == 0) { + return false; } - if (remote_sdp == NULL) { - _debug("< Sending 400 Bad Request (no SDP)\n"); - eXosip_lock(); - eXosip_call_send_answer (_tid, 400, NULL); - eXosip_unlock(); - return -1; - } - /* TODO: else build an offer */ - // Remote Media IP - eXosip_lock(); - sdp_connection_t *conn = eXosip_get_audio_connection (remote_sdp); - eXosip_unlock(); - if (conn != NULL && conn->c_addr != NULL) { - snprintf (_remote_sdp_audio_ip, 49, "%s", conn->c_addr); - _debug(" Remote Audio IP: %s\n", _remote_sdp_audio_ip); + sdp_media_t* remote_med = getRemoteMedia(event->tid, remote_sdp); + if (remote_med == 0) { + sdp_message_free (remote_sdp); + return false; } - // Remote Media Port - eXosip_lock(); - sdp_media_t *remote_med = eXosip_get_audio_media (remote_sdp); - eXosip_unlock(); - - if (remote_med == NULL || remote_med->m_port == NULL) { - // no audio media proposed - _debug("< Sending 415 Unsupported media type\n"); - eXosip_lock(); - eXosip_call_send_answer (_tid, 415, NULL); - eXosip_unlock(); + if (!setRemoteAudioFromSDP(remote_med, remote_sdp)) { + _debug("SIP Failure: unable to set IP address and port from SDP\n"); sdp_message_free (remote_sdp); - return -1; + return false; } - _remote_sdp_audio_port = atoi(remote_med->m_port); - _debug(" Remote Audio Port: %d\n", _remote_sdp_audio_port); - // Remote Payload - char *tmp = NULL; - if (_remote_sdp_audio_port > 0 && _remote_sdp_audio_ip[0] != '\0') { - int pos = 0; - while (!osip_list_eol (remote_med->m_payloads, pos)) { - tmp = (char *) osip_list_get (remote_med->m_payloads, pos); - if (tmp != NULL ) { - int payload = atoi(tmp); - // stop if we find a correct codec - if (0 != _codecMap.getCodec((CodecType)payload)){ - break; - } - } - tmp = NULL; - pos++; - } - } - setAudioCodec(0); - if (tmp != NULL) { - int payload = atoi (tmp); - _debug(" Payload: %d\n", payload); - setAudioCodec(_codecMap.getCodec((CodecType)payload)); // codec builder for the mic - } - if (getAudioCodec() == 0) { - _debug("< Sending 415 Unsupported media type\n"); - eXosip_lock(); - eXosip_call_send_answer (_tid, 415, NULL); - eXosip_unlock(); + if (!setAudioCodecFromSDP(remote_med, event->tid)) { sdp_message_free (remote_sdp); - return -1; + return false; } osip_message_t *answer = 0; eXosip_lock(); _debug("< Building Answer 183\n"); - if (0 == eXosip_call_build_answer (_tid, 183, &answer)) { + if (0 == eXosip_call_build_answer (event->tid, 183, &answer)) { if ( 0 != sdp_complete_message(remote_sdp, answer)) { osip_message_free(answer); // Send 415 Unsupported media type - _debug("< Sending Answer 415\n"); - eXosip_call_send_answer (_tid, 415, NULL); + _debug("< Sending Answer 415 : unsupported media type\n"); + eXosip_call_send_answer (event->tid, 415, NULL); } else { sdp_message_t *local_sdp = eXosip_get_sdp_info(answer); @@ -274,8 +111,8 @@ SipCall::newIncomingCall (eXosip_event_t *event) { } if (local_sdp != NULL && local_med != NULL) { /* search if stream is sendonly or recvonly */ - _remote_sendrecv = sdp_analyse_attribute (remote_sdp, remote_med); - _local_sendrecv = sdp_analyse_attribute (local_sdp, local_med); + int _remote_sendrecv = sdp_analyse_attribute (remote_sdp, remote_med); + int _local_sendrecv = sdp_analyse_attribute (local_sdp, local_med); _debug(" Remote SendRecv: %d\n", _remote_sendrecv); _debug(" Local SendRecv: %d\n", _local_sendrecv); if (_local_sendrecv == _SENDRECV) { @@ -286,149 +123,73 @@ SipCall::newIncomingCall (eXosip_event_t *event) { sdp_message_free (local_sdp); } _debug("< Sending answer 183\n"); - if (0 != eXosip_call_send_answer (_tid, 183, answer)) { + if (0 != eXosip_call_send_answer (event->tid, 183, answer)) { _debug("SipCall::newIncomingCall: cannot send 183 progress?\n"); } } } eXosip_unlock (); - sdp_message_free (remote_sdp); - return 0; + sdp_message_free (remote_sdp); + return true; } -// newReinviteCall is called when the IP-Phone user receives a change in the call -// it's almost an newIncomingCall but we send a 200 OK -// See: 3.7. Session with re-INVITE (IP Address Change) -int -SipCall::newReinviteCall (eXosip_event_t *event) { - - _cid = event->cid; - _did = event->did; - _tid = event->tid; - +/** + * newReinviteCall is called when the IP-Phone user receives a change in the call + * it's almost an newIncomingCall but we send a 200 OK + * See: 3.7. Session with re-INVITE (IP Address Change) + * @param event eXosip Event + * @return true if ok + */ +bool +SIPCall::SIPCallReinvite(eXosip_event_t *event) +{ if (_did < 1 && _cid < 1) { - return -1; /* not enough information for this event?? */ + _debug("SIP Failure: Invalid cid and did\n"); + return false; } - osip_strncpy (_textinfo, event->textinfo, 255); - if (event->response != NULL) { - _status_code = event->response->status_code; - snprintf (_reason_phrase, 49, "%s", event->response->reason_phrase); - _debug(" Status: %d %s\n", _status_code, _reason_phrase); + if (event->request == NULL) { + _debug("SIP Failure: No request into the event\n"); + return false; } - strcpy(_remote_uri, ""); - _name = ""; - _number = ""; - if (event->request != NULL) { - char *tmp = NULL; - - osip_from_to_str(event->request->from, &tmp); - if (tmp != NULL) { - snprintf (_remote_uri, 255, "%s", tmp); - osip_free (tmp); - - // Get the name/number - osip_from_t *from; - osip_from_init(&from); - osip_from_parse(from, _remote_uri); - char *name = osip_from_get_displayname(from); - if ( name != NULL ) { - _name = name; - } - osip_uri_t* url = osip_from_get_url(from); - if ( url != NULL && url->username != NULL ) { - _number = url->username; - } - osip_from_free(from); - } - } - _debug(" Name: %s\n", _name.c_str()); - _debug(" Number: %s\n", _number.c_str()); - _debug(" Remote URI: %s\n", _remote_uri); + setCid(event->cid); + setDid(event->did); + setTid(event->tid); - /* negotiate payloads */ - sdp_message_t *remote_sdp = NULL; - if (event->request != NULL) { - eXosip_lock(); - remote_sdp = eXosip_get_sdp_info (event->request); - eXosip_unlock(); - } - if (remote_sdp == NULL) { - _debug("< Sending 400 Bad Request (no sdp)\n"); - // Send 400 BAD REQUEST - eXosip_lock(); - eXosip_call_send_answer (_tid, 400, NULL); - eXosip_unlock(); - return 0; - } - /* TODO: else build an offer */ + setPeerInfoFromRequest(event); - // Remote Media IP - eXosip_lock(); - sdp_connection_t *conn = eXosip_get_audio_connection (remote_sdp); - eXosip_unlock(); - if (conn != NULL && conn->c_addr != NULL) { - snprintf (_remote_sdp_audio_ip, 49, "%s", conn->c_addr); - _debug(" Remote Audio IP: %s\n", _remote_sdp_audio_ip); + sdp_message_t* remote_sdp = getRemoteSDPFromRequest(event); + if (remote_sdp == 0) { + return false; } - // Remote Media Port - eXosip_lock(); - sdp_media_t *remote_med = eXosip_get_audio_media (remote_sdp); - eXosip_unlock(); - - if (remote_med == NULL || remote_med->m_port == NULL) { - // no audio media proposed - _debug("< Sending 415 Unsupported media type\n"); - eXosip_lock(); - eXosip_call_send_answer (_tid, 415, NULL); - eXosip_unlock(); + sdp_media_t* remote_med = getRemoteMedia(event->tid, remote_sdp); + if (remote_med == 0) { sdp_message_free (remote_sdp); - return 0; + return false; } - _remote_sdp_audio_port = atoi(remote_med->m_port); - _debug(" Remote Audio Port: %d\n", _remote_sdp_audio_port); - // Remote Payload - char *tmp = NULL; - if (_remote_sdp_audio_port > 0 && _remote_sdp_audio_ip[0] != '\0') { - int pos = 0; - while (!osip_list_eol (remote_med->m_payloads, pos)) { - tmp = (char *) osip_list_get (remote_med->m_payloads, pos); - if (tmp != NULL) { - // we could check if the payload is active here... - break; - } - tmp = NULL; - pos++; - } + if (!setRemoteAudioFromSDP(remote_med, remote_sdp)) { + _debug("SIP Failure: unable to set IP address and port from SDP\n"); + sdp_message_free (remote_sdp); + return false; } - setAudioCodec(0); - if (tmp != NULL) { - int payload = atoi (tmp); - _debug(" Payload: %d\n", payload); - setAudioCodec(_codecMap.getCodec((CodecType)payload)); // codec builder for the mic - } - if (getAudioCodec() == 0) { - _debug("< Sending 415 Unsupported media type\n"); - eXosip_lock(); - eXosip_call_send_answer (_tid, 415, NULL); - eXosip_unlock(); + if (!setAudioCodecFromSDP(remote_med, event->tid)) { sdp_message_free (remote_sdp); - return 0; + return false; } osip_message_t *answer = 0; eXosip_lock(); _debug("< Building Answer 200\n"); - if (0 == eXosip_call_build_answer (_tid, 200, &answer)) { + if (0 == eXosip_call_build_answer (event->tid, 200, &answer)) { if ( 0 != sdp_complete_message(remote_sdp, answer)) { osip_message_free(answer); // Send 415 Unsupported media type - eXosip_call_send_answer (_tid, 415, NULL); + eXosip_call_send_answer (event->tid, 415, NULL); _debug("< Sending Answer 415\n"); } else { @@ -439,8 +200,8 @@ SipCall::newReinviteCall (eXosip_event_t *event) { } if (local_sdp != NULL && local_med != NULL) { /* search if stream is sendonly or recvonly */ - _remote_sendrecv = sdp_analyse_attribute (remote_sdp, remote_med); - _local_sendrecv = sdp_analyse_attribute (local_sdp, local_med); + int _remote_sendrecv = sdp_analyse_attribute (remote_sdp, remote_med); + int _local_sendrecv = sdp_analyse_attribute (local_sdp, local_med); _debug(" Remote SendRecv: %d\n", _remote_sendrecv); _debug(" Local SendRecv: %d\n", _local_sendrecv); if (_local_sendrecv == _SENDRECV) { @@ -451,88 +212,44 @@ SipCall::newReinviteCall (eXosip_event_t *event) { sdp_message_free (local_sdp); } _debug("< Sending answer 200\n"); - if (0 != eXosip_call_send_answer (_tid, 200, answer)) { + if (0 != eXosip_call_send_answer (event->tid, 200, answer)) { _debug("SipCall::newIncomingCall: cannot send 200 OK?\n"); } } } eXosip_unlock (); sdp_message_free (remote_sdp); - _reinvite = true; - return 0; + return true; } -int -SipCall::ringingCall (eXosip_event_t *event) { - - this->_cid = event->cid; - this->_did = event->did; - this->_tid = event->tid; - - if (this->_did < 1 && this->_cid < 1) { - return -1; - } - - osip_strncpy (_textinfo, event->textinfo, 255); - - if (event->response != NULL) { - _status_code = event->response->status_code; - snprintf (_reason_phrase, 49, "%s", event->response->reason_phrase); - } - - if (event->request != NULL) { - char *tmp = NULL; - - osip_from_to_str (event->request->from, &tmp); - if (tmp != NULL) { - snprintf (_remote_uri, 255, "%s", tmp); - osip_free (tmp); - } - } - return 0; -} - -int -SipCall::receivedAck (eXosip_event_t *event) + /** + * Peer answered to a call (on hold or not) + * @param event eXosip Event + * @return true if ok + */ +bool +SIPCall::SIPCallAnswered(eXosip_event_t *event) { - _cid = event->cid; - _did = event->did; - return 0; -} - - - -int -SipCall::answeredCall(eXosip_event_t *event) { - _cid = event->cid; - _did = event->did; - - if (_did < 1 && _cid < 1) { - return -1; /* not enough information for this event?? */ + if (_did < 1 && _cid < 1) { + _debug("SIP Failure: Invalid cid and did\n"); + return false; } - osip_strncpy(this->_textinfo, event->textinfo, 255); - if (event->response != NULL) { - _status_code = event->response->status_code; - snprintf (_reason_phrase, 49, "%s", event->response->reason_phrase); + if (event->request == NULL) { + _debug("SIP Failure: No request into the event\n"); + return false; + } - char *tmp = NULL; + setCid(event->cid); + setDid(event->did); - osip_from_to_str (event->response->from, &tmp); - if (tmp != NULL) { - snprintf (_remote_uri, 255, "%s", tmp); - osip_free (tmp); - } - } - _debug(" Status: %d %s\n", _status_code, _reason_phrase); - _debug(" From URI: %s\n", _remote_uri); + //setPeerInfoFromResponse() eXosip_lock (); { osip_message_t *ack = NULL; int i; - - i = eXosip_call_build_ack (_did, &ack); + i = eXosip_call_build_ack (event->did, &ack); if (i != 0) { _debug("SipCall::answeredCall: Cannot build ACK for call!\n"); } else { @@ -554,114 +271,120 @@ SipCall::answeredCall(eXosip_event_t *event) { sdp_message_free (remote_sdp); _debug("< Send ACK\n"); - eXosip_call_send_ack (_did, ack); + eXosip_call_send_ack (event->did, ack); } } eXosip_unlock (); - - return 0; + return true; } - -void -SipCall::answeredCall_without_hold (eXosip_event_t *event) + /** + * We retreive final SDP info if they changed + * @param event eXosip Event + * @return true if ok (change / no change) or false on error + */ +bool +SIPCall::SIPCallAnsweredWithoutHold(eXosip_event_t *event) { - if (event->response == NULL ) { return; } - - // TODO: understand this code.. - if (_cid!=0) { - eXosip_lock(); - sdp_message_t *sdp = eXosip_get_sdp_info (event->response); - eXosip_unlock(); - if (sdp != NULL) { - /* audio is started and session has just been modified */ - sdp_message_free (sdp); - } + if (event->response == NULL || event->request == NULL) { return false; } + + eXosip_lock(); + sdp_message_t *remote_sdp = eXosip_get_sdp_info (event->response); + eXosip_unlock(); + if (remote_sdp == NULL) { + _debug("SIP Failure: no remote sdp\n"); + sdp_message_free(remote_sdp); + return false; } - if (event->request != NULL) { /* audio is started */ - - eXosip_lock(); - sdp_message_t *local_sdp = eXosip_get_sdp_info (event->request); - sdp_message_t *remote_sdp = eXosip_get_sdp_info (event->response); - eXosip_unlock(); + sdp_media_t *remote_med = getRemoteMedia(event->tid, remote_sdp); + if (remote_med==NULL) { + sdp_message_free(remote_sdp); + return false; + } + if ( ! setRemoteAudioFromSDP(remote_med, remote_sdp) ) { + sdp_message_free(remote_sdp); + return false; + } - sdp_media_t *remote_med = NULL; - char *tmp = NULL; - if (remote_sdp == NULL) { - _debug("SipCall::answeredCall_without_hold: No remote SDP body found for call\n"); - /* TODO: remote_sdp = retreive from ack above */ - } else { - eXosip_lock(); - sdp_connection_t *conn = eXosip_get_audio_connection (remote_sdp); - if (conn != NULL && conn->c_addr != NULL) { - snprintf (_remote_sdp_audio_ip, 49, "%s", conn->c_addr); - } + char *tmp = (char *) osip_list_get (remote_med->m_payloads, 0); - remote_med = eXosip_get_audio_media (remote_sdp); - if (remote_med != NULL && remote_med->m_port != NULL) { - _remote_sdp_audio_port = atoi (remote_med->m_port); - } - eXosip_unlock(); - _debug(" Remote Audio: %s:%d\n", _remote_sdp_audio_ip, _remote_sdp_audio_port); - - if (_remote_sdp_audio_port > 0 && _remote_sdp_audio_ip[0] != '\0' && - remote_med != NULL) { - tmp = (char *) osip_list_get (remote_med->m_payloads, 0); - } + setAudioCodec(0); + if (tmp != NULL) { + int payload = atoi (tmp); + _debug(" Remote Payload: %d\n", payload); + setAudioCodec(_codecMap.getCodec((CodecType)payload)); // codec builder for the mic + } - setAudioCodec(0); - if (tmp != NULL) { - int payload = atoi (tmp); - _debug(" Remote Payload: %d\n", payload); - setAudioCodec(_codecMap.getCodec((CodecType)payload)); // codec builder for the mic - } +/* + // search if stream is sendonly or recvonly + _remote_sendrecv = sdp_analyse_attribute (remote_sdp, remote_med); + _local_sendrecv = sdp_analyse_attribute (local_sdp, local_med); + if (_local_sendrecv == _SENDRECV) { + if (_remote_sendrecv == _SENDONLY) + _local_sendrecv = _RECVONLY; + else if (_remote_sendrecv == _RECVONLY) + _local_sendrecv = _SENDONLY; } + _debug(" Remote Sendrecv: %d\n", _remote_sendrecv); + _debug(" Local Sendrecv: %d\n", _local_sendrecv); +*/ + sdp_message_free (remote_sdp); + return true; +} - if (local_sdp == NULL) { - _debug("SipCall::answeredCall_without_hold: SDP body was probably in the ACK (TODO)\n"); - } +const std::string& +SIPCall::getLocalIp() +{ + ost::MutexLock m(_callMutex); + return _localIPAddress; +} - if (remote_sdp != NULL && local_sdp != NULL) { - int audio_port = 0; - eXosip_lock(); - sdp_media_t *local_med = eXosip_get_audio_media (local_sdp); - eXosip_unlock(); - if (local_med != NULL && local_med->m_port != NULL) { - audio_port = atoi (local_med->m_port); - } - _debug(" Local Audio port: %d\n", audio_port); +unsigned int +SIPCall::getLocalAudioPort() +{ + ost::MutexLock m(_callMutex); + return _localAudioPort; +} - if (tmp != NULL && audio_port > 0 - && _remote_sdp_audio_port > 0 - && _remote_sdp_audio_ip[0] != '\0') { +unsigned int +SIPCall::getRemoteAudioPort() +{ + ost::MutexLock m(_callMutex); + return _remoteAudioPort; +} - /* search if stream is sendonly or recvonly */ - _remote_sendrecv = sdp_analyse_attribute (remote_sdp, remote_med); - _local_sendrecv = sdp_analyse_attribute (local_sdp, local_med); - if (_local_sendrecv == _SENDRECV) { - if (_remote_sendrecv == _SENDONLY) - _local_sendrecv = _RECVONLY; - else if (_remote_sendrecv == _RECVONLY) - _local_sendrecv = _SENDONLY; - } - } - _debug(" Remote Sendrecv: %d\n", _remote_sendrecv); - _debug(" Local Sendrecv: %d\n", _local_sendrecv); - } - sdp_message_free (local_sdp); - sdp_message_free (remote_sdp); - } +const std::string& +SIPCall::getRemoteIp() +{ + ost::MutexLock m(_callMutex); + return _remoteIPAddress; } -int -SipCall::sdp_complete_message(sdp_message_t * remote_sdp, - osip_message_t * msg) +AudioCodec* +SIPCall::getAudioCodec() { - char *tmp = NULL; - char buf[4096]; + ost::MutexLock m(_callMutex); + return _audioCodec; +} - char localip[128]; +void +SIPCall::setAudioStart(bool start) +{ + ost::MutexLock m(_callMutex); + _audioStarted = start; +} +bool +SIPCall::isAudioStarted() +{ + ost::MutexLock m(_callMutex); + return _audioStarted; +} + + //TODO: humm? +int +SIPCall::sdp_complete_message(sdp_message_t * remote_sdp, osip_message_t * msg) +{ // Format port to a char* if (remote_sdp == NULL) { _debug("SipCall::sdp_complete_message: No remote SDP body found for call\n"); @@ -672,13 +395,11 @@ SipCall::sdp_complete_message(sdp_message_t * remote_sdp, return -1; } - // this exosip is locked and is protected by other function - eXosip_guess_localip(AF_INET, localip, 128); - std::ostringstream media; // for each medias int iMedia = 0; + char *tmp = NULL; while (!osip_list_eol(remote_sdp->m_medias, iMedia)) { sdp_media_t *remote_med = (sdp_media_t *)osip_list_get(remote_sdp->m_medias, iMedia); if (remote_med == 0) { continue; } @@ -712,19 +433,20 @@ SipCall::sdp_complete_message(sdp_message_t * remote_sdp, media << "m=" << remote_med->m_media << " 0 << " << remote_med->m_proto << " \r\n"; } else { // we add the media line + a=rtpmap list - media << "m=" << remote_med->m_media << " " << _local_audio_port << " RTP/AVP " << listCodec.str() << "\r\n"; + media << "m=" << remote_med->m_media << " " << getLocalExternAudioPort() << " RTP/AVP " << listCodec.str() << "\r\n"; media << listRtpMap.str(); } } iMedia++; } + char buf[4096]; snprintf (buf, 4096, "v=0\r\n" "o=user 0 0 IN IP4 %s\r\n" "s=session\r\n" "c=IN IP4 %s\r\n" "t=0 0\r\n" - "%s\n", localip, localip, media.str().c_str()); + "%s\n", getLocalIp().c_str(), getLocalIp().c_str(), media.str().c_str()); osip_message_set_body (msg, buf, strlen (buf)); osip_message_set_content_type (msg, "application/sdp"); @@ -732,78 +454,200 @@ SipCall::sdp_complete_message(sdp_message_t * remote_sdp, return 0; } -int -SipCall::sdp_analyse_attribute (sdp_message_t * sdp, sdp_media_t * med) + + // TODO: hum??? +int +SIPCall::sdp_analyse_attribute (sdp_message_t * sdp, sdp_media_t * med) { - int pos; - int pos_media; - - /* test media attributes */ - pos = 0; - while (!osip_list_eol (med->a_attributes, pos)) { - sdp_attribute_t *at; - - at = (sdp_attribute_t *) osip_list_get (med->a_attributes, pos); - if (at->a_att_field != NULL && - 0 == strcmp (at->a_att_field, "sendonly")) { - return _SENDONLY; - } else if (at->a_att_field != NULL && - 0 == strcmp (at->a_att_field, "recvonly")) { - return _RECVONLY; - } else if (at->a_att_field != NULL && - 0 == strcmp (at->a_att_field, "sendrecv")) { - return _SENDRECV; - } - pos++; - } + int pos; + int pos_media; + + /* test media attributes */ + pos = 0; + while (!osip_list_eol (med->a_attributes, pos)) { + sdp_attribute_t *at; + + at = (sdp_attribute_t *) osip_list_get (med->a_attributes, pos); + if (at->a_att_field != NULL && + 0 == strcmp (at->a_att_field, "sendonly")) { + return _SENDONLY; + } else if (at->a_att_field != NULL && + 0 == strcmp (at->a_att_field, "recvonly")) { + return _RECVONLY; + } else if (at->a_att_field != NULL && + 0 == strcmp (at->a_att_field, "sendrecv")) { + return _SENDRECV; + } + pos++; + } - /* test global attributes */ - pos_media = -1; - pos = 0; - while (!osip_list_eol (sdp->a_attributes, pos)) { - sdp_attribute_t *at; - - at = (sdp_attribute_t *) osip_list_get (sdp->a_attributes, pos); - if (at->a_att_field != NULL && - 0 == strcmp (at->a_att_field, "sendonly")) { - return _SENDONLY; - } else if (at->a_att_field != NULL && - 0 == strcmp (at->a_att_field, "recvonly")) { - return _RECVONLY; - } else if (at->a_att_field != NULL && - 0 == strcmp (at->a_att_field, "sendrecv")) { - return _SENDRECV; - } - pos++; + /* test global attributes */ + pos_media = -1; + pos = 0; + while (!osip_list_eol (sdp->a_attributes, pos)) { + sdp_attribute_t *at; + + at = (sdp_attribute_t *) osip_list_get (sdp->a_attributes, pos); + if (at->a_att_field != NULL && + 0 == strcmp (at->a_att_field, "sendonly")) { + return _SENDONLY; + } else if (at->a_att_field != NULL && + 0 == strcmp (at->a_att_field, "recvonly")) { + return _RECVONLY; + } else if (at->a_att_field != NULL && + 0 == strcmp (at->a_att_field, "sendrecv")) { + return _SENDRECV; + } + pos++; + } + + return _SENDRECV; +} + +bool +SIPCall::setPeerInfoFromRequest(eXosip_event_t *event) +{ + // event->request should not be NULL! + char remote_uri[256] = ""; + std::string name(""); + std::string number(""); + + char *tmp = NULL; + osip_from_to_str(event->request->from, &tmp); + if (tmp != NULL) { + snprintf (remote_uri, 255, "%s", tmp); + remote_uri[255] = '\0'; + osip_free (tmp); + + // Get the name/number + osip_from_t *from; + osip_from_init(&from); + osip_from_parse(from, remote_uri); + char *tmpname = osip_from_get_displayname(from); + if ( tmpname != NULL ) { + name = tmpname; } + osip_uri_t* url = osip_from_get_url(from); + if ( url != NULL && url->username != NULL) { + number = url->username; + } + osip_from_free(from); + } - return _SENDRECV; + _debug(" Name: %s\n", name.c_str()); + _debug(" Number: %s\n", number.c_str()); + _debug(" Remote URI: %s\n", remote_uri); + + setPeerName(name); + setPeerNumber(number); + return true; } -void -SipCall::alloc(void) { - this->_reason_phrase = new char[50]; - this->_textinfo = new char[256]; - this->_remote_uri = new char[256]; - this->_remote_sdp_audio_ip = new char[50]; - - // initialize the strings... - this->_reason_phrase[0] = '\0'; - this->_textinfo[0] = '\0'; - this->_remote_uri[0] = '\0'; - strcpy(this->_remote_sdp_audio_ip, "127.0.0.1"); +sdp_message_t* +SIPCall::getRemoteSDPFromRequest(eXosip_event_t *event) +{ + // event->request should not be null! + /* negotiate payloads */ + sdp_message_t *remote_sdp = NULL; + if (event->request != NULL) { + eXosip_lock(); + remote_sdp = eXosip_get_sdp_info (event->request); + eXosip_unlock(); + } + if (remote_sdp == NULL) { + _debug("SIP Failure: No SDP into the request\n"); + _debug("< Sending 400 Bad Request (no SDP)\n"); + eXosip_lock(); + eXosip_call_send_answer (event->tid, 400, NULL); + eXosip_unlock(); + return 0; + } + return remote_sdp; } -void -SipCall::dealloc(void) { - delete [] _reason_phrase; _reason_phrase = NULL; - delete [] _textinfo; _textinfo = NULL; - delete [] _remote_uri; _remote_uri = NULL; - delete [] _remote_sdp_audio_ip; _remote_sdp_audio_ip = NULL; +sdp_media_t* +SIPCall::getRemoteMedia(int tid, sdp_message_t* remote_sdp) +{ + // Remote Media Port + eXosip_lock(); + sdp_media_t *remote_med = eXosip_get_audio_media(remote_sdp); + eXosip_unlock(); + + if (remote_med == NULL || remote_med->m_port == NULL) { + // no audio media proposed + _debug("SIP Failure: unsupported media\n"); + _debug("< Sending 415 Unsupported media type\n"); + eXosip_lock(); + eXosip_call_send_answer (tid, 415, NULL); + eXosip_unlock(); + sdp_message_free (remote_sdp); + return 0; + } + return remote_med; } -void -SipCall::noSupportedCodec (void) { - _debug("SipCall::noSupportedCodec: Codec no supported\n"); +bool +SIPCall::setRemoteAudioFromSDP(sdp_media_t* remote_med, sdp_message_t* remote_sdp) +{ + // Remote Media IP + eXosip_lock(); + sdp_connection_t *conn = eXosip_get_audio_connection(remote_sdp); + eXosip_unlock(); + if (conn != NULL && conn->c_addr != NULL) { + char _remote_sdp_audio_ip[50] = ""; + snprintf (_remote_sdp_audio_ip, 49, "%s", conn->c_addr); + _remote_sdp_audio_ip[49] = '\0'; + _debug(" Remote Audio IP: %s\n", _remote_sdp_audio_ip); + setRemoteIP(_remote_sdp_audio_ip); + if (_remote_sdp_audio_ip[0] == '\0') { + setRemoteAudioPort(0); + return false; + } + } + + // Remote port + int _remote_sdp_audio_port = atoi(remote_med->m_port); + _debug(" Remote Audio Port: %d\n", _remote_sdp_audio_port); + setRemoteAudioPort(_remote_sdp_audio_port); + + if (_remote_sdp_audio_port == 0) { + return false; + } + return true; } +bool +SIPCall::setAudioCodecFromSDP(sdp_media_t* remote_med, int tid) +{ + // Remote Payload + char *tmp = NULL; + int pos = 0; + while (!osip_list_eol (remote_med->m_payloads, pos)) { + tmp = (char *) osip_list_get (remote_med->m_payloads, pos); + if (tmp != NULL ) { + int payload = atoi(tmp); + // stop if we find a correct codec + if (0 != _codecMap.getCodec((CodecType)payload)){ + break; + } + } + tmp = NULL; + pos++; + } + + setAudioCodec(0); + if (tmp != NULL) { + int payload = atoi (tmp); + _debug(" Payload: %d\n", payload); + setAudioCodec(_codecMap.getCodec((CodecType)payload)); // codec builder for the mic + } + if (getAudioCodec() == 0) { + _debug("SIPCall Failure: Unable to set codec\n"); + _debug("< Sending 415 Unsupported media type\n"); + eXosip_lock(); + eXosip_call_send_answer(tid, 415, NULL); + eXosip_unlock(); + return false; + } + return true; +} diff --git a/src/sipcall.h b/src/sipcall.h index bf9c3ab195abc063853bad1d5e8d9d2dee4ce2a4..cbe640a055f25aea066e14bedd060e2df4adb50b 100644 --- a/src/sipcall.h +++ b/src/sipcall.h @@ -1,155 +1,181 @@ -/** - * Copyright (C) 2004-2005 Savoir-Faire Linux inc. - * Author: Yan Morin <yan.morin@savoirfairelinux.com> - * Author: Laurielle Lea <laurielle.lea@savoirfairelinux.com> - * - * Portions Copyright (C) 2002,2003 Aymeric Moizard <jack@atosc.org> +/* + * Copyright (C) 2004-2006 Savoir-Faire Linux inc. + * Author: Yan Morin <yan.morin@savoirfairelinux.com> + * Author : Laurielle Lea <laurielle.lea@savoirfairelinux.com> * - * This 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 2, - * or (at your option) any later version. + * 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 2 of the License, or + * (at your option) any later version. * - * This 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. + * 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 dpkg; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * 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 SIPCALL_H +#define SIPCALL_H -#ifndef __SIP_CALL_H__ -#define __SIP_CALL_H__ - -#include <eXosip2/eXosip.h> -#include <vector> -#include <string> #include "call.h" +#include "audio/codecDescriptor.h" +#include <eXosip2/eXosip.h> -class CodecDescriptor; class AudioCodec; -#define _SENDRECV 0 -#define _SENDONLY 1 -#define _RECVONLY 2 - -// Vector of CodecDescriptor -class SipCall { +/** + @author Yan Morin <yan.morin@gmail.com> + SIPCall are SIP implementation of a normal Call +*/ +class SIPCall : public Call +{ public: - SipCall(CALLID id, CodecDescriptorMap& codecMap); - ~SipCall (void); + SIPCall(const CallID& id, Call::CallType type); + + ~SIPCall(); + + /** @return SIP call id : protected by eXosip lock */ + int getCid() { return _cid; } + /** @param cid SIP call id : protected by eXosip lock */ + void setCid(int cid) { _cid = cid ; } + /** @return SIP domain id : protected by eXosip lock */ + int getDid() { return _did; } + /** @param did SIP domain id : protected by eXosip lock */ + void setDid(int did) { _did = did; } + /** @return SIP transaction id : protected by eXosip lock */ + int getTid() { return _tid; } + /** @param did SIP transaction id : protected by eXosip lock */ + void setTid(int tid) { _tid = tid; } + + // AUDIO + /** Set internal codec Map: initialization only, not protected */ + void setCodecMap(const CodecDescriptorMap& map) { _codecMap = map; } + CodecDescriptorMap& getCodecMap(); + + /** set internal, not protected */ + void setLocalIp(const std::string& ip) { _localIPAddress = ip; } + void setLocalAudioPort(unsigned int port) { _localAudioPort = port;} + void setLocalExternAudioPort(unsigned int port) { _localExternalAudioPort = port; } + unsigned int getLocalExternAudioPort() { return _localExternalAudioPort; } /** - * Store information about incoming call and negociate payload + * Answer incoming call correclty before telling the user + * @param event eXosip Event */ - int newIncomingCall(eXosip_event_t *); - int newReinviteCall(eXosip_event_t *); - - /* - * Use to answer to a ONHOLD/OFFHOLD event - */ - int answeredCall (eXosip_event_t *); - - /* - * Use to answer to an incoming call - */ - void answeredCall_without_hold (eXosip_event_t *); - - int ringingCall (eXosip_event_t *); - int receivedAck (eXosip_event_t *); - - /* - * Manage local audio port for each sipcall - */ - void setLocalAudioPort (int); - int getLocalAudioPort (void); - - std::string getLocalIp() { return _localIp; } - void setLocalIp(const std::string& ip) { _localIp = ip; } - - bool isReinvite() { return _reinvite; } - void endReinvite() { _reinvite = false; }; - - /* - * Manage id, did (dialog-id), cid (call-id) and tid (transaction-id) - * for each sipcall - */ - void setId (CALLID id); - CALLID getId (void); - void setDid (int did); - int getDid (void); - void setCid (int cid); - int getCid (void); - void setTid (int tid); - int getTid (void); - - /* - * Manage remote sdp audio port - */ - int getRemoteSdpAudioPort (void); - char* getRemoteSdpAudioIp (void); - - /* - * Manage audio codec + bool SIPCallInvite(eXosip_event_t *event); + + /** + * newReinviteCall is called when the IP-Phone user receives a change in the call + * it's almost an newIncomingCall but we send a 200 OK + * See: 3.7. Session with re-INVITE (IP Address Change) + * @param event eXosip Event + * @return true if ok */ - AudioCodec* getAudioCodec(void) { return _audiocodec; } - void setAudioCodec(AudioCodec* ac) { _audiocodec = ac; } - CodecDescriptorMap& getCodecMap() { return _codecMap; } + bool SIPCallReinvite(eXosip_event_t *event); - /* - * Accessor to remote-uri + /** + * Peer answered to a call (on hold or not) + * @param event eXosip Event + * @return true if ok + */ + bool SIPCallAnswered(eXosip_event_t *event); + /** + * We retreive final SDP info if they changed + * @param event eXosip Event + * @return true if ok (change / no change) or false on error */ - inline char* getRemoteUri (void) { return _remote_uri; } + bool SIPCallAnsweredWithoutHold(eXosip_event_t *event); - /* - * To avoid confusion when an incoming call occured in the same time - * that you make an outgoing call + /** protected */ + const std::string& getLocalIp(); + unsigned int getLocalAudioPort(); + unsigned int getRemoteAudioPort(); + const std::string& getRemoteIp(); + AudioCodec* getAudioCodec(); + + /** + * Set the audio start boolean (protected by mutex) + * @param start true if we start the audio + */ + void setAudioStart(bool start); + /** + * Tell if the audio is started (protected by mutex) + * @return true if it's already started */ - inline void setStandBy (bool standby) { _standby = standby; } - inline bool getStandBy (void) { return _standby; } + bool isAudioStarted(); - std::string getName() const { return _name; } - std::string getNumber() const { return _number; } + //TODO: humm? int sdp_complete_message(sdp_message_t * remote_sdp, osip_message_t * msg); + private: - void alloc (void); - void dealloc (void); - void noSupportedCodec(void); + /** set internal, not protected */ + void setRemoteIP(const std::string& ip) { _remoteIPAddress = ip; } + void setRemoteAudioPort(unsigned int port) { _remoteAudioPort = port; } + void setAudioCodec(AudioCodec* audioCodec) { _audioCodec = audioCodec; } + // TODO: hum??? int sdp_analyse_attribute (sdp_message_t * sdp, sdp_media_t * med); - - /////////////////////////// - // Private member variables - /////////////////////////// - CodecDescriptorMap& _codecMap; - AudioCodec* _audiocodec; - - CALLID _id; - int _cid; // call id - int _did; // dialog id - int _tid; // transaction id - bool _standby; // wait for a cid and did when outgoing call is made - - int _status_code; - - char* _reason_phrase; - char* _textinfo; - char* _remote_uri; - - char* _remote_sdp_audio_ip; - int _local_audio_port; - int _remote_sdp_audio_port; - int _local_sendrecv; /* _SENDRECV, _SENDONLY, _RECVONLY */ - int _remote_sendrecv; /* _SENDRECV, _SENDONLY, _RECVONLY */ - - std::string _localIp; - std::string _name; // set by incoming call - std::string _number; // set by incoming call - - bool _reinvite; + /** + * Set peer name and number with event->request->from + * @param event eXosip event + * @return false the event is invalid + */ + bool setPeerInfoFromRequest(eXosip_event_t *event); + /** + * Get a valid remote SDP or return a 400 bad request response if invalid + * @param event eXosip event + * @return valid remote_sdp or 0 + */ + sdp_message_t* getRemoteSDPFromRequest(eXosip_event_t *event); + + /** + * Get a valid remote media or return a 415 unsupported media type + * @param tid transaction id + * @param remote_sdp Remote SDP pointer + * @return valid sdp_media_t or 0 + */ + sdp_media_t* getRemoteMedia(int tid, sdp_message_t* remote_sdp); + + /** + * Set Audio Port and Audio IP from Remote SDP Info + * @param remote_med Remote Media info + * @param remote_sdp Remote SDP pointer + * @return true if everything is set correctly + */ + bool setRemoteAudioFromSDP(sdp_media_t* remote_med, sdp_message_t* remote_sdp); + + /** + * Set Audio Codec with the remote choice + * @param remote_med Remote Media info + * @return true if everything is set correctly + */ + bool setAudioCodecFromSDP(sdp_media_t* remote_med, int tid); + + + /** SIP call id */ + int _cid; + /** SIP domain id */ + int _did; + /** SIP transaction id */ + int _tid; + + /** Codec Map */ + CodecDescriptorMap _codecMap; + /** codec pointer */ + AudioCodec* _audioCodec; + bool _audioStarted; + + // Informations about call socket / audio + std::string _localIPAddress; + unsigned int _localAudioPort; + unsigned int _localExternalAudioPort; // what peer (NAT) should connect to + + std::string _remoteIPAddress; + unsigned int _remoteAudioPort; }; -#endif // __SIP_CALL_H__ +#endif diff --git a/src/sipvoiplink.cpp b/src/sipvoiplink.cpp index 314f462852e1e8d1f12e9413d643e83a40f623de..9214b097222dac6b357745f4fa36f3e583fcb7f5 100644 --- a/src/sipvoiplink.cpp +++ b/src/sipvoiplink.cpp @@ -1,10 +1,8 @@ /* - * Copyright (C) 2004-2005 Savoir-Faire Linux inc. + * Copyright (C) 2004-2006 Savoir-Faire Linux inc. * Author: Yan Morin <yan.morin@savoirfairelinux.com> * Author : Laurielle Lea <laurielle.lea@savoirfairelinux.com> * - * Portions Copyright (C) 2002,2003 Aymeric Moizard <jack@atosc.org> - * * 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 2 of the License, or @@ -19,564 +17,686 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ -#include <eXosip2/eXosip.h> -#include <osip2/osip.h> -#include <osipparser2/osip_const.h> - #include "sipvoiplink.h" -#include "global.h" -#include "audio/codecDescriptor.h" -#include "manager.h" -#include "sipcall.h" -#include "user_cfg.h" #include "eventthread.h" +#include "sipcall.h" +#include <sstream> // for ostringstream + +#include "manager.h" +#include "user_cfg.h" // SIGNALISATION / PULSE #define -#define DEFAULT_SIP_PORT 5060 -#define RANDOM_SIP_PORT rand() % 64000 + 1024 -#define DEFAULT_LOCAL_PORT 10500 -#define RANDOM_LOCAL_PORT ((rand() % 27250) + 5250)*2 +// for listener +#define DEFAULT_SIP_PORT 5060 +#define RANDOM_SIP_PORT rand() % 64000 + 1024 +#define RANDOM_LOCAL_PORT ((rand() % 27250) + 5250)*2 #define EXOSIP_ERROR_NO 0 #define EXOSIP_ERROR_STD -1 #define EXOSIP_ERROR_BUILDING -2 -#define VOICE_MSG "Voice-Message" -#define LENGTH_VOICE_MSG 15 +// for registration +#define EXPIRES_VALUE 180 + +// 1XX responses +#define DIALOG_ESTABLISHED 101 +// see: osip_const.h -SipVoIPLink::SipVoIPLink() : VoIPLink() +// FOR VOICE Message handling +#define VOICE_MSG "Voice-Message" +#define LENGTH_VOICE_MSG 15 + +// need for hold/unhold +#define INVITE_METHOD "INVITE" + + +SIPVoIPLink::SIPVoIPLink(const AccountID& accountID) + : VoIPLink(accountID), _localExternAddress("") { - // default _audioRTP object initialization _evThread = new EventThread(this); - _localPort = 0; + _nMsgVoicemail = 0; - _reg_id = EXOSIP_ERROR_STD; + _eXosipRegID = EXOSIP_ERROR_STD; + _eXosipStarted = false; + + _nbTryListenAddr = 2; // number of times to try to start SIP listener + _localExternPort = 0; + + // to get random number for RANDOM_PORT + srand (time(NULL)); +} - _registrationSend = false; - _started = false; - _localIpAddress = "127.0.0.1"; // sipvoip require this value to check network +SIPVoIPLink::~SIPVoIPLink() +{ + delete _evThread; _evThread = 0; + terminate(); +} + +bool +SIPVoIPLink::init() +{ + if (!_eXosipStarted) { + if (0 != eXosip_init()) { + _debug("Could not initialize eXosip\n"); + return false; + } + _eXosipStarted = true; + + // check networking capabilities + if ( !checkNetwork() ) { + _debug("SIP FAILURE: Unable to determine network capabilities\n"); + return false; + } + + // if we useStun and we failed to receive something on port 5060, we try a random port + // If use STUN server, firewall address setup + int errExosip = 0; + int port = DEFAULT_SIP_PORT; + + int iTry = 1; // try number.. + + do { + if (_useStun && !Manager::instance().behindNat(port)) { + port = RANDOM_SIP_PORT; + if (!Manager::instance().behindNat(port)) { + _debug("SIP FAILURE: Unable to check NAT setting\n"); + return false; // hoho we can't use the random sip port too... + } + } + + // second parameter, NULL is "::" for ipv6 and "0.0.0.0" for ipv4, we can put INADDR_ANY + errExosip = eXosip_listen_addr(IPPROTO_UDP, INADDR_ANY, port, AF_INET, 0); + if (errExosip != 0) { + _debug("SIP ERROR: [%d/%d] could not initialize SIP listener on port %d\n", iTry, _nbTryListenAddr, port); + port = RANDOM_SIP_PORT; + } + } while ( errExosip != 0 && iTry < _nbTryListenAddr ); + + if ( errExosip != 0 ) { // we didn't succeeded + _debug("SIP FAILURE: SIP failed to listen on port %d\n", port); + return false; + } + _localPort = port; + _debug("SIP Init: listening on port %d\n", port); + + if (_useStun) { + // This method is used to replace contact address with the public address of your NAT + // it should be call after eXosip_listen_addr + // set by last behindNat() call (ish)... + _localExternAddress = Manager::instance().getFirewallAddress(); + _localExternPort = Manager::instance().getFirewallPort(); + eXosip_masquerade_contact(_localExternAddress.data(), _localExternPort); + } else { + _localExternAddress = _localIPAddress; + _localExternPort = _localPort; + } + + // Set user agent + std::string tmp = std::string(PROGNAME_GLOBAL) + "/" + std::string(SFLPHONED_VERSION); + eXosip_set_user_agent(tmp.data()); + + _debug("SIP Init: starting loop thread (SIP events)\n"); + _evThread->start(); + } + return _eXosipStarted; } -SipVoIPLink::~SipVoIPLink(void) { - endSipCalls(); - delete _evThread; _evThread = NULL; - if (_started) { + + +void +SIPVoIPLink::terminate() +{ + terminateSIPCall(); + if (_eXosipStarted) { eXosip_quit(); + _eXosipStarted = false; } } -// for voIPLink interface void -SipVoIPLink::terminate(void) +SIPVoIPLink::terminateSIPCall() { + ost::MutexLock m(_callMapMutex); + CallMap::iterator iter = _callMap.begin(); + SIPCall *call; + while( iter != _callMap.end() ) { + call = dynamic_cast<SIPCall*>(iter->second); + if (call) { + // Release SIP stack. + eXosip_lock(); + eXosip_call_terminate(call->getCid(), call->getDid() ); + eXosip_unlock(); + delete call; call = 0; + } + iter++; + } + _callMap.clear(); } bool -SipVoIPLink::checkNetwork (void) +SIPVoIPLink::checkNetwork() { // Set IP address - return getSipLocalIp(); + return loadSIPLocalIP(); } - -/** - * Steps: - * 1. Init eXosip - * 2. Try to listen two times on a port - * if we use stun, we check if we can use 5060, before connecting to eXosip... - * if we can't we check on a random port - */ bool -SipVoIPLink::init(void) +SIPVoIPLink::loadSIPLocalIP() { - // TODO: should be inside the account - _fullname = Manager::instance().getConfigString(SIGNALISATION,FULL_NAME) ; - _hostname = Manager::instance().getConfigString(SIGNALISATION,HOST_PART); - - if (0 != eXosip_init()) { - _debug("Could not initialize eXosip\n"); - return false; - } - _started = true; - - srand (time(NULL)); - int i; - - // check networking capabilities - if ( !checkNetwork() ) { - return false; - } - - // if we useStun and we failed to receive something on port 5060, we try a random port - // If use STUN server, firewall address setup - bool useStun = Manager::instance().useStun(); - int port = DEFAULT_SIP_PORT; - - int nbTry = 2; // number of times to try to start SIP listener - int iTry = 1; // try number.. - - do { - if (useStun && !behindNat(port)) { - port = RANDOM_SIP_PORT; - if (!behindNat(port)) { - return false; // hoho we can't use the random sip port too... - } - } - - // second parameter, NULL is "::" for ipv6 and "0.0.0.0" for ipv4, we can put INADDR_ANY - i = eXosip_listen_addr(IPPROTO_UDP, INADDR_ANY, port, AF_INET, 0); - if (i != 0) { - _debug("SIP ERROR: [%d/%d] could not initialize SIP listener on port %d\n", iTry, nbTry, port); - port = RANDOM_SIP_PORT; + bool returnValue = true; + if (_localIPAddress == "127.0.0.1") { + char* myIPAddress = new char[65]; + if (eXosip_guess_localip(AF_INET, myIPAddress, 64) == EXOSIP_ERROR_STD) { + returnValue = false; + } else { + _localIPAddress = std::string(myIPAddress); + _debug("Checking network, setting local IP address to: %s\n", myIPAddress); } - } while ( i != 0 && iTry < nbTry ); - - if ( i != 0 ) { // we didn't succeeded - _debug("SIP FAILURE: SIP failed to listen on port %d\n", port); - return false; - } - _debug("SIP Init: listening on port %d\n", port); - - if (useStun) { - // This method is used to replace contact address with the public address of your NAT - // it should be call after eXosip_listen_addr - eXosip_masquerade_contact((Manager::instance().getFirewallAddress()).data(), Manager::instance().getFirewallPort()); + delete [] myIPAddress; myIPAddress = NULL; } - - // Set user agent - std::string tmp = std::string(PROGNAME_GLOBAL) + "/" + std::string(SFLPHONED_VERSION); - eXosip_set_user_agent(tmp.data()); - - _debug("SIP Init: starting loop thread (SIP events)\n"); - _evThread->start(); - return true; + return returnValue; } -/** - * Subscibe to message-summary notify - * It allows eXosip to not send ' 481 Subcription Does Not Exist ' response - */ void -SipVoIPLink::subscribeMessageSummary() +SIPVoIPLink::getEvent() { - osip_message_t *subscribe; - const char *route= NULL; - - // from/to - ManagerImpl& manager = Manager::instance(); - std::string from = fromHeader(manager.getConfigString(SIGNALISATION, USER_PART), manager.getConfigString(SIGNALISATION, HOST_PART)); - - // to - std::string to; - to = manager.getConfigString(SIGNALISATION, PROXY); - if (!to.empty()) { - to = toHeader(manager.getConfigString(SIGNALISATION, USER_PART)) + "@" + to; - } else { - to = from; - } - - - // like in http://www.faqs.org/rfcs/rfc3842.html - const char *event="message-summary"; - int expires = 86400; - - // return 0 if no error - // the first from is the to... but we send the same + eXosip_event_t* event = eXosip_event_wait(0, 50); eXosip_lock(); - int error = eXosip_subscribe_build_initial_request(&subscribe, to.c_str(), from.c_str(), route, event, expires); + eXosip_automatic_action(); eXosip_unlock(); - if (error == 0) { - // Accept: application/simple-message-summary - osip_message_set_header (subscribe, "Accept", "application/simple-message-summary"); - - _debug("Sending Message-summary subscription"); - // return 0 if ok - eXosip_lock(); - error = eXosip_subscribe_send_initial_request (subscribe); - eXosip_unlock(); - _debug(" and return %d\n", error); + if (event == NULL) { + return; } + + _debug("SIP Event: [cdt=%4d:%4d:%4d] type=#%03d %s \n", event->cid, event->did, event->tid, event->type, event->textinfo); + switch (event->type) { + /* REGISTER related events */ + case EXOSIP_REGISTRATION_NEW: /** 00 < announce new registration. */ + _debug("EXOSIP_REGISTRATION_NEW event is not implemented\n"); + break; + case EXOSIP_REGISTRATION_SUCCESS: /** 01 < user is successfully registred. */ + Manager::instance().registrationSucceed(getAccountID()); + break; + case EXOSIP_REGISTRATION_FAILURE: /** 02 < user is not registred. */ + Manager::instance().registrationFailed(getAccountID()); + break; + case EXOSIP_REGISTRATION_REFRESHED: /** 03 < registration has been refreshed. */ + _debug("EXOSIP_REGISTRATION_REFRESHED event is not implemented\n"); + break; + case EXOSIP_REGISTRATION_TERMINATED: /** 04 < UA is not registred any more. */ + _debug("EXOSIP_REGISTRATION_TERMINATED event is not implmeneted\n"); + break; + + /* INVITE related events within calls */ + case EXOSIP_CALL_INVITE: /** 05 < announce a new call */ + SIPCallInvite(event); + break; + case EXOSIP_CALL_REINVITE: /** 06 < announce a new INVITE within call */ + SIPCallReinvite(event); + break; + + case EXOSIP_CALL_NOANSWER: /** 07 < announce no answer within the timeout */ + _debug("EXOSIP_CALL_NOANSWER event is not implemented\n"); + break; + case EXOSIP_CALL_PROCEEDING: /** 08 < announce processing by a remote app */ + _debug("EXOSIP_CALL_NOANSWER event is not implemented\n"); + break; + case EXOSIP_CALL_RINGING: /** 09 < announce ringback */ + SIPCallRinging(event); + break; + case EXOSIP_CALL_ANSWERED: /** 10 < announce start of call */ + SIPCallAnswered(event); + break; + case EXOSIP_CALL_REDIRECTED: /** 11 < announce a redirection */ + _debug("EXOSIP_CALL_REDIRECTED event is not implemented\n"); + break; + case EXOSIP_CALL_REQUESTFAILURE: /** 12 < announce a request failure */ + SIPCallRequestFailure(event); + break; + case EXOSIP_CALL_SERVERFAILURE: /** 13 < announce a server failure */ + SIPCallServerFailure(event); + break; + case EXOSIP_CALL_GLOBALFAILURE: /** 14 < announce a global failure */ + SIPCallServerFailure(event); + break; + case EXOSIP_CALL_ACK: /** 15 < ACK received for 200ok to INVITE */ + SIPCallAck(event); + break; + + case EXOSIP_CALL_CANCELLED: /** 16 < announce that call has been cancelled */ + case EXOSIP_CALL_TIMEOUT: /** 17 < announce that call has failed */ + Manager::instance().displayError("EXOSIP Call Error not implemented yet"); + break; + + /* request related events within calls (except INVITE) */ + case EXOSIP_CALL_MESSAGE_NEW: /** 18 < announce new incoming MESSAGE. */ + SIPCallMessageNew(event); + break; + case EXOSIP_CALL_MESSAGE_PROCEEDING: /** 19 < announce a 1xx for MESSAGE. */ + case EXOSIP_CALL_MESSAGE_ANSWERED: /** 20 < announce a 200ok */ + // 200 OK + case EXOSIP_CALL_MESSAGE_REDIRECTED: /** 21 < announce a failure. */ + case EXOSIP_CALL_MESSAGE_REQUESTFAILURE: /** 22 < announce a failure. */ + case EXOSIP_CALL_MESSAGE_SERVERFAILURE: /** 23 < announce a failure. */ + case EXOSIP_CALL_MESSAGE_GLOBALFAILURE: /** 24 < announce a failure. */ + Manager::instance().displayError("EXOSIP Call Message not implemented yet"); + break; + + case EXOSIP_CALL_CLOSED: /** 25 < a BYE was received for this call */ + SIPCallClosed(event); + break; + + /* for both UAS & UAC events */ + case EXOSIP_CALL_RELEASED: /** 26 < call context is cleared. */ + SIPCallReleased(event); + break; + + /* response received for request outside calls */ + case EXOSIP_MESSAGE_NEW: /** 27 < announce new incoming MESSAGE. */ + if (event->request == NULL) { break; } + SIPMessageNew(event); + break; + case EXOSIP_MESSAGE_PROCEEDING: /** 28 < announce a 1xx for MESSAGE. */ + case EXOSIP_MESSAGE_ANSWERED: /** 29 < announce a 200ok */ + case EXOSIP_MESSAGE_REDIRECTED: /** 30 < announce a failure. */ + Manager::instance().displayError("EXOSIP Message not implemented yet"); + break; + + case EXOSIP_MESSAGE_REQUESTFAILURE: /** 31 < announce a failure. */ + if (event->response !=0 && event->response->status_code == SIP_METHOD_NOT_ALLOWED) { + Manager::instance().incomingMessage(getAccountID(), "Message are not allowed"); + } else { + Manager::instance().displayError("EXOSIP_MESSAGE_REQUESTFAILURE not implemented yet"); + } + break; + case EXOSIP_MESSAGE_SERVERFAILURE: /** 32 < announce a failure. */ + case EXOSIP_MESSAGE_GLOBALFAILURE: /** 33 < announce a failure. */ + Manager::instance().displayError("EXOSIP Message not implemented yet"); + break; + + /* Presence and Instant Messaging */ + case EXOSIP_SUBSCRIPTION_UPDATE: /** 34 < announce incoming SUBSCRIBE. */ + case EXOSIP_SUBSCRIPTION_CLOSED: /** 35 < announce end of subscription. */ + Manager::instance().displayError("EXOSIP Subscription not implemented yet"); + break; + + case EXOSIP_SUBSCRIPTION_NOANSWER: /** 37 < announce no answer */ + case EXOSIP_SUBSCRIPTION_PROCEEDING: /** 38 < announce a 1xx */ + Manager::instance().displayError("EXOSIP Subscription resposne not implemented yet"); + break; + case EXOSIP_SUBSCRIPTION_ANSWERED: /** 39 < announce a 200ok */ + eXosip_lock(); + eXosip_automatic_action(); + eXosip_unlock(); + break; + + case EXOSIP_SUBSCRIPTION_REDIRECTED: /** 40 < announce a redirection */ + case EXOSIP_SUBSCRIPTION_REQUESTFAILURE: /** 41 < announce a request failure */ + case EXOSIP_SUBSCRIPTION_SERVERFAILURE: /** 42 < announce a server failure */ + case EXOSIP_SUBSCRIPTION_GLOBALFAILURE: /** 43 < announce a global failure */ + case EXOSIP_SUBSCRIPTION_NOTIFY: /** 44 < announce new NOTIFY request */ + case EXOSIP_SUBSCRIPTION_RELEASED: /** 45 < call context is cleared. */ + Manager::instance().displayError("EXOSIP Subscription resposne not implemented yet"); + break; + + case EXOSIP_IN_SUBSCRIPTION_NEW: /** 46 < announce new incoming SUBSCRIBE.*/ + case EXOSIP_IN_SUBSCRIPTION_RELEASED: /** 47 < announce end of subscription. */ + Manager::instance().displayError("EXOSIP Subscription not implemented yet"); + break; + + case EXOSIP_EVENT_COUNT: /** 48 < MAX number of events */ + break; + } + eXosip_event_free(event); } -int -SipVoIPLink::setRegister (void) +bool +SIPVoIPLink::setRegister() { - ManagerImpl& manager = Manager::instance(); - - if (_reg_id != EXOSIP_ERROR_STD) { - manager.displayError("Registration already sent. Try to unregister"); - return EXOSIP_ERROR_STD; + if (_eXosipRegID != EXOSIP_ERROR_STD) { + Manager::instance().displayError("SIP Error: Registration already sent. Try to unregister"); + return false; } - // all this will be inside the profil associate with the voip link - std::string proxy = "sip:" + manager.getConfigString(SIGNALISATION, PROXY); - std::string hostname = "sip:" + manager.getConfigString(SIGNALISATION, HOST_PART); - std::string from = fromHeader(manager.getConfigString(SIGNALISATION, USER_PART), manager.getConfigString(SIGNALISATION, HOST_PART)); - - if (manager.getConfigString(SIGNALISATION, HOST_PART).empty()) { - manager.displayConfigError("Fill host part field"); - return EXOSIP_ERROR_STD; + std::string hostname = getHostName(); + if (hostname.empty()) { + Manager::instance().displayConfigError("Fill host part field"); + return false; } - if (manager.getConfigString(SIGNALISATION, USER_PART).empty()) { - manager.displayConfigError("Fill user part field"); - return EXOSIP_ERROR_STD; + + if (_userpart.empty()) { + Manager::instance().displayConfigError("Fill user part field"); + return false; } + + std::string proxy = "sip:" + _proxy; + hostname = "sip:" + hostname; + std::string from = SIPFromHeader(_userpart, getHostName()); + osip_message_t *reg = NULL; eXosip_lock(); - if (!manager.getConfigString(SIGNALISATION, PROXY).empty()) { - _debug("REGISTER From: %s to %s\n", from.data(), proxy.data()); - _reg_id = eXosip_register_build_initial_register ((char*)from.data(), - (char*)proxy.data(), NULL, EXPIRES_VALUE, ®); + if (!_proxy.empty()) { + _debug("SIP Register: From: %s to %s\n", from.data(), proxy.data()); + _eXosipRegID = eXosip_register_build_initial_register(from.data(), + proxy.data(), NULL, EXPIRES_VALUE, ®); } else { - _debug("REGISTER From: %s to %s\n", from.data(), hostname.data()); - _reg_id = eXosip_register_build_initial_register ((char*)from.data(), - (char*)hostname.data(), NULL, EXPIRES_VALUE, ®); + _debug("SIP Register: From: %s to %s\n", from.data(), hostname.data()); + _eXosipRegID = eXosip_register_build_initial_register(from.data(), + hostname.data(), NULL, EXPIRES_VALUE, ®); } eXosip_unlock(); - if (_reg_id < EXOSIP_ERROR_NO ) { - return EXOSIP_ERROR_STD; + if (_eXosipRegID < EXOSIP_ERROR_NO ) { + return false; } - if (setAuthentication() != EXOSIP_ERROR_NO) { - _debug("No authentication\n"); - return EXOSIP_ERROR_STD; + if (!sendSIPAuthentification()) { + _debug("SIP Register: No authentication\n"); + return false; } osip_message_set_header (reg, "Event", "Registration"); osip_message_set_header (reg, "Allow-Events", "presence"); eXosip_lock(); - int i = eXosip_register_send_register (_reg_id, reg); - if (i == -2) { - _debug("Cannot build registration, check the setup\n"); + int eXosipErr = eXosip_register_send_register(_eXosipRegID, reg); + if (eXosipErr == EXOSIP_ERROR_BUILDING) { + _debug("SIP Failure: Cannot build registration, check the setup\n"); eXosip_unlock(); - return EXOSIP_ERROR_STD; + return false; } - if (i == -1) { - _debug("Registration sending failed\n"); + if (eXosipErr == EXOSIP_ERROR_STD) { + _debug("SIP Failure: Registration sending failed\n"); eXosip_unlock(); - return EXOSIP_ERROR_STD; + return false; } eXosip_unlock(); - // subscribe to message one time? - // subscribeMessageSummary(); - _registrationSend = true; - return i; + return true; } -/** - * setUnregister - * unregister if we already send the first registration - * @return -1 if there is an error - */ -int -SipVoIPLink::setUnregister (void) +std::string +SIPVoIPLink::SIPFromHeader(const std::string& userpart, const std::string& hostpart) { - if ( _registrationSend ) { - int i = 0; - osip_message_t *reg = NULL; - - eXosip_lock(); - - if (_reg_id > 0) { - i = eXosip_register_build_register (_reg_id, 0, ®); - } - eXosip_unlock(); - if (i < 0) { - return EXOSIP_ERROR_STD; - } - - eXosip_lock(); - _debug("< Sending REGISTER (expire=0)\n"); - i = eXosip_register_send_register (_reg_id, reg); - if (i == EXOSIP_ERROR_BUILDING) { - _debug(" Cannot build registration (unregister), check the setup\n"); - eXosip_unlock(); - return EXOSIP_ERROR_STD; - } - if (i == EXOSIP_ERROR_STD) { - _debug(" Registration (unregister) Failed\n"); - } - eXosip_unlock(); - _reg_id = EXOSIP_ERROR_STD; - return i; - } else { - // no registration send before - return EXOSIP_ERROR_STD; - } + return ("\"" + getFullName() + "\"" + " <sip:" + userpart + "@" + hostpart + ">"); } -/** - * Get the Sip FROM url (add sip:, add @host, etc...) - */ -std::string -SipVoIPLink::getSipFrom() { - - // Form the From header field basis on configuration panel - std::string user = Manager::instance().getConfigString(SIGNALISATION, USER_PART); - std::string host = Manager::instance().getConfigString(SIGNALISATION, HOST_PART); - if ( host.empty() ) { - host = getLocalIpAddress(); +bool +SIPVoIPLink::sendSIPAuthentification() +{ + std::string login = _authname; + if (login.empty()) { + login = _userpart; } - return fromHeader(user, host); + if (login.empty()) { + Manager::instance().displayConfigError("Fill authentification name"); + return false; + } + if (_password.empty()) { + Manager::instance().displayConfigError("Fill password field"); + return false; + } + eXosip_lock(); + int returnValue = eXosip_add_authentication_info(login.data(), login.data(), _password.data(), NULL, NULL); + eXosip_unlock(); + + return (returnValue != EXOSIP_ERROR_STD ? true : false); } -/** - * Get the Sip TO url (add sip:, add @host, etc...) - */ -std::string -SipVoIPLink::getSipTo(const std::string& to_url) { - // Form the From header field basis on configuration panel - bool isRegistered = (_reg_id < EXOSIP_ERROR_NO) ? false : true; +bool +SIPVoIPLink::setUnregister() +{ + if ( _eXosipRegID == EXOSIP_ERROR_STD) return false; + int eXosipErr = EXOSIP_ERROR_NO; + osip_message_t *reg = NULL; - // add a @host if we are registered and there is no one inside the url - if (to_url.find("@") == std::string::npos && isRegistered) { - std::string host = Manager::instance().getConfigString(SIGNALISATION, HOST_PART); - if(!host.empty()) { - return toHeader(to_url + "@" + host); - } + eXosip_lock(); + eXosipErr = eXosip_register_build_register (_eXosipRegID, 0, ®); + eXosip_unlock(); + + if (eXosipErr != EXOSIP_ERROR_NO) { + _debug("SIP Failure: Unable to build registration for setUnregister"); + return false; } - return toHeader(to_url); -} -/** - * Get the sip proxy (add sip: if there is one) - * @return empty string or <sip:proxy;lr> url - */ -std::string -SipVoIPLink::getSipRoute() { - std::string proxy = Manager::instance().getConfigString(SIGNALISATION, PROXY); - if ( !proxy.empty() ) { - proxy = "<sip:" + proxy + ";lr>"; + eXosip_lock(); + _debug("< Sending REGISTER (expire=0)\n"); + eXosipErr = eXosip_register_send_register (_eXosipRegID, reg); + if (eXosipErr == EXOSIP_ERROR_BUILDING) { + _debug("SIP Failure: Cannot build registration (unregister), check the setup\n"); + eXosip_unlock(); + return false; } - return proxy; // return empty + if (eXosipErr == EXOSIP_ERROR_STD) { + _debug("SIP Failure: Unable to send registration (unregister)\n"); + } + eXosip_unlock(); + _eXosipRegID = EXOSIP_ERROR_STD; + + return true; } -int -SipVoIPLink::outgoingInvite (CALLID id, const std::string& to_url) +Call* +SIPVoIPLink::newOutgoingCall(const CallID& id, const std::string& toUrl) { - bool has_ip = checkNetwork(); - std::string from = getSipFrom(); - std::string to = getSipTo(to_url); - std::string route = getSipRoute(); - - _debug(" From: %s\n", from.data()); - _debug(" To: %s\n", to.data()); - _debug(" Route: %s\n", route.data()); - - // If no SIP proxy setting for direct call with only IP address - if (has_ip) { - if (startCall(id, from, to, "", route) <= 0) { - _debug("Warning SipVoIPLink: call not started\n"); - return EXOSIP_ERROR_STD; + SIPCall* call = new SIPCall(id, Call::Outgoing); + if (call) { + call->setPeerNumber(toUrl); + // we have to add the codec before using it in SIPOutgoingInvite... + call->setCodecMap(Manager::instance().getCodecDescriptorMap()); + if ( SIPOutgoingInvite(call) ) { + call->setConnectionState(Call::Progressing); + call->setState(Call::Active); + addCall(call); + } else { + delete call; call = 0; } - } else { - Manager::instance().displayErrorText(id, "No network found\n"); - return EXOSIP_ERROR_STD; } - return 0; + return call; } -/** - * @return 0 is good, -1 is bad - */ -int -SipVoIPLink::answer(CALLID id) +bool +SIPVoIPLink::answer(const CallID& id) { - int i; - int port; - char tmpbuf[64]; - bzero (tmpbuf, 64); - // Get port - snprintf (tmpbuf, 63, "%d", getSipCall(id)->getLocalAudioPort()); - - _debug("%10d: Answer call [cid = %d, did = %d]\n", id, getSipCall(id)->getCid(), getSipCall(id)->getDid()); - port = getSipCall(id)->getLocalAudioPort(); - _debug(" Local audio port: %d\n", port); + _debug("SIP Action: start answering\n"); - osip_message_t *answerMessage = NULL; - SipCall* ca = getSipCall(id); + SIPCall* call = getSIPCall(id); + if (call==0) { + _debug("SIP Failure: SIPCall doesn't exists\n"); + return false; + } // Send 180 RINGING _debug("< Send 180 Ringing\n"); eXosip_lock (); - eXosip_call_send_answer(ca->getTid(), RINGING, NULL); + eXosip_call_send_answer(call->getTid(), SIP_RINGING, NULL); eXosip_unlock (); + call->setConnectionState(Call::Ringing); // Send 200 OK + osip_message_t *answerMessage = NULL; eXosip_lock(); - i = eXosip_call_build_answer(ca->getTid(), OK, &answerMessage); + _debug("< Building 200 OK\n"); + int i = eXosip_call_build_answer(call->getTid(), SIP_OK, &answerMessage); if (i != 0) { _debug("< Send 400 Bad Request\n"); - eXosip_call_send_answer (ca->getTid(), BAD_REQ, NULL); + eXosip_call_send_answer (call->getTid(), SIP_BAD_REQUEST, NULL); } else { // use exosip, bug locked i = 0; - sdp_message_t *remote_sdp = eXosip_get_remote_sdp(ca->getDid()); + sdp_message_t *remote_sdp = eXosip_get_remote_sdp(call->getDid()); if (remote_sdp!=NULL) { - i = ca->sdp_complete_message(remote_sdp, answerMessage); + i = call->sdp_complete_message(remote_sdp, answerMessage); if (i!=0) { osip_message_free(answerMessage); } - sdp_message_free (remote_sdp); + sdp_message_free(remote_sdp); } if (i != 0) { _debug("< Send 415 Unsupported Media Type\n"); - eXosip_call_send_answer (ca->getTid(), UNSUP_MEDIA_TYPE, NULL); + eXosip_call_send_answer (call->getTid(), SIP_UNSUPPORTED_MEDIA_TYPE, NULL); } else { _debug("< Send 200 OK\n"); - eXosip_call_send_answer (ca->getTid(), OK, answerMessage); + eXosip_call_send_answer (call->getTid(), SIP_OK, answerMessage); } } eXosip_unlock(); - // Incoming call is answered, start the sound channel. - _debug(" Starting AudioRTP\n"); - if (_audiortp.createNewSession (getSipCall(id)) < 0) { - _debug("FATAL: Unable to start sound (%s:%d)\n", __FILE__, __LINE__); - i = EXOSIP_ERROR_STD; + if(i==0) { + // Incoming call is answered, start the sound channel. + _debug(" Starting AudioRTP\n"); + if (_audiortp.createNewSession(call) >= 0) { + call->setAudioStart(true); + call->setConnectionState(Call::Connected); + call->setState(Call::Active); + return true; + } else { + _debug("FATAL: Unable to start sound when answering %s/%d\n", __FILE__, __LINE__); + } } - return i; -} + removeCall(call->getCallId()); + return false; +/* int i; + int port; + char tmpbuf[64]; + bzero (tmpbuf, 64); + // Get port + snprintf (tmpbuf, 63, "%d", getSipCall(id)->getLocalAudioPort()); -/** - * @return > 0 is good, -1 is bad - */ -int -SipVoIPLink::hangup (CALLID id) + _debug("%10d: Answer call [cid = %d, did = %d]\n", id, getSipCall(id)->getCid(), getSipCall(id)->getDid()); + port = getSipCall(id)->getLocalAudioPort(); + _debug(" Local audio port: %d\n", port); +*/ +} + +bool +SIPVoIPLink::hangup(const CallID& id) { - int i = 0; - SipCall* sipcall = getSipCall(id); - if (sipcall == NULL) { return EXOSIP_ERROR_STD; } - _debug("%10d: Hang up call [cid = %d, did = %d]\n", - id, sipcall->getCid(), sipcall->getDid()); + SIPCall* call = getSIPCall(id); + if (call==0) { _debug("Call doesn't exist\n"); return false; } + + _debug("Hang up call %s [cd: %3d %3d]\n", id.data(), call->getCid(), call->getDid()); // Release SIP stack. eXosip_lock(); - i = eXosip_call_terminate (sipcall->getCid(), sipcall->getDid()); + eXosip_call_terminate(call->getCid(), call->getDid()); eXosip_unlock(); // Release RTP channels - if (id == Manager::instance().getCurrentCallId()) { + if (Manager::instance().isCurrentCall(id)) { _audiortp.closeRtpSession(); } - - deleteSipCall(id); - return i; + removeCall(id); + return true; } -int -SipVoIPLink::cancel (CALLID id) +bool +SIPVoIPLink::cancel(const CallID& id) { - int i = 0; - SipCall* sipcall = getSipCall(id); - _debug("%10d: Cancel call [cid = %d]\n", id, sipcall->getCid()); + SIPCall* call = getSIPCall(id); + if (call==0) { _debug("Call doesn't exist\n"); return false; } + + _debug("Cancel call %s [cid: %3d]\n", id.data(), call->getCid()); // Release SIP stack. eXosip_lock(); - i = eXosip_call_terminate (sipcall->getCid(), -1); + eXosip_call_terminate(call->getCid(), -1); eXosip_unlock(); - deleteSipCall(id); - return i; + removeCall(id); + return true; } -/* - * @return -1 = sipcall not present - */ -int -SipVoIPLink::onhold (CALLID id) +bool +SIPVoIPLink::onhold(const CallID& id) { - osip_message_t *invite; - int i; - int did; - - sdp_message_t *local_sdp = NULL; - - SipCall *sipcall = getSipCall(id); - if ( sipcall == NULL ) { return EXOSIP_ERROR_STD; } + SIPCall* call = getSIPCall(id); + if (call==0) { _debug("Call doesn't exist\n"); return false; } - did = sipcall->getDid(); + int did = call->getDid(); eXosip_lock (); - local_sdp = eXosip_get_local_sdp (did); + sdp_message_t *local_sdp = eXosip_get_local_sdp(did); eXosip_unlock (); if (local_sdp == NULL) { - return EXOSIP_ERROR_STD; + _debug("SIP Failure: unable to find local_sdp\n"); + return false; } // Build INVITE_METHOD for put call on-hold + osip_message_t *invite = NULL; eXosip_lock (); - i = eXosip_call_build_request (did, INVITE_METHOD, &invite); + int exosipErr = eXosip_call_build_request (did, INVITE_METHOD, &invite); eXosip_unlock (); - if (i != 0) { + if (exosipErr != 0) { sdp_message_free(local_sdp); - return EXOSIP_ERROR_STD; + _debug("SIP Failure: unable to build invite method to hold call\n"); + return false; } /* add sdp body */ { char *tmp = NULL; - i = sdp_hold_call (local_sdp); + int i = sdp_hold_call(local_sdp); if (i != 0) { sdp_message_free (local_sdp); osip_message_free (invite); - return EXOSIP_ERROR_STD; + _debug("SIP Failure: Unable to hold call in SDP\n"); + return false; } - i = sdp_message_to_str (local_sdp, &tmp); - sdp_message_free (local_sdp); + i = sdp_message_to_str(local_sdp, &tmp); + sdp_message_free(local_sdp); if (i != 0) { osip_message_free (invite); osip_free (tmp); - return EXOSIP_ERROR_STD; + _debug("SIP Failure: Unable to translate sdp message to string\n"); + return false; } osip_message_set_body (invite, tmp, strlen (tmp)); osip_free (tmp); osip_message_set_content_type (invite, "application/sdp"); } - // Send request + // Stop sound + call->setAudioStart(false); _audiortp.closeRtpSession(); + // send request + _debug("< Send on hold request\n"); eXosip_lock (); - i = eXosip_call_send_request (did, invite); + exosipErr = eXosip_call_send_request (did, invite); eXosip_unlock (); - // Disable audio - return i; + return true; } -/** - * @return 0 is good, -1 is bad - */ -int -SipVoIPLink::offhold (CALLID id) +bool +SIPVoIPLink::offhold(const CallID& id) { - osip_message_t *invite; - int i; - int did; + SIPCall* call = getSIPCall(id); + if (call==0) { _debug("Call doesn't exist\n"); return false; } - sdp_message_t *local_sdp = NULL; + int did = call->getDid(); - did = getSipCall(id)->getDid(); eXosip_lock (); - local_sdp = eXosip_get_local_sdp (did); + sdp_message_t *local_sdp = eXosip_get_local_sdp(did); eXosip_unlock (); + if (local_sdp == NULL) { - return EXOSIP_ERROR_STD; + _debug("SIP Failure: unable to find local_sdp\n"); + return false; } // Build INVITE_METHOD for put call off-hold + osip_message_t *invite; eXosip_lock (); - i = eXosip_call_build_request (did, INVITE_METHOD, &invite); + int exosipErr = eXosip_call_build_request (did, INVITE_METHOD, &invite); eXosip_unlock (); - if (i != 0) { + if (exosipErr != 0) { sdp_message_free(local_sdp); return EXOSIP_ERROR_STD; } @@ -585,11 +705,11 @@ SipVoIPLink::offhold (CALLID id) { char *tmp = NULL; - i = sdp_off_hold_call (local_sdp); + int i = sdp_off_hold_call (local_sdp); if (i != 0) { sdp_message_free (local_sdp); osip_message_free (invite); - return EXOSIP_ERROR_STD; + return false; } i = sdp_message_to_str (local_sdp, &tmp); @@ -597,7 +717,7 @@ SipVoIPLink::offhold (CALLID id) if (i != 0) { osip_message_free (invite); osip_free (tmp); - return EXOSIP_ERROR_STD; + return false; } osip_message_set_body (invite, tmp, strlen (tmp)); osip_free (tmp); @@ -607,516 +727,67 @@ SipVoIPLink::offhold (CALLID id) // Send request _debug("< Send off hold request\n"); eXosip_lock (); - i = eXosip_call_send_request (did, invite); + exosipErr = eXosip_call_send_request (did, invite); eXosip_unlock (); // Enable audio _debug(" Starting AudioRTP\n"); - if (_audiortp.createNewSession (getSipCall(id)) < 0) { - _debug("FATAL: Unable to start sound (%s:%d)\n", __FILE__, __LINE__); - i = EXOSIP_ERROR_STD; + // it's sure that this is the current call id... + if (_audiortp.createNewSession(call) < 0) { + _debug("SIP Failure: Unable to start sound (%s:%d)\n", __FILE__, __LINE__); + return false; } - return i; + return true; } -int -SipVoIPLink::transfer (CALLID id, const std::string& to) +bool +SIPVoIPLink::transfer(const CallID& id, const std::string& to) { - osip_message_t *refer; - int i; - std::string tmp_to; - tmp_to = toHeader(to); + SIPCall* call = getSIPCall(id); + if (call==0) { _debug("Call doesn't exist\n"); return false; } + + std::string tmp_to = SIPToHeader(to); if (tmp_to.find("@") == std::string::npos) { - tmp_to = tmp_to + "@" + Manager::instance().getConfigString(SIGNALISATION, -HOST_PART); + tmp_to = tmp_to + "@" + getHostName(); } + osip_message_t *refer; eXosip_lock(); // Build transfer request - i = eXosip_call_build_refer (getSipCall(id)->getDid(), (char*)tmp_to.data(), - &refer); - if (i == 0) { + int exosipErr = eXosip_call_build_refer(call->getDid(), (char*)tmp_to.data(), &refer); + if (exosipErr == 0) { // Send transfer request - i = eXosip_call_send_request (getSipCall(id)->getDid(), refer); + exosipErr = eXosip_call_send_request(call->getDid(), refer); } eXosip_unlock(); - return i; + + // shall we delete the call? + removeCall(id); + return true; } -int -SipVoIPLink::refuse (CALLID id) +bool +SIPVoIPLink::refuse (const CallID& id) { - int i; - char tmpbuf[64]; - bzero (tmpbuf, 64); - // Get local port - snprintf (tmpbuf, 63, "%d", getSipCall(id)->getLocalAudioPort()); - + SIPCall* call = getSIPCall(id); + if (call==0) { _debug("Call doesn't exist\n"); return false; } + osip_message_t *answerMessage = NULL; eXosip_lock(); // not BUSY.. where decline the invitation! - i = eXosip_call_build_answer (getSipCall(id)->getTid(), SIP_DECLINE, &answerMessage); - if (i == 0) { - i = eXosip_call_send_answer (getSipCall(id)->getTid(), SIP_DECLINE, answerMessage); + int exosipErr = eXosip_call_build_answer(call->getTid(), SIP_DECLINE, &answerMessage); + if (exosipErr == 0) { + exosipErr = eXosip_call_send_answer(call->getTid(), SIP_DECLINE, answerMessage); } eXosip_unlock(); - return i; -} - -int -SipVoIPLink::getEvent (void) -{ - // wait for 0 s, 50 ms - eXosip_event_t* event = eXosip_event_wait (0, 50); - eXosip_lock(); - eXosip_automatic_action(); - eXosip_unlock(); - - if (event == NULL) { - return EXOSIP_ERROR_STD; - } - - SipCall* sipcall = NULL; - CALLID id = 0; - int returnValue = EXOSIP_ERROR_NO; - - _debug("SIP Event: #%03d %s\n", event->type, event->textinfo); - - switch (event->type) { - // IP-Phone user receives a new call - case EXOSIP_CALL_INVITE: // - _debug("> INVITE (receive)\n"); - checkNetwork(); - - // Set local random port for incoming call - if (!Manager::instance().useStun()) { - setLocalPort(RANDOM_LOCAL_PORT); - } else { - // If there is a firewall - if (behindNat(DEFAULT_LOCAL_PORT) != 0) { - setLocalPort(Manager::instance().getFirewallPort()); - } else { - returnValue = EXOSIP_ERROR_STD; - break; - } - } - - // Generate id - id = Manager::instance().generateNewCallId(); - Manager::instance().pushBackNewCall(id, Call::Incoming); - _debug("%10d: [cid = %d, did = %d]\n", id, event->cid, event->did); - - // Associate an audio port with a call - sipcall = getSipCall(id); - sipcall->setLocalAudioPort(_localPort); - sipcall->setLocalIp(getLocalIpAddress()); - _debug(" Local listening port: %d\n", _localPort); - _debug(" Local listening IP: %s\n", getLocalIpAddress().c_str()); - - if (sipcall->newIncomingCall(event) == 0 ) { - if (Manager::instance().incomingCall(id, sipcall->getName(), sipcall->getNumber()) == EXOSIP_ERROR_STD) { - Manager::instance().displayError("Incoming Call Failed"); - deleteSipCall(id); - } - } else { - Manager::instance().peerHungupCall(id); - deleteSipCall(id); - Manager::instance().displayError("Incoming Call Failed"); - } - break; - - case EXOSIP_CALL_REINVITE: - _debug("> INVITE (reinvite)\n"); - //eXosip_call_send_answer(event->tid, 403, NULL); - //488 as http://www.atosc.org/pipermail/public/osip/2005-June/005385.html - - id = findCallId(event); - if (id != 0) { - sipcall = getSipCall(id); - if (sipcall != 0) { - _debug("%10d: Receive Reinvite [cid = %d, did = %d], localport=%d\n", id, event->cid, event->did,sipcall->getLocalAudioPort()); - - if ( id == Manager::instance().getCurrentCallId() ) { - Manager::instance().stopTone(); - _audiortp.closeRtpSession(); - } - sipcall->newReinviteCall(event); - // we should receive an ack after that... - } - } else { - _debug("< Send 488 Not Acceptable Here"); - eXosip_lock(); - eXosip_call_send_answer(event->tid, 488, NULL); - eXosip_unlock(); - } - break; - - case EXOSIP_CALL_PROCEEDING: // 8 - // proceeding call... - break; - - case EXOSIP_CALL_RINGING: // 9 peer call is ringing - id = findCallIdInitial(event); - _debug("%10d: Receive Call Ringing [cid = %d, did = %d]\n", id, event->cid, event->did); - if (id != 0) { - getSipCall(id)->ringingCall(event); - Manager::instance().peerRingingCall(id); - } else { - returnValue = -1; - } - break; - - // The peer-user answers - case EXOSIP_CALL_ANSWERED: // 10 - { - id = findCallIdInitial(event); - if ( id != 0) { - sipcall = getSipCall(id); - if ( sipcall != 0 ) { - _debug("%10d: Receive Call Answer [cid = %d, did = %d], localport=%d\n", id, event->cid, event->did, sipcall->getLocalAudioPort()); - - // Answer - if (Manager::instance().callCanBeAnswered(id)) { - sipcall->setStandBy(false); - if (sipcall->answeredCall(event) != -1) { - sipcall->answeredCall_without_hold(event); - Manager::instance().peerAnsweredCall(id); - - if(!Manager::instance().callIsOnHold(id) && Manager::instance().getCurrentCallId()==id) { - // Outgoing call is answered, start the sound channel. - _debug(" Starting AudioRTP\n"); - if (_audiortp.createNewSession(sipcall) < 0) { - _debug(" FATAL: Unable to start sound (%s:%d)\n", - __FILE__, __LINE__); - returnValue = -1; - } - } - } - } else { - // Answer to on/off hold to send ACK - _debug(" Answering call\n"); - sipcall->answeredCall(event); - } - } - } else { - returnValue = -1; - } - } - break; - case EXOSIP_CALL_REDIRECTED: // 11 - break; - - case EXOSIP_CALL_ACK: // 15 - id = findCallId(event); - _debug("%10d: Receive ACK [cid = %d, did = %d]\n", id, event->cid, event->did); - if (id != 0 ) { - sipcall = getSipCall(id); - if(sipcall != 0 ) { - sipcall->receivedAck(event); - if (sipcall->isReinvite()) { - sipcall->endReinvite(); - if(!Manager::instance().callIsOnHold(id) && Manager::instance().getCurrentCallId()==id) { - _debug(" Starting AudioRTP\n"); - _audiortp.createNewSession(sipcall); - } else { - _debug(" Didn't start RTP because it's on hold or it's not the current call id\n"); - } - } - } - } else { - returnValue = -1; - } - break; - - // The peer-user closed the phone call(we received BYE). - case EXOSIP_CALL_CLOSED: // 25 - id = findCallId(event); - if (id==0) { id = findCallIdInitial(event); } - _debug("%10d: Receive BYE [cid = %d, did = %d]\n", id, event->cid, event->did); - if (id != 0) { - if (Manager::instance().callCanBeClosed(id)) { - sipcall = getSipCall(id); - _audiortp.closeRtpSession(); - } - Manager::instance().peerHungupCall(id); - deleteSipCall(id); - } else { - returnValue = -1; - } - break; - case EXOSIP_CALL_RELEASED: - if (event) { - _debug("SIP call released: [cid = %d, did = %d]\n", event->cid, event->did); - id = findCallId(event); - if (id!=0) { - // not supposed to be execute on a current call... - Manager::instance().callFailure(id); - deleteSipCall(id); - } - - } - break; - case EXOSIP_CALL_REQUESTFAILURE: //12 - - _debug("Request Failure, receive code %d\n", event->response->status_code); - // Handle 4XX errors - switch (event->response->status_code) { - case AUTH_REQUIRED: - _debug("SIP Server ask required authentification: logging...\n"); - setAuthentication(); - eXosip_lock(); - eXosip_automatic_action(); - eXosip_unlock(); - break; - case UNAUTHORIZED: - _debug("Request is unauthorized. SIP Server ask authentification: logging...\n"); - setAuthentication(); - break; - - case BAD_REQ: - case FORBIDDEN: - case NOT_FOUND: - case NOT_ALLOWED: - case NOT_ACCEPTABLE: - case REQ_TIMEOUT: - case TEMP_UNAVAILABLE: - case ADDR_INCOMPLETE: - case NOT_ACCEPTABLE_HERE: // 488 - // Display error on the screen phone - //Manager::instance().displayError(event->response->reason_phrase); - id = findCallId(event); - Manager::instance().displayErrorText(id, event->response->reason_phrase); - Manager::instance().callFailure(id); - deleteSipCall(id); - break; - case BUSY_HERE: - id = findCallId(event); - Manager::instance().displayErrorText(id, event->response->reason_phrase); - Manager::instance().callBusy(id); - deleteSipCall(id); - break; - case REQ_TERMINATED: - break; - default: - // sipphone.com send 478 Unresolveable destination (478/TM) - id = findCallId(event); - Manager::instance().displayErrorText(id, event->response->reason_phrase); - Manager::instance().callFailure(id); - deleteSipCall(id); - break; - } - - break; - - case EXOSIP_CALL_SERVERFAILURE: - // Handle 5XX errors - switch (event->response->status_code) { - case SERVICE_UNAVAILABLE: - id = findCallId(event); - Manager::instance().callFailure(id); - break; - default: - break; - } - break; - - case EXOSIP_CALL_GLOBALFAILURE: - // Handle 6XX errors - switch (event->response->status_code) { - case BUSY_EVERYWHERE: - case DECLINE: - id = findCallId(event); - Manager::instance().callFailure(id); - break; - default: - break; - } - break; - - case EXOSIP_CALL_MESSAGE_NEW: // 18 - if (0 == event->request) break; - if (MSG_IS_INFO(event->request)) { - _debug("Receive a call message request info\n"); - osip_content_type_t* c_t = event->request->content_type; - if (c_t != 0 && c_t->type != 0 && c_t->subtype != 0 ) { - _debug(" Content Type of the message: %s/%s\n", c_t->type, c_t->subtype); - // application/dtmf-relay - if (strcmp(c_t->type, "application") == 0 && strcmp(c_t->subtype, "dtmf-relay") == 0) { - handleDtmfRelay(event); - } - } - } - - osip_message_t *answerOKNewMessage; - eXosip_lock(); - if ( 0 == eXosip_call_build_answer(event->tid, OK, &answerOKNewMessage)) { - _debug("< Sending 200 OK\n"); - eXosip_call_send_answer(event->tid, OK, answerOKNewMessage); - } else { - _debug("Could not sent an OK message\n"); - } - eXosip_unlock(); - break; - - case EXOSIP_REGISTRATION_SUCCESS: // 1 - // Manager::instance().displayStatus(LOGGED_IN_STATUS); - Manager::instance().registrationSucceed(); - break; - - case EXOSIP_REGISTRATION_FAILURE: // 2 - //Manager::instance().displayError("getEvent : Registration Failure"); - Manager::instance().registrationFailed(); - break; - - case EXOSIP_MESSAGE_NEW: //27 - - if ( event->request == NULL) { - break; // do nothing - } - unsigned int k; - - if (MSG_IS_OPTIONS(event->request)) { - for (k = 0; k < _sipcallVector.size(); k++) { - if (_sipcallVector.at(k)->getCid() == event->cid) { - break; - } - } - - // TODO: Que faire si rien trouve?? - eXosip_lock(); - if (k == _sipcallVector.size()) { - /* answer 200 ok */ - eXosip_options_send_answer (event->tid, OK, NULL); - - } else if (_sipcallVector.at(k)->getCid() == event->cid) { - /* already answered! */ - } else { - /* answer 486 ok */ - eXosip_options_send_answer (event->tid, BUSY_HERE, NULL); - } - eXosip_unlock(); - } - - // Voice message - else if (MSG_IS_NOTIFY(event->request)){ - _debug("> NOTIFY Voice message\n"); - int ii; - unsigned int pos; - unsigned int pos_slash; - - osip_body_t *body = NULL; - // Get the message body - ii = osip_message_get_body(event->request, 0, &body); - if (ii != 0) { - _debug(" Cannot get body in a new EXOSIP_MESSAGE_NEW event\n"); - returnValue = EXOSIP_ERROR_STD; - break; - } - - // Analyse message body - if (!body || !body->body) { - returnValue = EXOSIP_ERROR_STD; - break; - } - std::string str(body->body); - pos = str.find(VOICE_MSG); - - if (pos == std::string::npos) { - // If the string is not found - returnValue = EXOSIP_ERROR_STD; - break; - } - - pos_slash = str.find ("/"); - std::string nb_msg = str.substr(pos + LENGTH_VOICE_MSG, - pos_slash - (pos + LENGTH_VOICE_MSG)); - - // Set the number of voice-message - setMsgVoicemail(atoi(nb_msg.data())); - - if (getMsgVoicemail() != 0) { - // If there is at least one voice-message, start notification - Manager::instance().startVoiceMessageNotification(nb_msg); - } else { - // Stop notification when there is 0 voice message - Manager::instance().stopVoiceMessageNotification(); - } - // http://www.jdrosen.net/papers/draft-ietf-simple-im-session-00.txt - } else if (MSG_IS_MESSAGE(event->request)) { - _debug("> MESSAGE received\n"); - // osip_content_type_t* osip_message::content_type - osip_content_type_t* c_t = event->request->content_type; - if (c_t != 0 && c_t->type != 0 && c_t->subtype != 0 ) { - _debug(" Content Type of the message: %s/%s\n", c_t->type, c_t->subtype); - - osip_body_t *body = NULL; - // Get the message body - if (0 == osip_message_get_body(event->request, 0, &body)) { - _debug(" Body length: %d\n", body->length); - if (body->body!=0 && - strcmp(c_t->type,"text") == 0 && - strcmp(c_t->subtype,"plain") == 0 - ) { - _debug(" Text body: %s\n", body->body); - Manager::instance().incomingMessage(body->body); - } - } - } - osip_message_t *answerOK; - eXosip_lock(); - if ( 0 == eXosip_message_build_answer(event->tid, OK, &answerOK)) { - _debug("< Sending 200 OK\n"); - eXosip_message_send_answer(event->tid, OK, answerOK); - } - eXosip_unlock(); - } - break; - - case EXOSIP_MESSAGE_REQUESTFAILURE: // 31 - // 405 Method Not Allowed - if (event->response != 0 && event->response->status_code == SIP_METHOD_NOT_ALLOWED) { -// setAllows(event); -// AllowList::iterator iter = _allowList.find(std::string("MESSAGE")); -// if (iter==_allowList.end()) { - Manager::instance().incomingMessage("Message are not allowed"); -// } - } - break; - - case EXOSIP_SUBSCRIPTION_ANSWERED: // 38 - eXosip_lock(); - eXosip_automatic_action(); - eXosip_unlock(); - break; - - case EXOSIP_SUBSCRIPTION_REQUESTFAILURE: //40 - break; - - default: - returnValue = EXOSIP_ERROR_STD; - break; - } - eXosip_event_free(event); - - return returnValue; -} - -int -SipVoIPLink::getLocalPort (void) -{ - return _localPort; + return true; } -void -SipVoIPLink::setLocalPort (int port) +bool +SIPVoIPLink::carryingDTMFdigits(const CallID& id, char code) { - _localPort = port; -} - -void -SipVoIPLink::carryingDTMFdigits (CALLID id, char code) { - SipCall* sipcall = getSipCall(id); - if (sipcall == 0) { return; } + SIPCall* call = getSIPCall(id); + if (call==0) { _debug("Call doesn't exist\n"); return false; } int duration = Manager::instance().getConfigInt(SIGNALISATION, PULSE_LENGTH); osip_message_t *info; @@ -1127,438 +798,666 @@ SipVoIPLink::carryingDTMFdigits (CALLID id, char code) { eXosip_lock(); // Build info request - i = eXosip_call_build_info (getSipCall(id)->getDid(), &info); + i = eXosip_call_build_info(call->getDid(), &info); if (i == 0) { - snprintf(dtmf_body, body_len - 1, "Signal=%c\r\nDuration=%d\r\n", - code, duration); + snprintf(dtmf_body, body_len - 1, "Signal=%c\r\nDuration=%d\r\n", code, duration); osip_message_set_content_type (info, "application/dtmf-relay"); osip_message_set_body (info, dtmf_body, strlen (dtmf_body)); // Send info request - i = eXosip_call_send_request(sipcall->getDid(), info); + i = eXosip_call_send_request(call->getDid(), info); } eXosip_unlock(); - + delete[] dtmf_body; dtmf_body = NULL; -} - -void -SipVoIPLink::newOutgoingCall (CALLID id) -{ - SipCall* sipcall = new SipCall(id, Manager::instance().getCodecDescriptorMap()); - if (sipcall != NULL) { - _sipcallVector.push_back(sipcall); - sipcall->setStandBy(true); - } + return true; } -void -SipVoIPLink::newIncomingCall (CALLID id) +bool +SIPVoIPLink::sendMessage(const std::string& to, const std::string& body) { - SipCall* sipcall = new SipCall(id, Manager::instance().getCodecDescriptorMap()); - if (sipcall != NULL) { - _sipcallVector.push_back(sipcall); - } -} + bool returnValue = false; -void -SipVoIPLink::deleteSipCall (CALLID id) -{ - std::vector< SipCall* >::iterator iter = _sipcallVector.begin(); + // fast return + if (body.empty()) {return returnValue; } - while(iter != _sipcallVector.end()) { - if (*iter && (*iter)->getId() == id) { - delete *iter; *iter = NULL; - _sipcallVector.erase(iter); - return; - } - iter++; + osip_message_t* message = 0; + const char* method = "MESSAGE"; + + std::string sipFrom = getSipFrom(); + std::string sipTo = getSipTo(to); + std::string sipRoute = getSipRoute(); + + if (!SIPCheckUrl(sipFrom)) { + Manager::instance().displayConfigError("Error in source address"); + return returnValue; + } + if (!SIPCheckUrl(sipTo)) { + Manager::instance().displayError("Error in destination address"); + return returnValue; } -} -void -SipVoIPLink::endSipCalls() -{ - std::vector< SipCall* >::iterator iter = _sipcallVector.begin(); - while(iter != _sipcallVector.end()) { - if ( *iter ) { + int eXosipError = EXOSIP_ERROR_STD; + eXosip_lock(); + if ( sipRoute.empty() ) { + eXosipError = eXosip_message_build_request(&message, method, sipTo.c_str(), sipFrom.c_str(), NULL); + } else { + eXosipError = eXosip_message_build_request(&message, method, sipTo.c_str(), sipFrom.c_str(), sipRoute.c_str()); + } - // Release SIP stack. - eXosip_lock(); - eXosip_call_terminate ((*iter)->getCid(), (*iter)->getDid()); - eXosip_unlock(); + if (eXosipError == EXOSIP_ERROR_NO) { + // add body + // add message + // src: http://www.atosc.org/pipermail/public/osip/2005-October/006007.html + osip_message_set_expires(message, "120"); + osip_message_set_body(message, body.c_str(), body.length()); + osip_message_set_content_type(message, "text/plain"); - // Release RTP channels - _audiortp.closeRtpSession(); - delete *iter; *iter = NULL; + eXosipError = eXosip_message_send_request(message); + if (eXosipError == EXOSIP_ERROR_NO) { + // correctly send the message + returnValue = true; } - iter++; } - _sipcallVector.clear(); + eXosip_unlock(); + return returnValue; } -SipCall* -SipVoIPLink::getSipCall (CALLID id) +bool +SIPVoIPLink::SIPOutgoingInvite(SIPCall* call) { - SipCall* sipcall = NULL; - for (unsigned int i = 0; i < _sipcallVector.size(); i++) { - sipcall = _sipcallVector.at(i); - if (sipcall && sipcall->getId() == id) { - return sipcall; - } + // If no SIP proxy setting for direct call with only IP address + if (!SIPStartCall(call, "")) { + _debug("SIP Failure: call not started\n"); + return false; } - return NULL; + return true; } -AudioCodec* -SipVoIPLink::getAudioCodec (CALLID id) +bool +SIPVoIPLink::SIPStartCall(SIPCall* call, const std::string& subject) { - SipCall* sipcall = getSipCall(id); - if (sipcall != NULL) { - return sipcall->getAudioCodec(); - } else { - return NULL; + if (!call) return false; + + std::string to = getSipTo(call->getPeerNumber()); + std::string from = getSipFrom(); + std::string route = getSipRoute(); + _debug(" From: %s\n", from.data()); + _debug(" Route: %s\n", route.data()); + + if (!SIPCheckUrl(from)) { + _debug("SIP Error: Source address is invalid %s\n", from.data()); + Manager::instance().displayConfigError("Error in source address"); + return false; + } + if (!SIPCheckUrl(to)) { + Manager::instance().displayErrorText(call->getCallId(), "Error in destination address"); + return false; } -} -/////////////////////////////////////////////////////////////////////////////// -// Private functions -/////////////////////////////////////////////////////////////////////////////// -int -SipVoIPLink::sdp_hold_call (sdp_message_t * sdp) -{ - int pos; - int pos_media = -1; - char *rcvsnd; - int recv_send = -1; - pos = 0; - rcvsnd = sdp_message_a_att_field_get (sdp, pos_media, pos); - while (rcvsnd != NULL) { - if (rcvsnd != NULL && 0 == strcmp (rcvsnd, "sendonly")) { - recv_send = 0; - } else if (rcvsnd != NULL && (0 == strcmp (rcvsnd, "recvonly") - || 0 == strcmp (rcvsnd, "sendrecv"))) { - recv_send = 0; - sprintf (rcvsnd, "sendonly"); - } - pos++; - rcvsnd = sdp_message_a_att_field_get (sdp, pos_media, pos); + osip_message_t *invite; + eXosip_lock(); + int eXosipError = eXosip_call_build_initial_invite (&invite, (char*)to.data(), + (char*)from.data(), + (char*)route.data(), + (char*)subject.data()); + + if (eXosipError != 0) { + eXosip_unlock(); + return false; // error when building the invite } - pos_media = 0; - while (!sdp_message_endof_media (sdp, pos_media)) { - pos = 0; - rcvsnd = sdp_message_a_att_field_get (sdp, pos_media, pos); - while (rcvsnd != NULL) { - if (rcvsnd != NULL && 0 == strcmp (rcvsnd, "sendonly")) { - recv_send = 0; - } else if (rcvsnd != NULL && (0 == strcmp (rcvsnd, "recvonly") - || 0 == strcmp (rcvsnd, "sendrecv"))) { - recv_send = 0; - sprintf (rcvsnd, "sendonly"); + setCallAudioLocal(call); + + std::ostringstream media_audio; + std::ostringstream rtpmap_attr; + int payload; + int nbChannel; + + // Set rtpmap according to the supported codec order + CodecMap map = call->getCodecMap().getMap(); + CodecMap::iterator iter = map.begin(); + + while(iter != map.end()) { + if (iter->second!=0 && iter->second->isActive()) { + payload = iter->first; + // add each payload in the list of payload + media_audio << payload << " "; + + rtpmap_attr << "a=rtpmap: " << payload << " " << + iter->second->getCodecName().data() << "/" << iter->second->getClockRate(); + + nbChannel = iter->second->getChannel(); + if (nbChannel!=1) { + rtpmap_attr << "/" << nbChannel; } - pos++; - rcvsnd = sdp_message_a_att_field_get (sdp, pos_media, pos); + rtpmap_attr << "\r\n"; } - pos_media++; + // go to next codec + iter++; } - if (recv_send == -1) { - /* we need to add a global attribute with a field set to "sendonly" */ - sdp_message_a_attribute_add (sdp, -1, osip_strdup ("sendonly"), NULL); + // http://www.antisip.com/documentation/eXosip2/group__howto1__initialize.html + // tell sip if we support SIP extension like 100rel + // osip_message_set_supported (invite, "100rel"); + + /* add sdp body */ + { + char tmp[4096]; + snprintf (tmp, 4096, + "v=0\r\n" + "o=SFLphone 0 0 IN IP4 %s\r\n" + "s=call\r\n" + "c=IN IP4 %s\r\n" + "t=0 0\r\n" + "m=audio %d RTP/AVP %s\r\n" + "%s", + _localExternAddress.c_str(), _localExternAddress.c_str(), call->getLocalExternAudioPort(), media_audio.str().c_str(), rtpmap_attr.str().c_str()); + // media_audio should be one, two or three numbers? + osip_message_set_body (invite, tmp, strlen (tmp)); + osip_message_set_content_type (invite, "application/sdp"); + _debug("SDP send: %s", tmp); } + + _debug("> INVITE To <%s>\n", to.data()); + int cid = eXosip_call_send_initial_invite(invite); - return 0; + // Keep the cid in case of cancelling + call->setCid(cid); + + if (cid <= 0) { + eXosip_unlock(); + return false ; + } else { + _debug("SIP Info: Outgoing callID is %s, cid=%d\n", call->getCallId().data(), cid); + eXosip_call_set_reference (cid, NULL); + } + eXosip_unlock(); + + return true; } -int -SipVoIPLink::sdp_off_hold_call (sdp_message_t * sdp) -{ - int pos; - int pos_media = -1; - char *rcvsnd; +/** + * Get the Sip FROM url (add sip:, add @host, etc...) + */ +std::string +SIPVoIPLink::getSipFrom() { - pos = 0; - rcvsnd = sdp_message_a_att_field_get (sdp, pos_media, pos); - while (rcvsnd != NULL) { - if (rcvsnd != NULL && (0 == strcmp (rcvsnd, "sendonly") - || 0 == strcmp (rcvsnd, "recvonly"))) { - sprintf (rcvsnd, "sendrecv"); - } - pos++; - rcvsnd = sdp_message_a_att_field_get (sdp, pos_media, pos); + // Form the From header field basis on configuration panel + std::string host = getHostName(); + if ( host.empty() ) { + host = _localIPAddress; } + return SIPFromHeader(_userpart, host); +} - pos_media = 0; - while (!sdp_message_endof_media (sdp, pos_media)) { - pos = 0; - rcvsnd = sdp_message_a_att_field_get (sdp, pos_media, pos); - while (rcvsnd != NULL) { - if (rcvsnd != NULL && (0 == strcmp (rcvsnd, "sendonly") - || 0 == strcmp (rcvsnd, "recvonly"))) { - sprintf (rcvsnd, "sendrecv"); - } - pos++; - rcvsnd = sdp_message_a_att_field_get (sdp, pos_media, pos); +/** + * Get the Sip TO url (add sip:, add @host, etc...) + */ +std::string +SIPVoIPLink::getSipTo(const std::string& to_url) { + // Form the From header field basis on configuration panel + bool isRegistered = (_eXosipRegID == EXOSIP_ERROR_STD) ? false : true; + + // add a @host if we are registered and there is no one inside the url + if (to_url.find("@") == std::string::npos && isRegistered) { + std::string host = getHostName(); + if(!host.empty()) { + return SIPToHeader(to_url + "@" + host); } - pos_media++; } - - return 0; + return SIPToHeader(to_url); } -bool -SipVoIPLink::behindNat(int port) -{ - StunAddress4 stunSvrAddr; - stunSvrAddr.addr = 0; - - // Stun server - std::string svr = Manager::instance().getConfigString(SIGNALISATION, STUN_SERVER); - - // Convert char* to StunAddress4 structure - bool ret = stunParseServerName ((char*)svr.data(), stunSvrAddr); - if (!ret) { - _debug("SIP: Stun server address (%s) is not valid\n", svr.data()); - return 0; +/** + * Get the sip proxy (add sip: if there is one) + * @return empty string or <sip:proxy;lr> url + */ +std::string +SIPVoIPLink::getSipRoute() { + std::string proxy = _proxy; + if ( !proxy.empty() ) { + proxy = "<sip:" + proxy + ";lr>"; } - - // Firewall address - //_debug("STUN server: %s\n", svr.data()); - return Manager::instance().getStunInfo(stunSvrAddr, port); + return proxy; // return empty } -/** - * Get the local Ip by eXosip - * only if the local ip address is to his default value: 127.0.0.1 - * setLocalIpAdress - * @return false if not found - */ -bool -SipVoIPLink::getSipLocalIp (void) +std::string +SIPVoIPLink::SIPToHeader(const std::string& to) { - bool returnValue = true; - if (getLocalIpAddress() == "127.0.0.1") { - char* myIPAddress = new char[65]; - if (eXosip_guess_localip(AF_INET, myIPAddress, 64) == -1) { - returnValue = false; - } else { - setLocalIpAddress(std::string(myIPAddress)); - _debug("Checking network, setting local ip address to: %s\n", myIPAddress); - } - delete [] myIPAddress; myIPAddress = NULL; + if (to.find("sip:") == std::string::npos) { + return ("sip:" + to ); + } else { + return to; } - return returnValue; } -int -SipVoIPLink::checkUrl (const std::string& url) +bool +SIPVoIPLink::SIPCheckUrl(const std::string& url) { int i; - + osip_from_t *to; i = osip_from_init(&to); if (i != 0) { - _debug("Warning: Cannot initialize\n"); - return EXOSIP_ERROR_STD; + _debug("SIP Warning: Cannot initialize osip parser\n"); + return false; } i = osip_from_parse(to, url.data()); if (i != 0) { - _debug("Warning: Cannot parse url\n"); - return EXOSIP_ERROR_STD; + _debug("SIP Warning: Cannot parse url %s\n", url.data()); + return false; } // Free memory osip_from_free (to); - return 0; + return true; } -int -SipVoIPLink::setAuthentication (void) +bool +SIPVoIPLink::setCallAudioLocal(SIPCall* call) { - ManagerImpl& manager = Manager::instance(); - std::string login = manager.getConfigString(SIGNALISATION, AUTH_USER_NAME); - if (login.empty()) { - login = manager.getConfigString(SIGNALISATION, USER_PART); - } - std::string pass = manager.getConfigString(SIGNALISATION, PASSWORD); - if (pass.empty()) { - manager.displayConfigError("Fill password field"); - return EXOSIP_ERROR_STD; + // Setting Audio + unsigned int callLocalAudioPort = RANDOM_LOCAL_PORT; + unsigned int callLocalExternAudioPort = callLocalAudioPort; + if (_useStun) { + // If use Stun server + if (Manager::instance().behindNat(callLocalAudioPort)) { + callLocalExternAudioPort = Manager::instance().getFirewallPort(); + } } - eXosip_lock(); + _debug(" Setting local audio port to: %d\n", callLocalAudioPort); + _debug(" Setting local audio port (external) to: %d\n", callLocalExternAudioPort); + + // Set local audio port for SIPCall(id) + call->setLocalIp(_localIPAddress); + call->setLocalAudioPort(callLocalAudioPort); + call->setLocalExternAudioPort(callLocalExternAudioPort); - int returnValue = eXosip_add_authentication_info(login.data(), login.data(), pass.data(), NULL, NULL); - eXosip_unlock(); + return true; +} - return returnValue; +void +SIPVoIPLink::SIPCallInvite(eXosip_event_t *event) +{ + _debug("> INVITE (receive)\n"); + + CallID id = Manager::instance().getNewCallID(); + + SIPCall* call = new SIPCall(id, Call::Incoming); + if (!call) { + _debug("SIP Failure: unable to create an incoming call"); + return; + } + setCallAudioLocal(call); + call->setConnectionState(Call::Progressing); + if (call->SIPCallInvite(event)) { + if (Manager::instance().incomingCall(call, getAccountID())) { + addCall(call); + } else { + delete call; call = 0; + } + } else { + delete call; call = 0; + } } -std::string -SipVoIPLink::fromHeader (const std::string& user, const std::string& host) +void +SIPVoIPLink::SIPCallReinvite(eXosip_event_t *event) { - std::string displayname = Manager::instance().getConfigString(SIGNALISATION, -FULL_NAME); - return ("\"" + displayname + "\"" + " <sip:" + user + "@" + host + ">"); + _debug("> REINVITE (receive)\n"); + SIPCall* call = findSIPCallWithCidDid(event->cid, event->did); + if (call == 0) { + _debug("SIP Failure: unknown call\n"); + _debug("< Send 488 Not Acceptable Here"); + eXosip_lock(); + eXosip_call_send_answer(event->tid, 488, NULL); + eXosip_unlock(); + return; + } + if ( call->getCallId() == Manager::instance().getCurrentCallId()) { + // STOP tone + Manager::instance().stopTone(); + // STOP old rtp session + _audiortp.closeRtpSession(); + call->setAudioStart(false); + } + call->SIPCallReinvite(event); } +void +SIPVoIPLink::SIPCallRinging(eXosip_event_t *event) +{ + SIPCall* call = findSIPCallWithCidDid(event->cid, event->did); + if (!call) { + _debug("SIP Failure: unknown call\n"); + return; + } + // we could set the cid/did/tid and get the FROM here... + // but we found the call with the cid/did already, why setting it again? + // call->ringingCall(event); + call->setConnectionState(Call::Ringing); + Manager::instance().peerRingingCall(call->getCallId()); +} -std::string -SipVoIPLink::toHeader(const std::string& to) +void +SIPVoIPLink::SIPCallAnswered(eXosip_event_t *event) { - if (to.find("sip:") == std::string::npos) { - return ("sip:" + to ); + SIPCall* call = findSIPCallWithCid(event->cid); + if (!call) { + _debug("SIP Failure: unknown call\n"); + return; + } + call->setDid(event->did); + + if (call->getConnectionState() != Call::Connected) { + call->SIPCallAnswered(event); + call->SIPCallAnsweredWithoutHold(event); + + call->setConnectionState(Call::Connected); + call->setState(Call::Active); + + Manager::instance().peerAnsweredCall(call->getCallId()); + if (Manager::instance().isCurrentCall(call->getCallId())) { + _debug("SIP: Starting AudioRTP\n"); + if ( _audiortp.createNewSession(call) < 0) { + _debug("RTP Failure: unable to create new session\n"); + } else { + call->setAudioStart(true); + } + } } else { - return to; + _debug("Answering call (on/off hold to send ACK)\n"); + call->SIPCallAnswered(event); } } -int -SipVoIPLink::startCall(CALLID id, const std::string& from, const std::string& to, const std::string& subject, const std::string& route) +void +SIPVoIPLink::SIPCallRequestFailure(eXosip_event_t *event) { - SipCall* sipcall = getSipCall(id); - if ( sipcall == NULL) { - return -1; // error, we can't find the sipcall + if (!event->response) { return; } + // 404 error + _debug("SIP Event: Request Failure, receive code %d\n", event->response->status_code); + // Handle 4XX errors + switch (event->response->status_code) { + case SIP_PROXY_AUTHENTICATION_REQUIRED: + _debug("SIP Server ask required authentification: logging...\n"); + sendSIPAuthentification(); + eXosip_lock(); + eXosip_automatic_action(); + eXosip_unlock(); + break; + case SIP_UNAUTHORIZED: + _debug("Request is unauthorized. SIP Server ask authentification: logging...\n"); + sendSIPAuthentification(); + break; + + case SIP_BUSY_HERE: // 486 + { + SIPCall* call = findSIPCallWithCid(event->cid); + if (call!=0) { + CallID& id = call->getCallId(); + call->setConnectionState(Call::Connected); + call->setState(Call::Busy); + Manager::instance().displayErrorText(id, event->response->reason_phrase); + Manager::instance().callBusy(id); + removeCall(id); + } + } + break; + case SIP_REQUEST_TERMINATED: // 487 + break; + + default: + /*case SIP_BAD_REQUEST: + case SIP_FORBIDDEN: + case SIP_NOT_FOUND: + case SIP_METHOD_NOT_ALLOWED: + case SIP_406_NOT_ACCEPTABLE: + case SIP_REQ_TIME_OUT: + case SIP_TEMPORARILY_UNAVAILABLE: + case SIP_ADDRESS_INCOMPLETE: + case SIP_NOT_ACCEPTABLE_HERE: // 488 */ + // Display error on the screen phone + { + SIPCall* call = findSIPCallWithCid(event->cid); + if (call!=0) { + CallID& id = call->getCallId(); + call->setConnectionState(Call::Connected); + call->setState(Call::Error); + Manager::instance().displayErrorText(id, event->response->reason_phrase); + Manager::instance().callFailure(id); + removeCall(id); + } + } } - osip_message_t *invite; +} - if (checkUrl(from) != 0) { - Manager::instance().displayConfigError("Error in source address"); - return -1; +void +SIPVoIPLink::SIPCallServerFailure(eXosip_event_t *event) +{ + if (!event->response) { return; } + switch(event->response->status_code) { + case SIP_SERVICE_UNAVAILABLE: // 500 + case SIP_BUSY_EVRYWHERE: // 600 + case SIP_DECLINE: // 603 + SIPCall* call = findSIPCallWithCid(event->cid); + if (call != 0) { + CallID id = call->getCallId(); + Manager::instance().callFailure(id); + removeCall(id); + } + break; } - if (checkUrl(to) != 0) { - Manager::instance().displayErrorText(id, "Error in destination address"); - return -1; +} + +void +SIPVoIPLink::SIPCallAck(eXosip_event_t *event) +{ + SIPCall* call = findSIPCallWithCidDid(event->cid, event->did); + if (!call) { return; } + if (!call->isAudioStarted()) { + if (Manager::instance().isCurrentCall(call->getCallId())) { + _debug(" Starting AudioRTP\n"); + if ( _audiortp.createNewSession(call) ) { + call->setAudioStart(true); + } + } } - - if (!Manager::instance().useStun()) { - // Set random port for outgoing call if no firewall - setLocalPort(RANDOM_LOCAL_PORT); - _debug(" Setting local port to random: %d\n",_localPort); - } else { - // If use Stun server - if (behindNat(_localPort)) { - setLocalIpAddress(Manager::instance().getFirewallAddress()); - setLocalPort(Manager::instance().getFirewallPort()); - _debug(" Setting local port to firewall port: %d\n", _localPort); - } else { - return -1; +} + +void +SIPVoIPLink::SIPCallMessageNew(eXosip_event_t *event) +{ + if (0 == event->request) return; + + _debug("Receive a call message\n"); + + if (MSG_IS_INFO(event->request)) { + _debug("It's a Request Info\n"); + osip_content_type_t* c_t = event->request->content_type; + if (c_t != 0 && c_t->type != 0 && c_t->subtype != 0 ) { + _debug(" Content Type of the message: %s/%s\n", c_t->type, c_t->subtype); + // application/dtmf-relay + if (strcmp(c_t->type, "application") == 0 && strcmp(c_t->subtype, "dtmf-relay") == 0) { + handleDtmfRelay(event); + } } } - - // Set local audio port for sipcall(id) - sipcall->setLocalIp(getLocalIpAddress()); - sipcall->setLocalAudioPort(_localPort); + osip_message_t *answerOKNewMessage; eXosip_lock(); - int i = eXosip_call_build_initial_invite (&invite, (char*)to.data(), - (char*)from.data(), - (char*)route.data(), - (char*)subject.data()); - - if (i != 0) { - eXosip_unlock(); - return EXOSIP_ERROR_STD; // error when building the invite + if ( 0 == eXosip_call_build_answer(event->tid, SIP_OK, &answerOKNewMessage)) { + _debug("< Sending 200 OK\n"); + eXosip_call_send_answer(event->tid, SIP_OK, answerOKNewMessage); + } else { + _debug("SIP Failure: Could not sent an OK message\n"); } + eXosip_unlock(); - std::ostringstream media_audio; - std::ostringstream rtpmap_attr; - int payload; - int nbChannel; +} - // Set rtpmap according to the supported codec order - CodecMap map = Manager::instance().getCodecDescriptorMap().getMap(); - CodecMap::iterator iter = map.begin(); +void +SIPVoIPLink::SIPCallClosed(eXosip_event_t *event) +{ + // it was without did before + SIPCall* call = findSIPCallWithCid(event->cid); + if (!call) { return; } + + CallID id = call->getCallId(); + call->setDid(event->did); + if (Manager::instance().isCurrentCall(id)) { + call->setAudioStart(false); + _audiortp.closeRtpSession(); + } + Manager::instance().peerHungupCall(id); + removeCall(id); +} - while(iter != map.end()) { - if (iter->second!=0 && iter->second->isActive()) { - payload = iter->first; - // add each payload in the list of payload - media_audio << payload << " "; +void +SIPVoIPLink::SIPCallReleased(eXosip_event_t *event) +{ + // do cleanup if exists + // only cid because did is always 0 in these case.. + SIPCall* call = findSIPCallWithCid(event->cid); + if (!call) { return; } + + // if we are here.. something when wrong before... + CallID id = call->getCallId(); + Manager::instance().callFailure(id); + removeCall(id); +} - rtpmap_attr << "a=rtpmap: " << payload << " " << - iter->second->getCodecName().data() << "/" << iter->second->getClockRate(); +void +SIPVoIPLink::SIPMessageNew(eXosip_event_t *event) +{ + if (MSG_IS_OPTIONS(event->request)) { + // old handling was + // - send 200 OK if call id is not found + // - send nothing if call id is found + eXosip_lock(); + eXosip_options_send_answer (event->tid, SIP_OK, NULL); + eXosip_unlock(); + } + // Voice message + else if (MSG_IS_NOTIFY(event->request)){ + _debug("> NOTIFY Voice message\n"); + int ii; + unsigned int pos; + unsigned int pos_slash; + + osip_body_t *body = NULL; + // Get the message body + ii = osip_message_get_body(event->request, 0, &body); + if (ii != 0) { + _debug(" Cannot get body in a new EXOSIP_MESSAGE_NEW event\n"); + return; + } - nbChannel = iter->second->getChannel(); - if (nbChannel!=1) { - rtpmap_attr << "/" << nbChannel; - } - rtpmap_attr << "\r\n"; + // Analyse message body + if (!body || !body->body) { + return; } - // go to next codec - iter++; - } + std::string str(body->body); + pos = str.find(VOICE_MSG); - // http://www.antisip.com/documentation/eXosip2/group__howto1__initialize.html - // tell sip if we support SIP extension like 100rel - // osip_message_set_supported (invite, "100rel"); + if (pos == std::string::npos) { + // If the string is not found + return; + } - /* add sdp body */ - { - char tmp[4096]; - snprintf (tmp, 4096, - "v=0\r\n" - "o=SFLphone 0 0 IN IP4 %s\r\n" - "s=call\r\n" - "c=IN IP4 %s\r\n" - "t=0 0\r\n" - "m=audio %d RTP/AVP %s\r\n" - "%s", - getLocalIpAddress().c_str(), getLocalIpAddress().c_str(), getLocalPort(), media_audio.str().c_str(), rtpmap_attr.str().c_str()); - // media_audio should be one, two or three numbers? - osip_message_set_body (invite, tmp, strlen (tmp)); - osip_message_set_content_type (invite, "application/sdp"); - _debug("SDP send: %s", tmp); - } - - // this is the cid (call id from exosip) - _debug("%10d: Receive INVITE\n", id); - int cid = eXosip_call_send_initial_invite (invite); - _debug(" Local IP:port: %s:%d\n", getLocalIpAddress().c_str(), getLocalPort()); + pos_slash = str.find ("/"); + std::string nb_msg = str.substr(pos + LENGTH_VOICE_MSG, + pos_slash - (pos + LENGTH_VOICE_MSG)); - // Keep the cid in case of cancelling - sipcall->setCid(cid); + // Set the number of voice-message + int msgVoicemail = atoi(nb_msg.data()); - if (cid <= 0) { + if (msgVoicemail != 0) { + // If there is at least one voice-message, start notification + Manager::instance().startVoiceMessageNotification(getAccountID(), nb_msg); + } else { + // Stop notification when there is 0 voice message + Manager::instance().stopVoiceMessageNotification(getAccountID()); + } + + // http://www.jdrosen.net/papers/draft-ietf-simple-im-session-00.txt + } else if (MSG_IS_MESSAGE(event->request)) { + _debug("> MESSAGE received\n"); + // osip_content_type_t* osip_message::content_type + osip_content_type_t* c_t = event->request->content_type; + if (c_t != 0 && c_t->type != 0 && c_t->subtype != 0 ) { + _debug(" Content Type of the message: %s/%s\n", c_t->type, c_t->subtype); + + osip_body_t *body = NULL; + // Get the message body + if (0 == osip_message_get_body(event->request, 0, &body)) { + _debug(" Body length: %d\n", body->length); + if (body->body!=0 && + strcmp(c_t->type,"text") == 0 && + strcmp(c_t->subtype,"plain") == 0 + ) { + _debug(" Text body: %s\n", body->body); + Manager::instance().incomingMessage(getAccountID(), body->body); + } + } + } + osip_message_t *answerOK; + eXosip_lock(); + if ( 0 == eXosip_message_build_answer(event->tid, SIP_OK, &answerOK)) { + _debug("< Sending 200 OK\n"); + eXosip_message_send_answer(event->tid, SIP_OK, answerOK); + } eXosip_unlock(); - return EXOSIP_ERROR_STD; - } else { - eXosip_call_set_reference (cid, NULL); } - eXosip_unlock(); - return cid; // this is the Cid } -CALLID -SipVoIPLink::findCallId (eXosip_event_t *e) +SIPCall* +SIPVoIPLink::findSIPCallWithCid(int cid) { - for (unsigned int k = 0; k < _sipcallVector.size(); k++) { - SipCall* sipcall = _sipcallVector.at(k); - if (sipcall && sipcall->getCid() == e->cid && - sipcall->getDid() == e->did) { - return sipcall->getId(); + if (cid < 1) { + _debug("Not enough information for this event\n"); + return 0; + } + ost::MutexLock m(_callMapMutex); + SIPCall* call = 0; + CallMap::iterator iter = _callMap.begin(); + while(iter != _callMap.end()) { + call = dynamic_cast<SIPCall*>(iter->second); + if (call && call->getCid() == cid) { + return call; } + iter++; } return 0; } -/** - * This function is used when findCallId failed (return 0) - * ie: the dialog id change - * can be use when anwsering a new call or - * when cancelling a call - */ -CALLID -SipVoIPLink::findCallIdInitial (eXosip_event_t *e) +SIPCall* +SIPVoIPLink::findSIPCallWithCidDid(int cid, int did) { - for (unsigned int k = 0; k < _sipcallVector.size(); k++) { - SipCall* sipcall = _sipcallVector.at(k); - // the dialog id is not set when you do a new call - // so you can't check it when you want to retreive it - // for the first call anwser - if (sipcall && sipcall->getCid() == e->cid) { - return sipcall->getId(); + if (cid < 1 && did < -1) { + _debug("Not enough information for this event\n"); + return 0; + } + ost::MutexLock m(_callMapMutex); + SIPCall* call = 0; + CallMap::iterator iter = _callMap.begin(); + while(iter != _callMap.end()) { + call = dynamic_cast<SIPCall*>(iter->second); + if (call && call->getCid() == cid && call->getDid() == did) { + return call; } + iter++; + } + return 0; +} + +SIPCall* +SIPVoIPLink::getSIPCall(const CallID& id) +{ + Call* call = getCall(id); + if (call) { + return dynamic_cast<SIPCall*>(call); } return 0; } @@ -1568,7 +1467,12 @@ SipVoIPLink::findCallIdInitial (eXosip_event_t *e) * @param event eXosip Event */ bool -SipVoIPLink::handleDtmfRelay(eXosip_event_t* event) { +SIPVoIPLink::handleDtmfRelay(eXosip_event_t* event) { + + SIPCall* call = findSIPCallWithCidDid(event->cid, event->did); + if (call==0) { return false; } + + bool returnValue = false; osip_body_t *body = NULL; // Get the message body @@ -1591,9 +1495,9 @@ SipVoIPLink::handleDtmfRelay(eXosip_event_t* event) { _debug("Signal value: %s\n", signal.c_str()); if (!signal.empty()) { - unsigned int id = findCallId(event); - if (id !=0 && id == Manager::instance().getCurrentCallId()) { + if (Manager::instance().isCurrentCall(call->getCallId())) { Manager::instance().playDtmf(signal[0]); + returnValue = true; } } /* @@ -1616,77 +1520,89 @@ SipVoIPLink::handleDtmfRelay(eXosip_event_t* event) { return returnValue; } -// http://www.ietf.org/rfc/rfc3428.txt -// The size of MESSAGE requests outside of a media session MUST NOT -// exceed 1300 bytes, unless the UAC has positive knowledge that the -// message will not traverse a congestion-unsafe link at any hop, or -// that the message size is at least 200 bytes less than the lowest MTU -// value found en route to the UAS. -bool -SipVoIPLink::sendMessage(const std::string& to, const std::string& body) { - bool returnValue = false; - - // fast return - if (body.empty()) {return returnValue; } - - osip_message_t* message = 0; - const char* method = "MESSAGE"; - - std::string sipFrom = getSipFrom(); - std::string sipTo = getSipTo(to); - std::string sipRoute = getSipRoute(); +/////////////////////////////////////////////////////////////////////////////// +// Private functions +/////////////////////////////////////////////////////////////////////////////// +int +SIPVoIPLink::sdp_hold_call (sdp_message_t * sdp) +{ + int pos; + int pos_media = -1; + char *rcvsnd; + int recv_send = -1; - if (checkUrl(sipFrom) != 0) { - Manager::instance().displayConfigError("Error in source address"); - return returnValue; - } - if (checkUrl(sipTo) != 0) { - Manager::instance().displayError("Error in destination address"); - return returnValue; + pos = 0; + rcvsnd = sdp_message_a_att_field_get (sdp, pos_media, pos); + while (rcvsnd != NULL) { + if (rcvsnd != NULL && 0 == strcmp (rcvsnd, "sendonly")) { + recv_send = 0; + } else if (rcvsnd != NULL && (0 == strcmp (rcvsnd, "recvonly") + || 0 == strcmp (rcvsnd, "sendrecv"))) { + recv_send = 0; + sprintf (rcvsnd, "sendonly"); + } + pos++; + rcvsnd = sdp_message_a_att_field_get (sdp, pos_media, pos); } - int eXosipError = EXOSIP_ERROR_STD; - eXosip_lock(); - if ( sipRoute.empty() ) { - eXosipError = eXosip_message_build_request(&message, method, sipTo.c_str(), sipFrom.c_str(), NULL); - } else { - eXosipError = eXosip_message_build_request(&message, method, sipTo.c_str(), sipFrom.c_str(), sipRoute.c_str()); + pos_media = 0; + while (!sdp_message_endof_media (sdp, pos_media)) { + pos = 0; + rcvsnd = sdp_message_a_att_field_get (sdp, pos_media, pos); + while (rcvsnd != NULL) { + if (rcvsnd != NULL && 0 == strcmp (rcvsnd, "sendonly")) { + recv_send = 0; + } else if (rcvsnd != NULL && (0 == strcmp (rcvsnd, "recvonly") + || 0 == strcmp (rcvsnd, "sendrecv"))) { + recv_send = 0; + sprintf (rcvsnd, "sendonly"); + } + pos++; + rcvsnd = sdp_message_a_att_field_get (sdp, pos_media, pos); + } + pos_media++; } - if (eXosipError == EXOSIP_ERROR_NO) { - // add body - // add message - // src: http://www.atosc.org/pipermail/public/osip/2005-October/006007.html - osip_message_set_expires(message, "120"); - osip_message_set_body(message, body.c_str(), body.length()); - osip_message_set_content_type(message, "text/plain"); - - eXosipError = eXosip_message_send_request(message); - if (eXosipError == EXOSIP_ERROR_NO) { - // correctly send the message - returnValue = true; - } + if (recv_send == -1) { + /* we need to add a global attribute with a field set to "sendonly" */ + sdp_message_a_attribute_add (sdp, -1, osip_strdup ("sendonly"), NULL); } - eXosip_unlock(); - return returnValue; + + return 0; } -bool -SipVoIPLink::setAllows(eXosip_event_t *event) { - bool returnValue = false; +int +SIPVoIPLink::sdp_off_hold_call (sdp_message_t * sdp) +{ + int pos; + int pos_media = -1; + char *rcvsnd; - _allowList.clear(); + pos = 0; + rcvsnd = sdp_message_a_att_field_get (sdp, pos_media, pos); + while (rcvsnd != NULL) { + if (rcvsnd != NULL && (0 == strcmp (rcvsnd, "sendonly") + || 0 == strcmp (rcvsnd, "recvonly"))) { + sprintf (rcvsnd, "sendrecv"); + } + pos++; + rcvsnd = sdp_message_a_att_field_get (sdp, pos_media, pos); + } - if (event->response!=0 && event->response->allows!=0) { - int allowsSize = osip_list_size(event->response->allows); - if (allowsSize != 0) { returnValue = true;} - osip_allow_t *allows = 0; - for(int pos=0; pos<allowsSize; pos++) { - allows = (osip_allow_t*)osip_list_get(event->response->allows, pos); - if (allows!=0 && allows->value!=0) { - _allowList.push_back(std::string(allows->value)); + pos_media = 0; + while (!sdp_message_endof_media (sdp, pos_media)) { + pos = 0; + rcvsnd = sdp_message_a_att_field_get (sdp, pos_media, pos); + while (rcvsnd != NULL) { + if (rcvsnd != NULL && (0 == strcmp (rcvsnd, "sendonly") + || 0 == strcmp (rcvsnd, "recvonly"))) { + sprintf (rcvsnd, "sendrecv"); } + pos++; + rcvsnd = sdp_message_a_att_field_get (sdp, pos_media, pos); } + pos_media++; } - return returnValue; + + return 0; } diff --git a/src/sipvoiplink.h b/src/sipvoiplink.h index 392209dbab16f6552aae536acd485296a30a9a18..b9f87bab7582ae0722eae87e6116bac04ccfca12 100644 --- a/src/sipvoiplink.h +++ b/src/sipvoiplink.h @@ -1,10 +1,8 @@ /* - * Copyright (C) 2004-2005 Savoir-Faire Linux inc. + * Copyright (C) 2004-2006 Savoir-Faire Linux inc. * Author: Yan Morin <yan.morin@savoirfairelinux.com> * Author : Laurielle Lea <laurielle.lea@savoirfairelinux.com> * - * Portions Copyright (C) 2002,2003 Aymeric Moizard <jack@atosc.org> - * * 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 2 of the License, or @@ -19,216 +17,251 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ - -#ifndef __SIP_VOIP_LINK_H__ -#define __SIP_VOIP_LINK_H__ - -#include <vector> -#include <map> // for allowed -#include <eXosip2/eXosip.h> +#ifndef SIPVOIPLINK_H +#define SIPVOIPLINK_H #include "voIPLink.h" +#include <string> +#include <eXosip2/eXosip.h> #include "audio/audiortp.h" -#include "call.h" // for CALLID - -#define EXPIRES_VALUE 180 -// To build request -#define INVITE_METHOD "INVITE" -// 1XX responses -#define DIALOG_ESTABLISHED 101 -#define RINGING 180 -// 2XX -#define OK 200 -// 4XX Errors -#define BAD_REQ 400 -#define UNAUTHORIZED 401 -#define FORBIDDEN 403 -#define NOT_FOUND 404 -#define NOT_ALLOWED 405 -#define NOT_ACCEPTABLE 406 -#define AUTH_REQUIRED 407 -#define REQ_TIMEOUT 408 -#define UNSUP_MEDIA_TYPE 415 -#define TEMP_UNAVAILABLE 480 -#define ADDR_INCOMPLETE 484 -#define BUSY_HERE 486 -#define REQ_TERMINATED 487 -#define NOT_ACCEPTABLE_HERE 488 // Not Acceptable Here -// 5XX errors -#define SERVICE_UNAVAILABLE 503 -// 6XX errors -#define BUSY_EVERYWHERE 600 -#define DECLINE 603 - -class AudioCodec; -class CodecDescriptor; -class SipCall; -class EventThread; -typedef std::vector< CodecDescriptor* > CodecDescriptorVector; -typedef std::list<std::string> AllowList; +class EventThread; +class SIPCall; -class SipVoIPLink : public VoIPLink { +/** + @author Yan Morin <yan.morin@gmail.com> +*/ +class SIPVoIPLink : public VoIPLink +{ public: - SipVoIPLink(); - virtual ~SipVoIPLink(); - - virtual bool init (void); - virtual bool checkNetwork (void); - virtual void terminate (void); - virtual int setRegister (void); - virtual int setUnregister (void); - virtual int outgoingInvite (CALLID id, const std::string& to_url); - virtual int answer (CALLID id); - virtual int hangup (CALLID id); - virtual int cancel (CALLID id); - virtual int onhold (CALLID id); - virtual int offhold (CALLID id); - virtual int transfer (CALLID id, const std::string& to); - virtual int refuse (CALLID id); - virtual int getEvent (void); - virtual void carryingDTMFdigits (CALLID id, char code); - - /* - * To handle the local port - */ - int getLocalPort (void); - void setLocalPort (int); - bool getSipLocalIp (void); - - /* - * Add a new SipCall at the end of the SipCallVector with identifiant 'id' - */ - void newOutgoingCall(CALLID callid); - void newIncomingCall(CALLID callid); - - /* - * Erase the SipCall(id) from the SipCallVector - */ - void deleteSipCall(CALLID callid); - - /* - * Return a pointer to the SipCall with identifiant 'id' - */ - SipCall* getSipCall(CALLID callid); - - /* - * Accessor to the audio codec of SipCall with identifiant 'id' - */ - AudioCodec* getAudioCodec(CALLID callid); - -// Handle voice-message - inline void setMsgVoicemail (int nMsg) { _nMsgVoicemail = nMsg; } - inline int getMsgVoicemail (void) { return _nMsgVoicemail; } - - /** - * send text message - * the size of message should not exceed 1300 bytes - */ - virtual bool sendMessage(const std::string& to, const std::string& body); - + SIPVoIPLink(const AccountID& accountID); + + ~SIPVoIPLink(); + + /** try to initiate the eXosip engine/thread and set config */ + bool init(void); + void terminate(void); + bool checkNetwork(void); + void getEvent(void); + + bool setRegister(void); + bool setUnregister(void); + + Call* newOutgoingCall(const CallID& id, const std::string& toUrl); + bool answer(const CallID& id); + + bool hangup(const CallID& id); + bool cancel(const CallID& id); + bool onhold(const CallID& id); + bool offhold(const CallID& id); + bool transfer(const CallID& id, const std::string& to); + bool refuse (const CallID& id); + bool carryingDTMFdigits(const CallID& id, char code); + bool sendMessage(const std::string& to, const std::string& body); + + + + // SIP Specific + /** If set to true, we check for a firewall + * @param use true if we use STUN + */ + void setUseStun(bool use) { _useStun = use; } + void setProxy(const std::string& proxy) { _proxy = proxy; } + void setUserPart(const std::string& userpart) { _userpart = userpart; } + void setAuthName(const std::string& authname) { _authname = authname; } + void setPassword(const std::string& password) { _password = password; } + + private: - /* - * If you are behind a NAT, you have to use STUN server, specified in - * STUN configuration(you can change this one by default) to give you an - * public IP address and assign a port number. - * @param port : on which port we want to listen to - * - * Return false if an error occured and true if no error. - */ - bool behindNat(int port); - - /* - * Return -1 if an error occured and 0 if no error - */ - int checkUrl(const std::string& url); - - /* - * Allow the authentication when you want register - * Return -1 if an error occured and 0 if no error - */ - int setAuthentication (void); - - /* - * Build a sip address from the user configuration - * Example: "Display user name" <sip:user@host.com> - * Return the result in a string - */ - std::string fromHeader (const std::string& user, const std::string& host); - - /* - * Build a sip address with the number that you want to call - * Example: sip:124@domain.com - * Return the result in a string - */ - std::string toHeader(const std::string& to); - - /* - * Beginning point to make outgoing call. - * Check the 'from' and 'to' url. - * Allocate local audio port. - * Build SDP body. - * Return -1 if an error occured and 0 if no error - */ - int startCall (CALLID id, const std::string& from, const std::string& to, const std::string& subject, const std::string& route); + /** Terminate every call not hangup | brutal | Protected by mutex */ + void terminateSIPCall(); + + /** + * Get the local Ip by eXosip + * only if the local ip address is to his default value: 127.0.0.1 + * setLocalIpAdress + * @return false if not found + */ + bool loadSIPLocalIP(); + + /** + * send SIP authentification + * @return true if sending succeed + */ + bool sendSIPAuthentification(); + + /** + * Get a SIP From header ("fullname" <sip:userpart@hostpart>) + * @param userpart + * @param hostpart + * @return SIP URI for from Header + */ + std::string SIPFromHeader(const std::string& userpart, const std::string& hostpart); + + /** + * Build a sip address with the number that you want to call + * Example: sip:124@domain.com + * @return result as a string + */ + std::string SIPToHeader(const std::string& to); + + /** + * Check if an url is sip-valid + * @return true if osip tell that is valid + */ + bool SIPCheckUrl(const std::string& url); + + + /** + * SIPOutgoingInvite do SIPStartCall + * @return true if all is correct + */ + bool SIPOutgoingInvite(SIPCall* call); + /** + * Start a SIP Call + * @return true if all is correct + */ + bool SIPStartCall(SIPCall* call, const std::string& subject); std::string getSipFrom(); std::string getSipRoute(); std::string getSipTo(const std::string& to_url); + /** + * Set audio (SDP) configuration for a call + * localport, localip, localexternalport + * @param call a SIPCall valid pointer + * @return true + */ + bool setCallAudioLocal(SIPCall* call); + /** + * Create a new call and send a incoming call notification to the user + * @param event eXosip Event + */ + void SIPCallInvite(eXosip_event_t *event); - /* - * Look for call with same cid/did - * Return the id of the found call - */ - CALLID findCallId (eXosip_event_t *e); - CALLID findCallIdInitial (eXosip_event_t *e); + /** + * Use a exisiting call to restart the audio + * @param event eXosip Event + */ + void SIPCallReinvite(eXosip_event_t *event); - /* - * To build sdp when call is on-hold - */ - int sdp_hold_call (sdp_message_t * sdp); - - /* - * To build sdp when call is off-hold - */ - int sdp_off_hold_call (sdp_message_t * sdp); + /** + * Tell the user that the call is ringing + * @param event eXosip Event + */ + void SIPCallRinging(eXosip_event_t *event); + + /** + * Tell the user that the call was answered + * @param event eXosip Event + */ + void SIPCallAnswered(eXosip_event_t *event); + + /** + * Handling 4XX error + * @param event eXosip Event + */ + void SIPCallRequestFailure(eXosip_event_t *event); + + /** + * Handling 5XX/6XX error + * @param event eXosip Event + */ + void SIPCallServerFailure(eXosip_event_t *event); /** - * Subscribe to message summary + * Handling ack (restart audio if reinvite) + * @param event eXosip Event */ - void subscribeMessageSummary(); + void SIPCallAck(eXosip_event_t *event); /** - * End all sip call not deleted + * Handling message inside a call (like dtmf) + * @param event eXosip Event */ - void endSipCalls(); + void SIPCallMessageNew(eXosip_event_t *event); + bool handleDtmfRelay(eXosip_event_t *event); /** - * Handle DTMF Relay INFO Request + * Peer close the connection + * @param event eXosip Event */ - bool handleDtmfRelay(eXosip_event_t* event); + void SIPCallClosed(eXosip_event_t *event); /** - * Get from a response event, all allowed request + * The call pointer was released + * If the call was not cleared before, report an error + * @param event eXosip Event */ - bool setAllows(eXosip_event_t *event); + void SIPCallReleased(eXosip_event_t *event); + + /** + * Receive a new Message request + * Option/Notify/Message + * @param event eXosip Event + */ + void SIPMessageNew(eXosip_event_t *event); + + /** + * Find a SIPCall with cid from eXosip Event + * Explication there is no DID when the dialog is not establish... + * @param cid call ID + * @return 0 or SIPCall pointer + */ + SIPCall* findSIPCallWithCid(int cid); + + /** + * Find a SIPCall with cid and did from eXosip Event + * @param cid call ID + * @param did domain ID + * @return 0 or SIPCall pointer + */ + SIPCall* findSIPCallWithCidDid(int cid, int did); + SIPCall* getSIPCall(const CallID& id); + + /** To build sdp when call is on-hold */ + int sdp_hold_call (sdp_message_t * sdp); + /** To build sdp when call is off-hold */ + int sdp_off_hold_call (sdp_message_t * sdp); + + + + /** EventThread get every incoming events */ + EventThread* _evThread; + /** Tell if eXosip was stared (eXosip_init) */ + bool _eXosipStarted; + /** Registration identifier, needed by unregister to build message */ + int _eXosipRegID; + /** Number of voicemail */ + int _nMsgVoicemail; + + /** when we init the listener, how many times we try to bind a port? */ + int _nbTryListenAddr; + + /** Do we use stun? */ + bool _useStun; + + /** Local Extern Address is the IP address seens by peers for SIP listener */ + std::string _localExternAddress; + + /** Local Extern Port is the port seens by peers for SIP listener */ + unsigned int _localExternPort; + + /** SIP Proxy URL */ + std::string _proxy; + /** SIP UserPart */ + std::string _userpart; - /////////////////////////// - // Private member variables - /////////////////////////// - EventThread *_evThread; - std::vector< SipCall * > _sipcallVector; - AllowList _allowList; + /** SIP Authenfication name */ + std::string _authname; - AudioRtp _audiortp; - int _localPort; - int _reg_id; - int _nMsgVoicemail; + /** SIP Authenfication password */ + std::string _password; - bool _registrationSend; // unregistered - bool _started; // eXosip_init and eXosip_start + /** Starting sound */ + AudioRtp _audiortp; }; -#endif // __SIP_VOIP_LINK_H__ +#endif diff --git a/src/user_cfg.h b/src/user_cfg.h index 9d55dfe455ad6c6c305a7c96a589793e3091d5b3..1237e55a32f80c4493360fafab843f0abf0862d1 100644 --- a/src/user_cfg.h +++ b/src/user_cfg.h @@ -38,7 +38,7 @@ #define PREFERENCES "Preferences" #define ACCOUNT_SIP0 "SIP0" -#define ACCOUNT_AIX0 "AIX0" +#define ACCOUNT_IAX0 "IAX0" // Fields to fill diff --git a/src/voIPLink.cpp b/src/voIPLink.cpp index 6ff6b561721a50bc8905e0506537e413da953069..4612ae53fc3132d698317df9e9c6900e4b3bf108 100644 --- a/src/voIPLink.cpp +++ b/src/voIPLink.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2005 Savoir-Faire Linux inc. + * Copyright (C) 2005-2006 Savoir-Faire Linux inc. * Author: Yan Morin <yan.morin@savoirfairelinux.com> * Author : Laurielle Lea <laurielle.lea@savoirfairelinux.com> * @@ -22,48 +22,61 @@ #include "user_cfg.h" #include "voIPLink.h" -#include "manager.h" -VoIPLink::VoIPLink () +VoIPLink::VoIPLink(const AccountID& accountID) : _accountID(accountID), _localIPAddress("127.0.0.1"), _localPort(0) { + } VoIPLink::~VoIPLink (void) { + clearCallMap(); } -void -VoIPLink::setFullName (const std::string& fullname) +bool +VoIPLink::addCall(Call* call) { - _fullname = fullname; + if (call) { + if (getCall(call->getCallId()) == 0) { + ost::MutexLock m(_callMapMutex); + _callMap[call->getCallId()] = call; + } + } + return false; } -std::string -VoIPLink::getFullName (void) +bool +VoIPLink::removeCall(const CallID& id) { - return _fullname; + ost::MutexLock m(_callMapMutex); + if (_callMap.erase(id)) { + return true; + } + return false; } -void -VoIPLink::setHostName (const std::string& hostname) +Call* +VoIPLink::getCall(const CallID& id) { - _hostname = hostname; + ost::MutexLock m(_callMapMutex); + CallMap::iterator iter = _callMap.find(id); + if ( iter != 0 && iter != _callMap.end() ) { + return iter->second; + } + return 0; } -std::string -VoIPLink::getHostName (void) +bool +VoIPLink::clearCallMap() { - return _hostname; -} - -void -VoIPLink::setLocalIpAddress (const std::string& ipAdress) -{ - _localIpAddress = ipAdress; + ost::MutexLock m(_callMapMutex); + CallMap::iterator iter = _callMap.begin(); + while( iter != _callMap.end() ) { + // if (iter) ? + delete iter->second; iter->second = 0; + iter++; + } + _callMap.clear(); + return true; } -std::string -VoIPLink::getLocalIpAddress (void) -{ - return _localIpAddress; -} diff --git a/src/voIPLink.h b/src/voIPLink.h index bfd7f957eea9d7174ad6593f957aec70dad31342..e0644bb2209303eb9d6eafd034da63fed2c62624 100644 --- a/src/voIPLink.h +++ b/src/voIPLink.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2005 Savoir-Faire Linux inc. + * Copyright (C) 2005-2006 Savoir-Faire Linux inc. * Author: Yan Morin <yan.morin@savoirfairelinux.com> * Author : Laurielle Lea <laurielle.lea@savoirfairelinux.com> * @@ -22,49 +22,87 @@ #define __VOIP_LINK_H__ #include <string> +#include "account.h" // for AccountID #include "call.h" +#include <map> +#include <cc++/thread.h> // for mutex class AudioCodec; -class Call; + +typedef std::map<CallID, Call*> CallMap; class VoIPLink { public: - VoIPLink (); + VoIPLink(const AccountID& accountID); virtual ~VoIPLink (void); // Pure virtual functions - virtual int getEvent (void) = 0; + virtual void getEvent (void) = 0; virtual bool init (void) = 0; virtual bool checkNetwork (void) = 0; virtual void terminate (void) = 0; - virtual void newOutgoingCall (CALLID id) = 0; - virtual void newIncomingCall (CALLID id) = 0; - virtual int outgoingInvite (CALLID id, const std::string& to_url) = 0; - virtual int answer (CALLID id) = 0; - virtual int hangup (CALLID id) = 0; - virtual int cancel (CALLID id) = 0; - virtual int onhold (CALLID id) = 0; - virtual int offhold (CALLID id) = 0; - virtual int transfer (CALLID id, const std::string& to) = 0; - virtual int refuse (CALLID id) = 0; - virtual int setRegister (void) = 0; - virtual int setUnregister (void) = 0; - virtual void carryingDTMFdigits(CALLID id, char code) = 0; - virtual AudioCodec* getAudioCodec (CALLID id) = 0; + virtual bool setRegister (void) = 0; + virtual bool setUnregister (void) = 0; + + /** Add a new outgoing call and return the call pointer or 0 if and error occurs */ + virtual Call* newOutgoingCall(const CallID& id, const std::string& toUrl) = 0; + virtual bool answer(const CallID& id) = 0; + + virtual bool hangup(const CallID& id) = 0; + virtual bool cancel(const CallID& id) = 0; + virtual bool onhold(const CallID& id) = 0; + virtual bool offhold(const CallID& id) = 0; + virtual bool transfer(const CallID& id, const std::string& to) = 0; + virtual bool refuse(const CallID& id) = 0; + virtual bool carryingDTMFdigits(const CallID& id, char code) = 0; virtual bool sendMessage(const std::string& to, const std::string& body) = 0; - void setFullName (const std::string& fullname); - std::string getFullName (void); - void setHostName (const std::string& hostname); - std::string getHostName (void); - void setLocalIpAddress (const std::string& ipAdress); - std::string getLocalIpAddress (void); + // these method are set only with 'Account init' and can be get by everyone + void setFullName (const std::string& fullname) { _fullname = fullname; } + std::string& getFullName (void) { return _fullname; } + void setHostName (const std::string& hostname) { _hostname = hostname; } + std::string& getHostName (void) { return _hostname; } + AccountID& getAccountID(void) { return _accountID; } + + /** Get the call pointer from the call map (protected by mutex) + * @param id A Call ID + * @return call pointer or 0 + */ + Call* getCall(const CallID& id); + + +private: + std::string _fullname; + std::string _hostname; + AccountID _accountID; protected: - - std::string _fullname; - std::string _hostname; - std::string _localIpAddress; + /** Add a call to the call map (protected by mutex) + * @param call A call pointer with a unique pointer + * @return true if the call was unique and added + */ + bool addCall(Call* call); + + /** remove a call from the call map (protected by mutex) + * @param id A Call ID + * @return true if the call was correctly removed + */ + bool removeCall(const CallID& id); + + /** + * Remove all the call from the map + */ + bool clearCallMap(); + + /** Contains all the calls for this Link, protected by mutex */ + CallMap _callMap; + /** Mutex to protect call map */ + ost::Mutex _callMapMutex; + + /** Get Local IP Address (ie: 127.0.0.1, 192.168.0.1, ...) */ + std::string _localIPAddress; + /** Get local listening port (5060 for SIP, ...) */ + unsigned int _localPort; }; #endif // __VOIP_LINK_H__