diff --git a/src/iaxvoiplink.cpp b/src/iaxvoiplink.cpp index df5d51d51321fab5a4b36cdb83f0730fce3f79ca..7bcb0fe602fc3451c772ef538b449bdf5e164f4c 100644 --- a/src/iaxvoiplink.cpp +++ b/src/iaxvoiplink.cpp @@ -26,11 +26,42 @@ #define IAX_SUCCESS 0 #define IAX_FAILURE -1 +#define RANDOM_IAX_PORT rand() % 64000 + 1024 + +// from IAXC : iaxclient.h + +/* payload formats : WARNING: must match libiax values!!! */ +/* Data formats for capabilities and frames alike */ +#define IAX__FORMAT_G723_1 (1 << 0) /* G.723.1 compression */ +#define IAX__FORMAT_GSM (1 << 1) /* GSM compression */ +#define IAX__FORMAT_ULAW (1 << 2) /* Raw mu-law data (G.711) */ +#define IAX__FORMAT_ALAW (1 << 3) /* Raw A-law data (G.711) */ +#define IAX__FORMAT_G726 (1 << 4) /* ADPCM, 32kbps */ +#define IAX__FORMAT_ADPCM (1 << 5) /* ADPCM IMA */ +#define IAX__FORMAT_SLINEAR (1 << 6) /* Raw 16-bit Signed Linear (8000 Hz) PCM */ +#define IAX__FORMAT_LPC10 (1 << 7) /* LPC10, 180 samples/frame */ +#define IAX__FORMAT_G729A (1 << 8) /* G.729a Audio */ +#define IAX__FORMAT_SPEEX (1 << 9) /* Speex Audio */ +#define IAX__FORMAT_ILBC (1 << 10) /* iLBC Audio */ + +#define IAX__FORMAT_MAX_AUDIO (1 << 15) /* Maximum audio format */ +#define IAX__FORMAT_JPEG (1 << 16) /* JPEG Images */ +#define IAX__FORMAT_PNG (1 << 17) /* PNG Images */ +#define IAX__FORMAT_H261 (1 << 18) /* H.261 Video */ +#define IAX__FORMAT_H263 (1 << 19) /* H.263 Video */ +#define IAX__FORMAT_H263_PLUS (1 << 20) /* H.263+ Video */ +#define IAX__FORMAT_MPEG4 (1 << 21) /* MPEG4 Video */ +#define IAX__FORMAT_H264 (1 << 23) /* H264 Video */ +#define IAX__FORMAT_THEORA (1 << 24) /* Theora Video */ + IAXVoIPLink::IAXVoIPLink(const AccountID& accountID) : VoIPLink(accountID) { _evThread = new EventThread(this); _regSession = 0; + + // to get random number for RANDOM_PORT + srand (time(NULL)); } @@ -48,17 +79,31 @@ IAXVoIPLink::init() //_localAddress = "127.0.0.1"; // port 0 is default // iax_enable_debug(); have to enable debug when compiling iax... - int port = iax_init(IAX_DEFAULT_PORTNO); - if (port == IAX_FAILURE) { - _debug("IAX Failure: Error when initializing\n"); - } else if ( port == 0 ) { - _debug("IAX Warning: already initialize\n"); - } else { - _debug("IAX Info: listening on port %d\n", port); - _localPort = port; - returnValue = true; - - _evThread->start(); + int port = IAX_DEFAULT_PORTNO; + int last_port = 0; + int nbTry = 3; + + while (port != IAX_FAILURE && nbTry) { + last_port = port; + port = iax_init(port); + if ( port < 0 ) { + _debug("IAX Warning: already initialize on port %d\n", last_port); + port = RANDOM_IAX_PORT; + } else if (port == IAX_FAILURE) { + _debug("IAX Fail to start on port %d", last_port); + port = RANDOM_IAX_PORT; + } else { + _debug("IAX Info: listening on port %d\n", last_port); + _localPort = last_port; + returnValue = true; + + _evThread->start(); + break; + } + nbTry--; + } + if (port == IAX_FAILURE || nbTry==0) { + _debug("Fail to initialize iax\n"); } return returnValue; } @@ -75,42 +120,44 @@ void IAXVoIPLink::getEvent() { // mutex here + _mutexIAX.enterMutex(); + iax_event* event = 0; IAXCall* call = 0; while ( (event = iax_get_event(0)) != 0 ) { _debug ("Receive IAX Event: %d\n", event->etype); call = iaxFindCallBySession(event->session); if (call!=0) { - iaxHandleCallEvent(event, call); + iaxHandleCallEvent(event, call); } else if (event->session != 0 && event->session == _regSession) { - // in iaxclient, there is many session handling, here, only one - iaxHandleRegReply(event); + // in iaxclient, there is many session handling, here, only one + iaxHandleRegReply(event); } else { - switch(event->etype) { - case IAX_EVENT_REGACK: - case IAX_EVENT_REGREJ: - _debug("Unknown IAX Registration Event\n"); - break; - - case IAX_EVENT_REGREQ: - _debug("Registration by a peer, don't allow it\n"); - break; - case IAX_EVENT_CONNECT: // new call - // New incoming call! - break; - - case IAX_EVENT_TIMEOUT: // timeout for an unknown session - - break; - - default: - _debug("Unknown event type: %d\n", event->etype); - } + switch(event->etype) { + case IAX_EVENT_REGACK: + case IAX_EVENT_REGREJ: + _debug("Unknown IAX Registration Event\n"); + break; + + case IAX_EVENT_REGREQ: + _debug("Registration by a peer, don't allow it\n"); + break; + case IAX_EVENT_CONNECT: // new call + // New incoming call! + break; + + case IAX_EVENT_TIMEOUT: // timeout for an unknown session + + break; + + default: + _debug("Unknown event type: %d\n", event->etype); + } } iax_event_free(event); } // unlock mutex here - + _mutexIAX.leaveMutex(); //iaxRefreshRegistrations(); // thread wait 5 millisecond @@ -130,8 +177,9 @@ IAXVoIPLink::setRegister() Manager::instance().displayConfigError("Fill user field for IAX Account"); return false; } - // lock + // lock + _mutexIAX.enterMutex(); _regSession = iax_session_new(); if (!_regSession) { @@ -147,12 +195,13 @@ IAXVoIPLink::setRegister() strcpy(pass, _pass.c_str()); //iax_register don't use const char* - _debug("Sending registration to %s with user %s\n", host, user); - iax_register(_regSession, host, user, pass, 300); + _debug("IAX Sending registration to %s with user %s\n", host, user); + int val = iax_register(_regSession, host, user, pass, 300); + _debug ("Return value: %d\n", val); result = true; } - // unlock + _mutexIAX.leaveMutex(); } return result; } @@ -160,9 +209,69 @@ IAXVoIPLink::setRegister() bool IAXVoIPLink::setUnregister() { + if (_regSession==0) { + // lock here + _mutexIAX.enterMutex(); + iax_destroy(_regSession); + _regSession = 0; + // unlock here + _mutexIAX.leaveMutex(); + return false; + } return false; } +Call* +IAXVoIPLink::newOutgoingCall(const CallID& id, const std::string& toUrl) +{ + IAXCall* call = new IAXCall(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 ( iaxOutgoingInvite(call) ) { + call->setConnectionState(Call::Progressing); + call->setState(Call::Active); + addCall(call); + } else { + delete call; call = 0; + } + } + return call; +} + +bool +IAXVoIPLink::iaxOutgoingInvite(IAXCall* call) +{ + struct iax_session *newsession; + // lock here + _mutexIAX.enterMutex(); + newsession = iax_session_new(); + if (!newsession) { + _debug("IAX Error: Can't make new session for a new call\n"); + // unlock here + _mutexIAX.leaveMutex(); + return false; + } + call->setSession(newsession); + /* reset activity and ping "timers" */ + // iaxc_note_activity(callNo); + char num[call->getPeerNumber().length()+1]; + strcpy(num, call->getPeerNumber().c_str()); + + char* lang = NULL; + int wait = 0; + int audio_format_preferred = IAX__FORMAT_SPEEX; + int audio_format_capability = IAX__FORMAT_ULAW | IAX__FORMAT_ALAW | IAX__FORMAT_GSM | IAX__FORMAT_SPEEX; + + iax_call(newsession, num, num, num, lang, wait, audio_format_preferred, audio_format_capability); + + // unlock here + _mutexIAX.leaveMutex(); + return true; +} + + IAXCall* IAXVoIPLink::iaxFindCallBySession(struct iax_session* session) { @@ -196,7 +305,7 @@ IAXVoIPLink::iaxHandleCallEvent(iax_event* event, IAXCall* call) case IAX_EVENT_ACCEPT: break; - + case IAX_EVENT_ANSWER: break; @@ -233,8 +342,17 @@ IAXVoIPLink::iaxHandleCallEvent(iax_event* event, IAXCall* call) } } + + void IAXVoIPLink::iaxHandleRegReply(iax_event* event) { - // use _regSession here, should be equal to event->session; + //unregister + if (event->etype == IAX_EVENT_REGREJ) { + iax_destroy(_regSession); + _regSession = 0; + Manager::instance().registrationFailed(getAccountID()); + } else if (event->etype == IAX_EVENT_REGACK) { + Manager::instance().registrationSucceed(getAccountID()); + } } diff --git a/src/iaxvoiplink.h b/src/iaxvoiplink.h index 92f518d55872e8bf726fd501abbf7fca8f62b933..ca958f4634495865107aa92dfffe821ff78544d0 100644 --- a/src/iaxvoiplink.h +++ b/src/iaxvoiplink.h @@ -45,7 +45,7 @@ public: bool setRegister (void); bool setUnregister (void); - Call* newOutgoingCall(const CallID& id, const std::string& toUrl) {return 0; } + Call* newOutgoingCall(const CallID& id, const std::string& toUrl); bool answer(const CallID& id) {return false;} bool hangup(const CallID& id) { return false; } @@ -83,6 +83,11 @@ private: */ void iaxHandleRegReply(iax_event* event); + /** + * Send an outgoing call invite to iax + */ + bool iaxOutgoingInvite(IAXCall* Call); + EventThread* _evThread; /** registration session : 0 if not register */ struct iax_session* _regSession; @@ -93,7 +98,8 @@ private: std::string _user; /** IAX Password */ std::string _pass; - + + ost::Mutex _mutexIAX; }; #endif diff --git a/src/managerimpl.cpp b/src/managerimpl.cpp index 4449308f8a97ae4bf5d689e5e418856e801158bc..e8b83945252c318f372e44dcbb6c596a5c7e6845 100644 --- a/src/managerimpl.cpp +++ b/src/managerimpl.cpp @@ -421,12 +421,11 @@ ManagerImpl::initRegisterVoIPLink() if ( iter->second) { iter->second->loadConfig(); if ( iter->second->shouldInitOnStart() ) { - iter->second->init(); - if (iter->second->shouldRegisterOnStart()) { - iter->second->registerAccount(); + if ( iter->second->init() && iter->second->shouldRegisterOnStart()) { + iter->second->registerAccount(); } - // init only the first account - break; + // init only the first account + break; } } iter++;