Skip to content
Snippets Groups Projects
Commit 3111a739 authored by yanmorin's avatar yanmorin
Browse files

Adding IAXCall and beginning of iax get event

parent 087e935b
No related branches found
No related tags found
No related merge requests found
...@@ -15,8 +15,8 @@ if USE_IAX ...@@ -15,8 +15,8 @@ if USE_IAX
IAX_LIBS = $(top_builddir)/libs/libiax2/src/libiax.la IAX_LIBS = $(top_builddir)/libs/libiax2/src/libiax.la
IAX_FLAGS = -DUSE_IAX IAX_FLAGS = -DUSE_IAX
IAX_CFLAGS = -I$(top_srcdir)/libs/libiax2/src/ IAX_CFLAGS = -I$(top_srcdir)/libs/libiax2/src/
IAXSOURCES = iaxaccount.cpp iaxvoiplink.cpp IAXSOURCES = iaxaccount.cpp iaxvoiplink.cpp iaxcall.cpp
IAXHEADERS = iaxaccount.h iaxvoiplink.h IAXHEADERS = iaxaccount.h iaxvoiplink.h iaxcall.h
else else
IAX_LIBS = IAX_LIBS =
IAX_FLAGS = IAX_FLAGS =
......
/*
* 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
* 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 "sipcall.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()
{
}
CodecDescriptorMap&
SIPCall::getCodecMap()
{
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;
}
/*
* 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 IAXCALL_H
#define IAXCALL_H
#include "call.h"
#include <iax-client.h>
/**
* IAXCall are IAX implementation of a normal Call
* @author Yan Morin <yan.morin@gmail.com>
*/
class IAXCall : public Call
{
public:
IAXCall(const CallID& id, Call::CallType type);
~IAXCall();
/** Get the session pointer or 0 */
struct iax_session* getSession() { return _session; }
/** Set the session pointer
* @param session the session pointer to assign
*/
void setSession(struct iax_session* session) { _session = session; }
private:
// each call is associate to a session
struct iax_session* _session;
};
#endif
...@@ -18,6 +18,8 @@ ...@@ -18,6 +18,8 @@
*/ */
#include "iaxvoiplink.h" #include "iaxvoiplink.h"
#include "global.h" // for _debug #include "global.h" // for _debug
#include "iaxcall.h"
#include "eventthread.h"
#define IAX_SUCCESS 0 #define IAX_SUCCESS 0
#define IAX_FAILURE -1 #define IAX_FAILURE -1
...@@ -25,11 +27,14 @@ ...@@ -25,11 +27,14 @@
IAXVoIPLink::IAXVoIPLink(const AccountID& accountID) IAXVoIPLink::IAXVoIPLink(const AccountID& accountID)
: VoIPLink(accountID) : VoIPLink(accountID)
{ {
_evThread = new EventThread(this);
} }
IAXVoIPLink::~IAXVoIPLink() IAXVoIPLink::~IAXVoIPLink()
{ {
delete _evThread; _evThread = 0;
terminate();
} }
bool bool
...@@ -59,3 +64,57 @@ IAXVoIPLink::terminate() ...@@ -59,3 +64,57 @@ IAXVoIPLink::terminate()
// hangup all call // hangup all call
// iax_hangup(calls[callNo].session,"Dumped Call"); // iax_hangup(calls[callNo].session,"Dumped Call");
} }
void
IAXVoIPLink::getEvent()
{
// mutex here
iax_event* event = 0;
IAXCall* call = 0;
while ( (event = iax_get_event(0)) != 0 ) {
call = iaxFindCallBySession(event->session);
if (call!=0) {
iaxHandleCallEvent(event, call);
}
return;
}
iax_event_free(event);
// thread wait 5 second
// unlock mutex
}
bool
IAXVoIPLink::setRegister()
{
return false;
}
bool
IAXVoIPLink::setUnregister()
{
return false;
}
IAXCall*
IAXVoIPLink::iaxFindCallBySession(struct iax_session* session)
{
// access to callMap shoud use that
// the code below is like findSIPCallWithCid()
ost::MutexLock m(_callMapMutex);
IAXCall* call = 0;
CallMap::iterator iter = _callMap.begin();
while(iter != _callMap.end()) {
call = dynamic_cast<IAXCall*>(iter->second);
if (call && call->getSession() == session) {
return call;
}
iter++;
}
return 0; // not found
}
void
IAXVoIPLink::iaxHandleCallEvent(iax_event* event, IAXCall* call)
{
}
...@@ -20,9 +20,10 @@ ...@@ -20,9 +20,10 @@
#define IAXVOIPLINK_H #define IAXVOIPLINK_H
#include "voIPLink.h" #include "voIPLink.h"
#include "iax-client.h" #include <iax-client.h>
class AudioCodec; class EventThread;
class IAXCall;
/** /**
* VoIPLink contains a thread that listen to external events * VoIPLink contains a thread that listen to external events
...@@ -36,13 +37,13 @@ public: ...@@ -36,13 +37,13 @@ public:
~IAXVoIPLink(); ~IAXVoIPLink();
void getEvent (void) { } void getEvent(void);
bool init (void); bool init (void);
bool checkNetwork (void) { return false; } bool checkNetwork (void) { return false; }
void terminate (void); void terminate (void);
bool setRegister (void) { return false; } bool setRegister (void);
bool setUnregister (void) { return false; } bool setUnregister (void);
Call* newOutgoingCall(const CallID& id, const std::string& toUrl) {return 0; } Call* newOutgoingCall(const CallID& id, const std::string& toUrl) {return 0; }
bool answer(const CallID& id) {return false;} bool answer(const CallID& id) {return false;}
...@@ -55,6 +56,24 @@ public: ...@@ -55,6 +56,24 @@ public:
bool refuse (const CallID& id) { return false; } bool refuse (const CallID& id) { return false; }
bool carryingDTMFdigits(const CallID& id, char code) { return false; } bool carryingDTMFdigits(const CallID& id, char code) { return false; }
bool sendMessage(const std::string& to, const std::string& body) { return false; } bool sendMessage(const std::string& to, const std::string& body) { return false; }
private:
/**
* Find a iaxcall by iax session number
* @param session an iax_session valid pointer
* @return iaxcall or 0 if not found
*/
IAXCall* iaxFindCallBySession(struct iax_session *session);
/**
* Handle IAX Event for a call
* @param event An iax_event pointer
* @param call An IAXCall pointer
*/
void iaxHandleCallEvent(iax_event* event, IAXCall* call);
EventThread* _evThread;
}; };
#endif #endif
/* /*
* Copyright (C) 2004-2006 Savoir-Faire Linux inc. * Copyright (C) 2006 Savoir-Faire Linux inc.
* Author: Yan Morin <yan.morin@savoirfairelinux.com> * 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 * 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 * it under the terms of the GNU General Public License as published by
...@@ -18,636 +17,16 @@ ...@@ -18,636 +17,16 @@
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/ */
#include "sipcall.h" #include "iaxcall.h"
#include "global.h" // for _debug #include "global.h" // for _debug
#include <sstream> // for media buffer
#define _SENDRECV 0 IAXCall::IAXCall(const CallID& id, Call::CallType type) : Call(id, type), _session(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()
{
}
CodecDescriptorMap&
SIPCall::getCodecMap()
{
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? IAXCall::~IAXCall()
int
SIPCall::sdp_complete_message(sdp_message_t * remote_sdp, osip_message_t * msg)
{ {
// Format port to a char* _session = 0; // just to be sure to don't have unknown pointer, do not delete it!
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;
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment