From 2953c83c4ab6040d07a196d31874737958a4e6e3 Mon Sep 17 00:00:00 2001 From: yanmorin <yanmorin> Date: Wed, 26 Jul 2006 16:18:07 +0000 Subject: [PATCH] *** empty log message *** --- src/eventthread.cpp | 1 + src/iaxaccount.cpp | 2 +- src/iaxcall.cpp | 633 +------------------------------------------- src/iaxvoiplink.cpp | 107 +++++++- src/iaxvoiplink.h | 8 +- src/sipcall.cpp | 633 +++++++++++++++++++++++++++++++++++++++++++- 6 files changed, 744 insertions(+), 640 deletions(-) diff --git a/src/eventthread.cpp b/src/eventthread.cpp index dd113bad97..401e2e8948 100644 --- a/src/eventthread.cpp +++ b/src/eventthread.cpp @@ -43,3 +43,4 @@ EventThread::run (void) } } + diff --git a/src/iaxaccount.cpp b/src/iaxaccount.cpp index d8b49a5914..7ef9838bcd 100644 --- a/src/iaxaccount.cpp +++ b/src/iaxaccount.cpp @@ -88,7 +88,7 @@ IAXAccount::initConfig(Conf::ConfigTree& config) 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_TYPE, "IAX", type_str)); config.addConfigTreeItem(section, Conf::ConfigTreeItem(CONFIG_ACCOUNT_ENABLE,"1", type_int)); config.addConfigTreeItem(section, Conf::ConfigTreeItem(CONFIG_ACCOUNT_AUTO_REGISTER, "1", type_int)); } diff --git a/src/iaxcall.cpp b/src/iaxcall.cpp index cb3fde0926..bfcd6f8e0f 100644 --- a/src/iaxcall.cpp +++ b/src/iaxcall.cpp @@ -1,7 +1,6 @@ /* - * Copyright (C) 2004-2006 Savoir-Faire Linux inc. + * Copyright (C) 2006 Savoir-Faire Linux inc. * Author: Yan Morin <yan.morin@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 @@ -18,636 +17,16 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ -#include "sipcall.h" +#include "iaxcall.h" #include "global.h" // for _debug -#include <sstream> // for media buffer -#define _SENDRECV 0 -#define _SENDONLY 1 -#define _RECVONLY 2 - -SIPCall::SIPCall(const CallID& id, Call::CallType type) : Call(id, type), - _localIPAddress(""), _remoteIPAddress("") -{ - _cid = 0; - _did = 0; - _tid = 0; - _audioCodec = 0; - _localAudioPort = 0; - _localExternalAudioPort = 0; - _remoteAudioPort = 0; -} - -SIPCall::~SIPCall() +IAXCall::IAXCall(const CallID& id, Call::CallType type) : Call(id, type), _session(0) { + } -CodecDescriptorMap& -SIPCall::getCodecMap() +IAXCall::~IAXCall() { - return _codecMap; + _session = 0; // just to be sure to don't have unknown pointer, do not delete it! } -/** - * Answer incoming call correclty before telling the user - * @param event eXosip Event - */ -bool -SIPCall::SIPCallInvite(eXosip_event_t *event) -{ - if (event->cid < 1 && event->did < 1) { - _debug("SIP Failure: Invalid cid and did\n"); - return false; - } - - if (event->request == NULL) { - _debug("SIP Failure: No request into the event\n"); - return false; - } - - setCid(event->cid); - setDid(event->did); - setTid(event->tid); - - setPeerInfoFromRequest(event); - - sdp_message_t* remote_sdp = getRemoteSDPFromRequest(event); - if (remote_sdp == 0) { - return false; - } - - sdp_media_t* remote_med = getRemoteMedia(event->tid, remote_sdp); - if (remote_med == 0) { - sdp_message_free (remote_sdp); - return false; - } - - 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; - } - - if (!setAudioCodecFromSDP(remote_med, event->tid)) { - sdp_message_free (remote_sdp); - return false; - } - - osip_message_t *answer = 0; - eXosip_lock(); - _debug("< Building Answer 183\n"); - 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 : unsupported media type\n"); - eXosip_call_send_answer (event->tid, 415, NULL); - } else { - - sdp_message_t *local_sdp = eXosip_get_sdp_info(answer); - sdp_media_t *local_med = NULL; - if (local_sdp != NULL) { - local_med = eXosip_get_audio_media(local_sdp); - } - if (local_sdp != NULL && local_med != NULL) { - /* search if stream is sendonly or recvonly */ - 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) { - if (_remote_sendrecv == _SENDONLY) { _local_sendrecv = _RECVONLY; } - else if (_remote_sendrecv == _RECVONLY) { _local_sendrecv = _SENDONLY; } - } - _debug(" Final Local SendRecv: %d\n", _local_sendrecv); - sdp_message_free (local_sdp); - } - _debug("< Sending answer 183\n"); - 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 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) - * @param event eXosip Event - * @return true if ok - */ -bool -SIPCall::SIPCallReinvite(eXosip_event_t *event) -{ - if (event->cid < 1 && event->did < 1) { - _debug("SIP Failure: Invalid cid and did\n"); - return false; - } - - if (event->request == NULL) { - _debug("SIP Failure: No request into the event\n"); - return false; - } - - setCid(event->cid); - setDid(event->did); - setTid(event->tid); - - setPeerInfoFromRequest(event); - - sdp_message_t* remote_sdp = getRemoteSDPFromRequest(event); - if (remote_sdp == 0) { - return false; - } - - sdp_media_t* remote_med = getRemoteMedia(event->tid, remote_sdp); - if (remote_med == 0) { - sdp_message_free (remote_sdp); - return false; - } - - 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; - } - - if (!setAudioCodecFromSDP(remote_med, event->tid)) { - sdp_message_free (remote_sdp); - return false; - } - - osip_message_t *answer = 0; - eXosip_lock(); - _debug("< Building Answer 200\n"); - 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 (event->tid, 415, NULL); - _debug("< Sending Answer 415\n"); - } else { - - sdp_message_t *local_sdp = eXosip_get_sdp_info(answer); - sdp_media_t *local_med = NULL; - if (local_sdp != NULL) { - local_med = eXosip_get_audio_media(local_sdp); - } - if (local_sdp != NULL && local_med != NULL) { - /* search if stream is sendonly or recvonly */ - 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) { - if (_remote_sendrecv == _SENDONLY) { _local_sendrecv = _RECVONLY; } - else if (_remote_sendrecv == _RECVONLY) { _local_sendrecv = _SENDONLY; } - } - _debug(" Final Local SendRecv: %d\n", _local_sendrecv); - sdp_message_free (local_sdp); - } - _debug("< Sending answer 200\n"); - 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); - return true; -} - - /** - * Peer answered to a call (on hold or not) - * @param event eXosip Event - * @return true if ok - */ -bool -SIPCall::SIPCallAnswered(eXosip_event_t *event) -{ - if (event->cid < 1 && event->did < 1) { - _debug("SIP Failure: Invalid cid and did\n"); - return false; - } - - if (event->request == NULL) { - _debug("SIP Failure: No request into the event\n"); - return false; - } - - setCid(event->cid); - setDid(event->did); - - //setPeerInfoFromResponse() - - eXosip_lock (); - { - osip_message_t *ack = NULL; - int i; - i = eXosip_call_build_ack (event->did, &ack); - if (i != 0) { - _debug("SipCall::answeredCall: Cannot build ACK for call!\n"); - } else { - sdp_message_t *local_sdp = NULL; - sdp_message_t *remote_sdp = NULL; - - if (event->request != NULL && event->response != NULL) { - local_sdp = eXosip_get_sdp_info (event->request); - remote_sdp = eXosip_get_sdp_info (event->response); - } - if (local_sdp == NULL && remote_sdp != NULL) { - /* sdp in ACK */ - i = sdp_complete_message (remote_sdp, ack); - if (i != 0) { - _debug("SipCall::answeredCall: Cannot complete ACK with sdp body?!\n"); - } - } - sdp_message_free (local_sdp); - sdp_message_free (remote_sdp); - - _debug("< Send ACK\n"); - eXosip_call_send_ack (event->did, ack); - } - } - eXosip_unlock (); - return true; -} - /** - * 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 || 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; - } - - 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; - } - - char *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 - } - -/* - // 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; -} - -const std::string& -SIPCall::getLocalIp() -{ - ost::MutexLock m(_callMutex); - return _localIPAddress; -} - -unsigned int -SIPCall::getLocalAudioPort() -{ - ost::MutexLock m(_callMutex); - return _localAudioPort; -} - -unsigned int -SIPCall::getRemoteAudioPort() -{ - ost::MutexLock m(_callMutex); - return _remoteAudioPort; -} - -const std::string& -SIPCall::getRemoteIp() -{ - ost::MutexLock m(_callMutex); - return _remoteIPAddress; -} - -AudioCodec* -SIPCall::getAudioCodec() -{ - ost::MutexLock m(_callMutex); - return _audioCodec; -} - -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"); - return -1; - } - if (msg == NULL) { - _debug("SipCall::sdp_complete_message: No message to complete\n"); - return -1; - } - - 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; } - - if (0 != osip_strcasecmp (remote_med->m_media, "audio")) { - // if this is not an "audio" media, we set it to 0 - media << "m=" << remote_med->m_media << " 0 " << remote_med->m_proto << " \r\n"; - } else { - std::ostringstream listCodec; - std::ostringstream listRtpMap; - - // search for compatible codec: foreach payload - int iPayload = 0; - while (!osip_list_eol(remote_med->m_payloads, iPayload)) { - tmp = (char *)osip_list_get(remote_med->m_payloads, iPayload); - if (tmp!=NULL) { - int payload = atoi(tmp); - AudioCodec* audiocodec = _codecMap.getCodec((CodecType)payload); - if (audiocodec!=0 && audiocodec->isActive()) { - listCodec << payload << " "; - listRtpMap << "a=rtpmap: " << payload << " " << audiocodec->getCodecName() << "/" << audiocodec->getClockRate(); - if ( audiocodec->getChannel() != 1) { - listRtpMap << "/" << audiocodec->getChannel(); - } - listRtpMap << "\r\n"; - } - } - iPayload++; - } - if (listCodec.str().empty()) { - 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 << " " << 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", 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"); - _debug(" sdp: %s", buf); - return 0; -} - - - // 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++; - } - - /* 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); - } - - _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; -} - -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; -} - -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; -} - -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/iaxvoiplink.cpp b/src/iaxvoiplink.cpp index b02732d3cc..3a5a0d8cd8 100644 --- a/src/iaxvoiplink.cpp +++ b/src/iaxvoiplink.cpp @@ -28,12 +28,14 @@ IAXVoIPLink::IAXVoIPLink(const AccountID& accountID) : VoIPLink(accountID) { _evThread = new EventThread(this); + _regSession = 0; } IAXVoIPLink::~IAXVoIPLink() { delete _evThread; _evThread = 0; + _regSession = 0; // shall not delete it terminate(); } @@ -53,6 +55,8 @@ IAXVoIPLink::init() _debug("IAX Info: listening on port %d\n", port); _localPort = port; returnValue = true; + + _evThread->start(); } return returnValue; } @@ -75,17 +79,58 @@ IAXVoIPLink::getEvent() call = iaxFindCallBySession(event->session); if (call!=0) { iaxHandleCallEvent(event, call); + } else if (event->session != 0 && event->session == _regSession) { + // in iaxclient, there is many session handling, here, only one + iaxHandleRegReply(event); + } else { + switch(e->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->type); + } } - return; + iax_event_free(event); } - iax_event_free(event); - // thread wait 5 second - // unlock mutex + // unlock mutex here + + //iaxRefreshRegistrations(); + + // thread wait 5 millisecond + _evThread->sleep(5); } bool IAXVoIPLink::setRegister() { + if (_regSession==0) { + // lock + + _regSession = iax_session_new(); + + if (!_regSession) { + _debug("error when generating new session for register"); + } else { + // refresh + // last reg + } + + // unlock + } return false; } @@ -116,5 +161,57 @@ IAXVoIPLink::iaxFindCallBySession(struct iax_session* session) void IAXVoIPLink::iaxHandleCallEvent(iax_event* event, IAXCall* call) { - + // call should not be 0 + // note activity? + // + switch(event->type) { + case IAX_EVENT_HANGUP: + break; + + case IAX_EVENT_REJECT: + break; + + case IAX_EVENT_ACCEPT: + break; + + case IAX_EVENT_ANSWER: + break; + + case IAX_EVENT_BUSY: + break; + + case IAX_EVENT_VOICE: + break; + + case IAX_EVENT_TEXT: + break; + + case IAX_EVENT_RINGA: + break; + + case IAX_EVENT_PONG: + break; + + case IAX_EVENT_URL: + break; + + case IAX_EVENT_CNG: + break; + + case IAX_EVENT_TIMEOUT: + break; + + case IAX_EVENT_TRANSFER: + break; + + default: + _debug("Unknown event type: %d\n", event->type); + + } +} + +void +IAXVoIPLink::iaxHandleRegReply(iax_event* event) +{ + // use _regSession here, should be equal to event->session; } diff --git a/src/iaxvoiplink.h b/src/iaxvoiplink.h index c0329a7401..47d0d3e227 100644 --- a/src/iaxvoiplink.h +++ b/src/iaxvoiplink.h @@ -63,7 +63,7 @@ private: * @param session an iax_session valid pointer * @return iaxcall or 0 if not found */ - IAXCall* iaxFindCallBySession(struct iax_session *session); + IAXCall* iaxFindCallBySession(struct iax_session* session); /** * Handle IAX Event for a call @@ -72,8 +72,14 @@ private: */ void iaxHandleCallEvent(iax_event* event, IAXCall* call); + /** + * Handle IAX Registration Reply event + * @param event An iax_event pointer + */ + void iaxHandleRegReply(iax_event* event); EventThread* _evThread; + struct iax_session* _regSession; }; #endif diff --git a/src/sipcall.cpp b/src/sipcall.cpp index bfcd6f8e0f..cb3fde0926 100644 --- a/src/sipcall.cpp +++ b/src/sipcall.cpp @@ -1,6 +1,7 @@ /* - * Copyright (C) 2006 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> * * 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 @@ -17,16 +18,636 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ -#include "iaxcall.h" +#include "sipcall.h" #include "global.h" // for _debug +#include <sstream> // for media buffer -IAXCall::IAXCall(const CallID& id, Call::CallType type) : Call(id, type), _session(0) +#define _SENDRECV 0 +#define _SENDONLY 1 +#define _RECVONLY 2 + +SIPCall::SIPCall(const CallID& id, Call::CallType type) : Call(id, type), + _localIPAddress(""), _remoteIPAddress("") +{ + _cid = 0; + _did = 0; + _tid = 0; + _audioCodec = 0; + _localAudioPort = 0; + _localExternalAudioPort = 0; + _remoteAudioPort = 0; +} + +SIPCall::~SIPCall() { - } -IAXCall::~IAXCall() +CodecDescriptorMap& +SIPCall::getCodecMap() { - _session = 0; // just to be sure to don't have unknown pointer, do not delete it! + return _codecMap; } +/** + * Answer incoming call correclty before telling the user + * @param event eXosip Event + */ +bool +SIPCall::SIPCallInvite(eXosip_event_t *event) +{ + if (event->cid < 1 && event->did < 1) { + _debug("SIP Failure: Invalid cid and did\n"); + return false; + } + + if (event->request == NULL) { + _debug("SIP Failure: No request into the event\n"); + return false; + } + + setCid(event->cid); + setDid(event->did); + setTid(event->tid); + + setPeerInfoFromRequest(event); + + sdp_message_t* remote_sdp = getRemoteSDPFromRequest(event); + if (remote_sdp == 0) { + return false; + } + + sdp_media_t* remote_med = getRemoteMedia(event->tid, remote_sdp); + if (remote_med == 0) { + sdp_message_free (remote_sdp); + return false; + } + + 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; + } + + if (!setAudioCodecFromSDP(remote_med, event->tid)) { + sdp_message_free (remote_sdp); + return false; + } + + osip_message_t *answer = 0; + eXosip_lock(); + _debug("< Building Answer 183\n"); + 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 : unsupported media type\n"); + eXosip_call_send_answer (event->tid, 415, NULL); + } else { + + sdp_message_t *local_sdp = eXosip_get_sdp_info(answer); + sdp_media_t *local_med = NULL; + if (local_sdp != NULL) { + local_med = eXosip_get_audio_media(local_sdp); + } + if (local_sdp != NULL && local_med != NULL) { + /* search if stream is sendonly or recvonly */ + 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) { + if (_remote_sendrecv == _SENDONLY) { _local_sendrecv = _RECVONLY; } + else if (_remote_sendrecv == _RECVONLY) { _local_sendrecv = _SENDONLY; } + } + _debug(" Final Local SendRecv: %d\n", _local_sendrecv); + sdp_message_free (local_sdp); + } + _debug("< Sending answer 183\n"); + 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 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) + * @param event eXosip Event + * @return true if ok + */ +bool +SIPCall::SIPCallReinvite(eXosip_event_t *event) +{ + if (event->cid < 1 && event->did < 1) { + _debug("SIP Failure: Invalid cid and did\n"); + return false; + } + + if (event->request == NULL) { + _debug("SIP Failure: No request into the event\n"); + return false; + } + + setCid(event->cid); + setDid(event->did); + setTid(event->tid); + + setPeerInfoFromRequest(event); + + sdp_message_t* remote_sdp = getRemoteSDPFromRequest(event); + if (remote_sdp == 0) { + return false; + } + + sdp_media_t* remote_med = getRemoteMedia(event->tid, remote_sdp); + if (remote_med == 0) { + sdp_message_free (remote_sdp); + return false; + } + + 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; + } + + if (!setAudioCodecFromSDP(remote_med, event->tid)) { + sdp_message_free (remote_sdp); + return false; + } + + osip_message_t *answer = 0; + eXosip_lock(); + _debug("< Building Answer 200\n"); + 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 (event->tid, 415, NULL); + _debug("< Sending Answer 415\n"); + } else { + + sdp_message_t *local_sdp = eXosip_get_sdp_info(answer); + sdp_media_t *local_med = NULL; + if (local_sdp != NULL) { + local_med = eXosip_get_audio_media(local_sdp); + } + if (local_sdp != NULL && local_med != NULL) { + /* search if stream is sendonly or recvonly */ + 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) { + if (_remote_sendrecv == _SENDONLY) { _local_sendrecv = _RECVONLY; } + else if (_remote_sendrecv == _RECVONLY) { _local_sendrecv = _SENDONLY; } + } + _debug(" Final Local SendRecv: %d\n", _local_sendrecv); + sdp_message_free (local_sdp); + } + _debug("< Sending answer 200\n"); + 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); + return true; +} + + /** + * Peer answered to a call (on hold or not) + * @param event eXosip Event + * @return true if ok + */ +bool +SIPCall::SIPCallAnswered(eXosip_event_t *event) +{ + if (event->cid < 1 && event->did < 1) { + _debug("SIP Failure: Invalid cid and did\n"); + return false; + } + + if (event->request == NULL) { + _debug("SIP Failure: No request into the event\n"); + return false; + } + + setCid(event->cid); + setDid(event->did); + + //setPeerInfoFromResponse() + + eXosip_lock (); + { + osip_message_t *ack = NULL; + int i; + i = eXosip_call_build_ack (event->did, &ack); + if (i != 0) { + _debug("SipCall::answeredCall: Cannot build ACK for call!\n"); + } else { + sdp_message_t *local_sdp = NULL; + sdp_message_t *remote_sdp = NULL; + + if (event->request != NULL && event->response != NULL) { + local_sdp = eXosip_get_sdp_info (event->request); + remote_sdp = eXosip_get_sdp_info (event->response); + } + if (local_sdp == NULL && remote_sdp != NULL) { + /* sdp in ACK */ + i = sdp_complete_message (remote_sdp, ack); + if (i != 0) { + _debug("SipCall::answeredCall: Cannot complete ACK with sdp body?!\n"); + } + } + sdp_message_free (local_sdp); + sdp_message_free (remote_sdp); + + _debug("< Send ACK\n"); + eXosip_call_send_ack (event->did, ack); + } + } + eXosip_unlock (); + return true; +} + /** + * 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 || 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; + } + + 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; + } + + char *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 + } + +/* + // 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; +} + +const std::string& +SIPCall::getLocalIp() +{ + ost::MutexLock m(_callMutex); + return _localIPAddress; +} + +unsigned int +SIPCall::getLocalAudioPort() +{ + ost::MutexLock m(_callMutex); + return _localAudioPort; +} + +unsigned int +SIPCall::getRemoteAudioPort() +{ + ost::MutexLock m(_callMutex); + return _remoteAudioPort; +} + +const std::string& +SIPCall::getRemoteIp() +{ + ost::MutexLock m(_callMutex); + return _remoteIPAddress; +} + +AudioCodec* +SIPCall::getAudioCodec() +{ + ost::MutexLock m(_callMutex); + return _audioCodec; +} + +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"); + return -1; + } + if (msg == NULL) { + _debug("SipCall::sdp_complete_message: No message to complete\n"); + return -1; + } + + 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; } + + if (0 != osip_strcasecmp (remote_med->m_media, "audio")) { + // if this is not an "audio" media, we set it to 0 + media << "m=" << remote_med->m_media << " 0 " << remote_med->m_proto << " \r\n"; + } else { + std::ostringstream listCodec; + std::ostringstream listRtpMap; + + // search for compatible codec: foreach payload + int iPayload = 0; + while (!osip_list_eol(remote_med->m_payloads, iPayload)) { + tmp = (char *)osip_list_get(remote_med->m_payloads, iPayload); + if (tmp!=NULL) { + int payload = atoi(tmp); + AudioCodec* audiocodec = _codecMap.getCodec((CodecType)payload); + if (audiocodec!=0 && audiocodec->isActive()) { + listCodec << payload << " "; + listRtpMap << "a=rtpmap: " << payload << " " << audiocodec->getCodecName() << "/" << audiocodec->getClockRate(); + if ( audiocodec->getChannel() != 1) { + listRtpMap << "/" << audiocodec->getChannel(); + } + listRtpMap << "\r\n"; + } + } + iPayload++; + } + if (listCodec.str().empty()) { + 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 << " " << 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", 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"); + _debug(" sdp: %s", buf); + return 0; +} + + + // 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++; + } + + /* 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); + } + + _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; +} + +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; +} + +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; +} + +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; +} -- GitLab