Skip to content
Snippets Groups Projects
sipcall.cpp 22.9 KiB
Newer Older
yanmorin's avatar
 
yanmorin committed
/**
 *  Copyright (C) 2004-2005 Savoir-Faire Linux inc.
 *  Author: Yan Morin <yan.morin@savoirfairelinux.com>
 *  Author: Laurielle Lea <laurielle.lea@savoirfairelinux.com> 
savoirfairelinux's avatar
savoirfairelinux committed
 *
 * Portions Copyright (C) 2002,2003   Aymeric Moizard <jack@atosc.org>
 *
 * 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 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.
 */

llea's avatar
llea committed
#include <osipparser2/sdp_message.h>
yanmorin's avatar
 
yanmorin committed
#include <string.h> // strcpy
jpbl's avatar
jpbl committed
 
llea's avatar
llea committed
// For AF_INET
#include <sys/socket.h>

llea's avatar
llea committed
#include "global.h"
llea's avatar
llea committed
#include "audio/audiocodec.h"
jpbl's avatar
jpbl committed
#include "audio/codecDescriptor.h"
savoirfairelinux's avatar
savoirfairelinux committed
#include "sipcall.h"

yanmorin's avatar
 
yanmorin committed
SipCall::SipCall (CALLID id, CodecDescriptorVector* cdv) : _localIp("127.0.0.1")
llea's avatar
llea committed
{
yanmorin's avatar
 
yanmorin committed
  _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
  _cdv = cdv;
  _audiocodec = NULL;

  _local_audio_port = 0;
  _remote_sdp_audio_port = 0;
  _local_sendrecv  = 0;           /* _SENDRECV, _SENDONLY, _RECVONLY */
  _remote_sendrecv = 0;
yanmorin's avatar
 
yanmorin committed

  _reinvite = false;
llea's avatar
llea committed
}


SipCall::~SipCall (void) 
{
	dealloc();
yanmorin's avatar
 
yanmorin committed
  //delete _audiocodec;  don't delete it, the Manager will do it...
  _audiocodec = NULL;
llea's avatar
llea committed
}

void
SipCall::setLocalAudioPort (int newport) 
{
	_local_audio_port = newport;
}

int
SipCall::getLocalAudioPort (void) 
{
	return _local_audio_port;
}

void
yanmorin's avatar
 
yanmorin committed
SipCall::setId (CALLID id)
llea's avatar
llea committed
{
	_id = id;
}

yanmorin's avatar
 
yanmorin committed
CALLID
llea's avatar
llea committed
SipCall::getId (void)
{
	return _id;
llea's avatar
llea committed
void
SipCall::setDid (int did)
{
	_did = did;
llea's avatar
llea committed
int
SipCall::getDid (void)
{
	return _did;
savoirfairelinux's avatar
savoirfairelinux committed
}

void
llea's avatar
llea committed
SipCall::setCid (int cid)
{
	_cid = cid;
}

int
SipCall::getCid (void)
{
	return _cid;
llea's avatar
llea committed
void
SipCall::setTid (int tid)
{
	_tid = tid;
}

int
SipCall::getTid (void)
{
	return _tid;
}

savoirfairelinux's avatar
savoirfairelinux committed
int
llea's avatar
llea committed
SipCall::getRemoteSdpAudioPort (void)
{
	return _remote_sdp_audio_port;
}

char*
SipCall::getRemoteSdpAudioIp (void)
{
	return _remote_sdp_audio_ip;
}

AudioCodec*
SipCall::getAudioCodec (void)
{
	return _audiocodec;
}

void
SipCall::setAudioCodec (AudioCodec* ac)
{
yanmorin's avatar
 
yanmorin committed
  // it use a new!
yanmorin's avatar
 
yanmorin committed
  // delete _audiocodec;
 _audiocodec = ac;
savoirfairelinux's avatar
savoirfairelinux committed
}

// newIncomingCall is called when the IP-Phone user receives a new call.
int 
SipCall::newIncomingCall (eXosip_event_t *event) {	

yanmorin's avatar
 
yanmorin committed
  _cid = event->cid;
  _did = event->did;
  _tid = event->tid;
llea's avatar
llea committed

yanmorin's avatar
 
yanmorin committed
  if (_did < 1 && _cid < 1) {
    return -1; /* not enough information for this event?? */
  }
  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);
yanmorin's avatar
 
yanmorin committed
    _debug("            Status: %d %s\n", _status_code, _reason_phrase);
yanmorin's avatar
 
yanmorin committed
  }
llea's avatar
llea committed

yanmorin's avatar
 
yanmorin committed
  strcpy(_remote_uri, "");
  _name = "";
  _number = "";
  if (event->request != NULL) {
    char *tmp = NULL;
llea's avatar
llea committed

yanmorin's avatar
 
yanmorin committed
    osip_from_to_str(event->request->from, &tmp);
    if (tmp != NULL) {
      snprintf (_remote_uri, 255, "%s", tmp);
      osip_free (tmp);
llea's avatar
llea committed

yanmorin's avatar
 
yanmorin committed
      // Get the name/number
      osip_from_t *from;
      osip_from_init(&from);
      osip_from_parse(from, _remote_uri);
yanmorin's avatar
 
yanmorin committed
      char *name = osip_from_get_displayname(from);
      if ( name != NULL ) {
        _name = name;
      }
yanmorin's avatar
 
yanmorin committed
      osip_uri_t* url = osip_from_get_url(from); 
yanmorin's avatar
 
yanmorin committed
      if ( url != NULL && url->username != NULL) {
yanmorin's avatar
 
yanmorin committed
        _number = url->username;
      }
      osip_from_free(from);
llea's avatar
llea committed
    }
yanmorin's avatar
 
yanmorin committed
  }
yanmorin's avatar
 
yanmorin committed
  _debug("            Name: %s\n", _name.c_str());
  _debug("            Number: %s\n", _number.c_str());
  _debug("            Remote URI: %s\n", _remote_uri);
llea's avatar
llea committed

yanmorin's avatar
 
yanmorin committed
  /* negotiate payloads */
  sdp_message_t *remote_sdp = NULL;
  if (event->request != NULL) {
yanmorin's avatar
 
yanmorin committed
    eXosip_lock();
yanmorin's avatar
 
yanmorin committed
    remote_sdp = eXosip_get_sdp_info (event->request);
yanmorin's avatar
 
yanmorin committed
    eXosip_unlock();
yanmorin's avatar
 
yanmorin committed
  }
  if (remote_sdp == NULL) {
yanmorin's avatar
 
yanmorin committed
    _debug("< Sending 400 Bad Request (no SDP)\n");
yanmorin's avatar
 
yanmorin committed
    eXosip_lock();
yanmorin's avatar
 
yanmorin committed
    eXosip_call_send_answer (_tid, 400, NULL);
yanmorin's avatar
 
yanmorin committed
    eXosip_unlock();
yanmorin's avatar
 
yanmorin committed
    return -1;
yanmorin's avatar
 
yanmorin committed
  }
  /* TODO: else build an offer */
llea's avatar
llea committed

yanmorin's avatar
 
yanmorin committed
  // Remote Media IP
yanmorin's avatar
 
yanmorin committed
  eXosip_lock();
yanmorin's avatar
 
yanmorin committed
  sdp_connection_t *conn = eXosip_get_audio_connection (remote_sdp);
yanmorin's avatar
 
yanmorin committed
  eXosip_unlock();
yanmorin's avatar
 
yanmorin committed
  if (conn != NULL && conn->c_addr != NULL) {
      snprintf (_remote_sdp_audio_ip, 49, "%s", conn->c_addr);
yanmorin's avatar
 
yanmorin committed
      _debug("            Remote Audio IP: %s\n", _remote_sdp_audio_ip);
yanmorin's avatar
 
yanmorin committed
  }
llea's avatar
llea committed

yanmorin's avatar
 
yanmorin committed
  // Remote Media Port
yanmorin's avatar
 
yanmorin committed
  eXosip_lock();
yanmorin's avatar
 
yanmorin committed
  sdp_media_t *remote_med = eXosip_get_audio_media (remote_sdp);
yanmorin's avatar
 
yanmorin committed
  eXosip_unlock();
yanmorin's avatar
 
yanmorin committed

yanmorin's avatar
 
yanmorin committed
  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_message_free (remote_sdp);
yanmorin's avatar
 
yanmorin committed
    return -1;
yanmorin's avatar
 
yanmorin committed
  }
  _remote_sdp_audio_port = atoi(remote_med->m_port);
yanmorin's avatar
 
yanmorin committed
  _debug("            Remote Audio Port: %d\n", _remote_sdp_audio_port);
yanmorin's avatar
 
yanmorin committed

  // 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 && ( 0 == osip_strcasecmp (tmp, "0") || 0 == osip_strcasecmp (tmp, "8") )) {
        break;
      }
      tmp = NULL;
      pos++;
llea's avatar
llea committed
    }
yanmorin's avatar
 
yanmorin committed
  }
  if (tmp != NULL) {
    payload = atoi (tmp);
yanmorin's avatar
 
yanmorin committed
    _debug("            Payload: %d\n", payload);
yanmorin's avatar
 
yanmorin committed
    setAudioCodec(_cdv->at(0)->alloc(payload, "")); // codec builder for the mic
  } else {
    _debug("< Sending 415 Unsupported media type\n");
    eXosip_lock();
    eXosip_call_send_answer (_tid, 415, NULL);
    eXosip_unlock();
    sdp_message_free (remote_sdp);
yanmorin's avatar
 
yanmorin committed
    return -1;
yanmorin's avatar
 
yanmorin committed
  }
llea's avatar
llea committed

yanmorin's avatar
 
yanmorin committed
  osip_message_t *answer = 0;
  eXosip_lock();
  _debug("< Building Answer 183\n");
  if (0 == eXosip_call_build_answer (_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");
yanmorin's avatar
 
yanmorin committed
      eXosip_call_send_answer (_tid, 415, NULL);
yanmorin's avatar
 
yanmorin committed
    } else {
llea's avatar
llea committed

yanmorin's avatar
 
yanmorin committed
      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 */
        _remote_sendrecv = sdp_analyse_attribute (remote_sdp, remote_med);
        _local_sendrecv =  sdp_analyse_attribute (local_sdp, local_med);
yanmorin's avatar
 
yanmorin committed
        _debug("            Remote SendRecv: %d\n", _remote_sendrecv);
        _debug("            Local  SendRecv: %d\n", _local_sendrecv);
yanmorin's avatar
 
yanmorin committed
        if (_local_sendrecv == _SENDRECV) {
          if (_remote_sendrecv == _SENDONLY)      { _local_sendrecv = _RECVONLY; }
          else if (_remote_sendrecv == _RECVONLY) { _local_sendrecv = _SENDONLY; }
        }
yanmorin's avatar
 
yanmorin committed
        _debug("            Final Local SendRecv: %d\n", _local_sendrecv);
yanmorin's avatar
 
yanmorin committed
        sdp_message_free (local_sdp);
      }
yanmorin's avatar
 
yanmorin committed
      _debug("< Sending answer 183\n");
yanmorin's avatar
 
yanmorin committed
      if (0 != eXosip_call_send_answer (_tid, 183, answer)) {
        _debug("SipCall::newIncomingCall: cannot send 183 progress?\n");
      }
llea's avatar
llea committed
    }
yanmorin's avatar
 
yanmorin committed
  }
  eXosip_unlock ();
yanmorin's avatar
 
yanmorin committed
  sdp_message_free (remote_sdp);
yanmorin's avatar
 
yanmorin committed

yanmorin's avatar
 
yanmorin committed
  return 0;
yanmorin's avatar
 
yanmorin committed
// 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;

  if (_did < 1 && _cid < 1) {
    return -1; /* not enough information for this event?? */
  }
  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);
yanmorin's avatar
 
yanmorin committed
    _debug("            Status: %d %s\n", _status_code, _reason_phrase);
yanmorin's avatar
 
yanmorin committed
  }

  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); 
yanmorin's avatar
 
yanmorin committed
      if ( url != NULL && url->username != NULL ) {
yanmorin's avatar
 
yanmorin committed
        _number = url->username;
      }
      osip_from_free(from);
    }
  }
yanmorin's avatar
 
yanmorin committed
  _debug("            Name: %s\n", _name.c_str());
  _debug("            Number: %s\n", _number.c_str());
  _debug("            Remote URI: %s\n", _remote_uri);
yanmorin's avatar
 
yanmorin committed

  /* 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) {
yanmorin's avatar
 
yanmorin committed
    _debug("< Sending 400 Bad Request (no sdp)\n");
yanmorin's avatar
 
yanmorin committed
    // Send 400 BAD REQUEST
    eXosip_lock();
    eXosip_call_send_answer (_tid, 400, NULL);
    eXosip_unlock();
    return 0;
  }
  /* 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);
yanmorin's avatar
 
yanmorin committed
      _debug("            Remote Audio IP: %s\n", _remote_sdp_audio_ip);
yanmorin's avatar
 
yanmorin committed
  }

  // 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_message_free (remote_sdp);
    return 0;
  }
  _remote_sdp_audio_port = atoi(remote_med->m_port);
yanmorin's avatar
 
yanmorin committed
  _debug("            Remote Audio Port: %d\n", _remote_sdp_audio_port);
yanmorin's avatar
 
yanmorin committed

  // 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 && ( 0 == osip_strcasecmp (tmp, "0") || 0 == osip_strcasecmp (tmp, "8") )) {
        break;
      }
      tmp = NULL;
      pos++;
    }
  }
  if (tmp != NULL) {
    payload = atoi (tmp);
yanmorin's avatar
 
yanmorin committed
    _debug("            Payload: %d\n", payload);
yanmorin's avatar
 
yanmorin committed
    setAudioCodec(_cdv->at(0)->alloc(payload, "")); // codec builder for the mic
  } else {
    _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;
  }

  osip_message_t *answer = 0;
  eXosip_lock();
  _debug("< Building Answer 200\n");
  if (0 == eXosip_call_build_answer (_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);
      _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 */
        _remote_sendrecv = sdp_analyse_attribute (remote_sdp, remote_med);
        _local_sendrecv =  sdp_analyse_attribute (local_sdp, local_med);
yanmorin's avatar
 
yanmorin committed
        _debug("            Remote SendRecv: %d\n", _remote_sendrecv);
        _debug("            Local  SendRecv: %d\n", _local_sendrecv);
yanmorin's avatar
 
yanmorin committed
        if (_local_sendrecv == _SENDRECV) {
          if (_remote_sendrecv == _SENDONLY)      { _local_sendrecv = _RECVONLY; }
          else if (_remote_sendrecv == _RECVONLY) { _local_sendrecv = _SENDONLY; }
        }
yanmorin's avatar
 
yanmorin committed
        _debug("            Final Local SendRecv: %d\n", _local_sendrecv);
yanmorin's avatar
 
yanmorin committed
        sdp_message_free (local_sdp);
      }
      _debug("< Sending answer 200\n");
      if (0 != eXosip_call_send_answer (_tid, 200, answer)) {
        _debug("SipCall::newIncomingCall: cannot send 200 OK?\n");
      }
    }
  }
  eXosip_unlock ();
  sdp_message_free (remote_sdp);
  _reinvite = true;
  return 0;
}
savoirfairelinux's avatar
savoirfairelinux committed

int 
SipCall::ringingCall (eXosip_event_t *event) {     

yanmorin's avatar
 
yanmorin committed
  this->_cid = event->cid;
  this->_did = event->did;
  this->_tid = event->tid;
savoirfairelinux's avatar
savoirfairelinux committed

yanmorin's avatar
 
yanmorin committed
  if (this->_did < 1 && this->_cid < 1) {
    return -1; 
  }
llea's avatar
llea committed

yanmorin's avatar
 
yanmorin committed
  osip_strncpy (_textinfo, event->textinfo, 255);
llea's avatar
llea committed

yanmorin's avatar
 
yanmorin committed
  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;
llea's avatar
llea committed

yanmorin's avatar
 
yanmorin committed
    osip_from_to_str (event->request->from, &tmp);
    if (tmp != NULL) {
      snprintf (_remote_uri, 255, "%s", tmp);
      osip_free (tmp);
    }
  }
savoirfairelinux's avatar
savoirfairelinux committed
  	return 0;
}

llea's avatar
llea committed
int
SipCall::receivedAck (eXosip_event_t *event)
{
yanmorin's avatar
 
yanmorin committed
  _cid = event->cid;
  _did = event->did;
llea's avatar
llea committed
  return 0;
}
savoirfairelinux's avatar
savoirfairelinux committed

yanmorin's avatar
 
yanmorin committed


savoirfairelinux's avatar
savoirfairelinux committed
int 
SipCall::answeredCall(eXosip_event_t *event) {
yanmorin's avatar
 
yanmorin committed
  _cid = event->cid;
  _did = event->did;
yanmorin's avatar
 
yanmorin committed

  if (_did < 1 && _cid < 1)	{
    return -1; /* not enough information for this event?? */
  }
yanmorin's avatar
 
yanmorin committed
  osip_strncpy(this->_textinfo,   event->textinfo, 255);
llea's avatar
llea committed

yanmorin's avatar
 
yanmorin committed
  if (event->response != NULL) {
    _status_code = event->response->status_code;
    snprintf (_reason_phrase, 49, "%s", event->response->reason_phrase);
llea's avatar
llea committed

yanmorin's avatar
 
yanmorin committed
    char *tmp = NULL;
llea's avatar
llea committed

yanmorin's avatar
 
yanmorin committed
    osip_from_to_str (event->response->from, &tmp);
    if (tmp != NULL) {
        snprintf (_remote_uri, 255, "%s", tmp);
        osip_free (tmp);
savoirfairelinux's avatar
savoirfairelinux committed
    }
yanmorin's avatar
 
yanmorin committed
  }
yanmorin's avatar
 
yanmorin committed
  _debug("            Status: %d %s\n", _status_code, _reason_phrase);
  _debug("            From URI: %s\n", _remote_uri);
yanmorin's avatar
 
yanmorin committed

  eXosip_lock ();
  {
llea's avatar
llea committed
    osip_message_t *ack = NULL;
    int i;

    i = eXosip_call_build_ack (_did, &ack);
    if (i != 0) {
yanmorin's avatar
 
yanmorin committed
      _debug("SipCall::answeredCall: Cannot build ACK for call!\n");
llea's avatar
llea committed
    } else {
yanmorin's avatar
 
yanmorin committed
      sdp_message_t *local_sdp = NULL;
      sdp_message_t *remote_sdp = NULL;
llea's avatar
llea committed

yanmorin's avatar
 
yanmorin committed
      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");
llea's avatar
llea committed
        }
yanmorin's avatar
 
yanmorin committed
      }
      sdp_message_free (local_sdp);
      sdp_message_free (remote_sdp);
llea's avatar
llea committed

yanmorin's avatar
 
yanmorin committed
      _debug("< Send ACK\n");
      eXosip_call_send_ack (_did, ack);
    }
  }
  eXosip_unlock ();
llea's avatar
llea committed

yanmorin's avatar
 
yanmorin committed
  return 0;
llea's avatar
llea committed
void
SipCall::answeredCall_without_hold (eXosip_event_t *event) 
{
yanmorin's avatar
 
yanmorin committed
  if (event->response == NULL ) { return; }

yanmorin's avatar
 
yanmorin committed
  // TODO: understand this code..
yanmorin's avatar
 
yanmorin committed
  if (_cid!=0) {
yanmorin's avatar
 
yanmorin committed
    eXosip_lock();
yanmorin's avatar
 
yanmorin committed
    sdp_message_t *sdp = eXosip_get_sdp_info (event->response);
yanmorin's avatar
 
yanmorin committed
    eXosip_unlock();
yanmorin's avatar
 
yanmorin committed
    if (sdp != NULL) {
yanmorin's avatar
 
yanmorin committed
       /* audio is started and session has just been modified */
yanmorin's avatar
 
yanmorin committed
      sdp_message_free (sdp);
llea's avatar
llea committed
    }
yanmorin's avatar
 
yanmorin committed
  }
savoirfairelinux's avatar
savoirfairelinux committed

yanmorin's avatar
 
yanmorin committed
  if (event->request != NULL) {   /* audio is started */ 
llea's avatar
llea committed

yanmorin's avatar
 
yanmorin committed
    eXosip_lock();
yanmorin's avatar
 
yanmorin committed
    sdp_message_t *local_sdp = eXosip_get_sdp_info (event->request);
    sdp_message_t *remote_sdp = eXosip_get_sdp_info (event->response);
yanmorin's avatar
 
yanmorin committed
    eXosip_unlock();
llea's avatar
llea committed

yanmorin's avatar
 
yanmorin committed
    sdp_media_t *remote_med = NULL;
    char *tmp = NULL;
yanmorin's avatar
 
yanmorin committed
    if (remote_sdp == NULL) {
yanmorin's avatar
 
yanmorin committed
      _debug("SipCall::answeredCall_without_hold: No remote SDP body found for call\n");
yanmorin's avatar
 
yanmorin committed
      /* TODO: remote_sdp = retreive from ack above */
    } else {
yanmorin's avatar
 
yanmorin committed
      eXosip_lock();
yanmorin's avatar
 
yanmorin committed
      sdp_connection_t *conn = eXosip_get_audio_connection (remote_sdp);
yanmorin's avatar
 
yanmorin committed
      if (conn != NULL && conn->c_addr != NULL) {
          snprintf (_remote_sdp_audio_ip, 49, "%s", conn->c_addr);
      }
yanmorin's avatar
 
yanmorin committed

yanmorin's avatar
 
yanmorin committed
      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);
      }
yanmorin's avatar
 
yanmorin committed
      eXosip_unlock();
yanmorin's avatar
 
yanmorin committed
      _debug("            Remote Audio: %s:%d\n", _remote_sdp_audio_ip, _remote_sdp_audio_port);
yanmorin's avatar
 
yanmorin committed

      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);
      }

      if (tmp != NULL) {
yanmorin's avatar
 
yanmorin committed
        payload = atoi (tmp);
        setAudioCodec(_cdv->at(0)->alloc(payload, ""));
yanmorin's avatar
 
yanmorin committed
      }
    }
yanmorin's avatar
 
yanmorin committed
    _debug("            Remote Payload: %d\n", payload);
llea's avatar
llea committed

yanmorin's avatar
 
yanmorin committed
    if (local_sdp == NULL) {
yanmorin's avatar
 
yanmorin committed
      _debug("SipCall::answeredCall_without_hold: SDP body was probably in the ACK (TODO)\n");
yanmorin's avatar
 
yanmorin committed
    }

    if (remote_sdp != NULL && local_sdp != NULL) {
      int audio_port = 0;
yanmorin's avatar
 
yanmorin committed
      eXosip_lock();
yanmorin's avatar
 
yanmorin committed
      sdp_media_t *local_med = eXosip_get_audio_media (local_sdp);
yanmorin's avatar
 
yanmorin committed
      eXosip_unlock();
yanmorin's avatar
 
yanmorin committed
      if (local_med != NULL && local_med->m_port != NULL) {
        audio_port = atoi (local_med->m_port);
      }
yanmorin's avatar
 
yanmorin committed
      _debug("            Local Audio port: %d\n", audio_port);
yanmorin's avatar
 
yanmorin committed

      if (tmp != NULL && audio_port > 0
          && _remote_sdp_audio_port > 0
          && _remote_sdp_audio_ip[0] != '\0') {

        /* 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;
        }
      }
yanmorin's avatar
 
yanmorin committed
      _debug("            Remote Sendrecv: %d\n", _remote_sendrecv);
      _debug("            Local Sendrecv: %d\n", _local_sendrecv);
yanmorin's avatar
 
yanmorin committed
    }
    sdp_message_free (local_sdp);
    sdp_message_free (remote_sdp);
  }
llea's avatar
llea committed
SipCall::sdp_complete_message(sdp_message_t * remote_sdp, 
		osip_message_t * msg)
{
  sdp_media_t *remote_med;
  char *tmp = NULL;
  char buf[4096];
  int pos;
savoirfairelinux's avatar
savoirfairelinux committed

llea's avatar
llea committed
  char localip[128];
savoirfairelinux's avatar
savoirfairelinux committed

llea's avatar
llea committed
  	// Format port to a char*
  	char port_tmp[64];
	bzero(port_tmp, 64);
	snprintf(port_tmp, 63, "%d", _local_audio_port);
	
  	if (remote_sdp == NULL) {
yanmorin's avatar
 
yanmorin committed
      	_debug("SipCall::sdp_complete_message: No remote SDP body found for call\n");
llea's avatar
llea committed
      	return -1;
    }
  	if (msg == NULL) {
yanmorin's avatar
 
yanmorin committed
    	_debug("SipCall::sdp_complete_message: No message to complete\n");
llea's avatar
llea committed
      	return -1;
    }

yanmorin's avatar
 
yanmorin committed
        // this exosip is locked and is protected by other function
llea's avatar
llea committed
  	eXosip_guess_localip (AF_INET, localip, 128);
  	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", localip, localip);

  	pos = 0;
  	while (!osip_list_eol (remote_sdp->m_medias, pos)) {
      	char payloads[128];
      	int pos2;

      	memset (payloads, '\0', sizeof (payloads));
      	remote_med = (sdp_media_t *) osip_list_get (remote_sdp->m_medias, pos);

      	if (0 == osip_strcasecmp (remote_med->m_media, "audio")) {
          	pos2 = 0;
          	while (!osip_list_eol (remote_med->m_payloads, pos2)) {
              	tmp = (char *) osip_list_get (remote_med->m_payloads, pos2);
              	if (tmp != NULL && 
						(0 == osip_strcasecmp (tmp, "0")
                   		|| 0 == osip_strcasecmp (tmp, "8")
						|| 0 == osip_strcasecmp (tmp, "3"))) {
                  	strcat (payloads, tmp);
                  	strcat (payloads, " ");
                }
              	pos2++;
            }
          	strcat (buf, "m=");
          	strcat (buf, remote_med->m_media);
          	if (pos2 == 0 || payloads[0] == '\0') {
              	strcat (buf, " 0 RTP/AVP \r\n");
              	return -1;        /* refuse anyway */
          	} else {
			 	strcat (buf, " ");
              	strcat (buf, port_tmp);
              	strcat (buf, " RTP/AVP ");
              	strcat (buf, payloads);
              	strcat (buf, "\r\n");

              	if (NULL != strstr (payloads, " 0 ")
                  || (payloads[0] == '0' && payloads[1] == ' '))
                	strcat (buf, "a=rtpmap:0 PCMU/8000\r\n");
              	if (NULL != strstr (payloads, " 8 ")
                  || (payloads[0] == '8' && payloads[1] == ' '))
                	strcat (buf, "a=rtpmap:8 PCMA/8000\r\n");
				if (NULL != strstr (payloads, " 3 ")
                  || (payloads[0] == '8' && payloads[1] == ' '))
                	strcat (buf, "a=rtpmap:8 GSM/8000\r\n");
            }
      	} else {
          	strcat (buf, "m=");
          	strcat (buf, remote_med->m_media);
          	strcat (buf, " 0 ");
          	strcat (buf, remote_med->m_proto);
          	strcat (buf, " \r\n");
        }
      	pos++;
    }
savoirfairelinux's avatar
savoirfairelinux committed

llea's avatar
llea committed
  	osip_message_set_body (msg, buf, strlen (buf));
  	osip_message_set_content_type (msg, "application/sdp");
savoirfairelinux's avatar
savoirfairelinux committed
  	return 0;
}

llea's avatar
llea committed
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;
}

savoirfairelinux's avatar
savoirfairelinux committed
void
SipCall::alloc(void) {
yanmorin's avatar
 
yanmorin committed
  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';
yanmorin's avatar
 
yanmorin committed
  strcpy(this->_remote_sdp_audio_ip, "127.0.0.1");
savoirfairelinux's avatar
savoirfairelinux committed
}

void
SipCall::dealloc(void) {
yanmorin's avatar
 
yanmorin committed
  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;
llea's avatar
llea committed
}

void
SipCall::noSupportedCodec (void) {
yanmorin's avatar
 
yanmorin committed
	_debug("SipCall::noSupportedCodec: Codec no supported\n");