diff --git a/src/Makefile.am b/src/Makefile.am
index dc83d84f8a88dce7600a278648ba0b2d265180b3..7af7dbfec2d5350a0c1b9aa2d9cc6cfa4ec44835 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -29,6 +29,8 @@ sflphoned_SOURCES = \
 		call.cpp \
 		account.cpp \
 		sipcall.cpp \
+		sdp.cpp \
+		sdpmedia.cpp \
 		$(IAXSOURCES) 
 
 sflphoned_CXXFLAGS = \
@@ -67,7 +69,9 @@ noinst_HEADERS = \
 		accountcreator.h \
         sipvoiplink.h \
 		call.h \
-		sipcall.h 
+		sipcall.h \
+		sdp.h \
+		sdpmedia.h
 		
 libsflphone_la_LIBADD = \
 	$(src)/libs/stund/libstun.la \
diff --git a/src/audio/audiortp.cpp b/src/audio/audiortp.cpp
index 24042f7d2f4ce289962eba87805dd1a25a56cc4e..02972a3058afc50dc73fc175fd7aba350e9732f0 100644
--- a/src/audio/audiortp.cpp
+++ b/src/audio/audiortp.cpp
@@ -128,6 +128,7 @@ AudioRtpRTX::AudioRtpRTX (SIPCall *sipcall, bool sym) : time(new ost::Time()), _
         _sessionSend = new ost::RTPSession(local_ip, _ca->getLocalAudioPort());
         _session = NULL;
     } else {
+        _debug ("%i\n", _ca->getLocalAudioPort());
         _session = new ost::SymmetricRTPSession (local_ip, _ca->getLocalAudioPort());
         _sessionRecv = NULL;
         _sessionSend = NULL;
@@ -185,15 +186,16 @@ AudioRtpRTX::initBuffers()
     void
 AudioRtpRTX::initAudioRtpSession (void) 
 {
+
     try {
         if (_ca == 0) { return; }
-        _audiocodec = Manager::instance().getCodecDescriptorMap().getCodec( _ca->getAudioCodec() );
-        _codecSampleRate = _audiocodec->getClockRate();	
+        _audiocodec = _ca->getLocalSDP()->get_session_media ();
+        _codecSampleRate = _audiocodec->getClockRate(); 
 
-        _debug("Init audio RTP session\n");
-        ost::InetHostAddress remote_ip(_ca->getRemoteIp().c_str());
+        ost::InetHostAddress remote_ip(_ca->getLocalSDP()->get_remote_ip().c_str());
+        _debug("Init audio RTP session %s\n", _ca->getLocalSDP()->get_remote_ip().data());
         if (!remote_ip) {
-            _debug("! ARTP Thread Error: Target IP address [%s] is not correct!\n", _ca->getRemoteIp().data());
+            _debug("! ARTP Thread Error: Target IP address [%s] is not correct!\n", _ca->getLocalSDP()->get_remote_ip().data());
             return;
         }
 
@@ -210,12 +212,12 @@ AudioRtpRTX::initAudioRtpSession (void)
         }
 
         if (!_sym) {
-            if ( !_sessionRecv->addDestination(remote_ip, (unsigned short) _ca->getRemoteAudioPort()) ) {
-                _debug("AudioRTP Thread Error: could not connect to port %d\n",  _ca->getRemoteAudioPort());
+            if ( !_sessionRecv->addDestination(remote_ip, (unsigned short) _ca->getLocalSDP()->get_remote_audio_port()) ) {
+                _debug("AudioRTP Thread Error: could not connect to port %d\n",  _ca->getLocalSDP()->get_remote_audio_port());
                 return;
             }
-            if (!_sessionSend->addDestination (remote_ip, (unsigned short) _ca->getRemoteAudioPort())) {
-                _debug("! ARTP Thread Error: could not connect to port %d\n",  _ca->getRemoteAudioPort());
+            if (!_sessionSend->addDestination (remote_ip, (unsigned short) _ca->getLocalSDP()->get_remote_audio_port())) {
+                _debug("! ARTP Thread Error: could not connect to port %d\n", _ca->getLocalSDP()->get_remote_audio_port());
                 return;
             }
 
@@ -233,7 +235,7 @@ AudioRtpRTX::initAudioRtpSession (void)
 
             //_debug("AudioRTP Thread: Added session destination %s\n", remote_ip.getHostname() );
 
-            if (!_session->addDestination (remote_ip, (unsigned short) _ca->getRemoteAudioPort())) {
+            if (!_session->addDestination (remote_ip, (unsigned short)_ca->getLocalSDP()->get_remote_audio_port() )) {
                 return;
             }
 
@@ -251,7 +253,87 @@ AudioRtpRTX::initAudioRtpSession (void)
     } catch(...) {
         _debugException("! ARTP Failure: initialisation failed");
         throw;
-    }
+    }    
+
+/*
+    std::string remoteIP;
+    unsigned int remotePort;
+
+    try {
+        if (_ca == 0) { return; }
+
+        _audiocodec = _ca->getLocalSDP()->get_session_media ();
+
+        if(_audiocodec == 0) { return; }
+
+        _codecSampleRate = _audiocodec->getClockRate();	
+
+        remoteIP = _ca->getLocalSDP()->get_remote_ip();
+        //remoteIP = "192.168.1.234";
+        remotePort = _ca->getLocalSDP()->get_remote_audio_port();
+        _debug("Init audio RTP session - remote IP = %s\n", remoteIP.c_str());
+        ost::InetHostAddress remote_ip(remoteIP.c_str());
+        if (!remote_ip) {
+            _debug("! ARTP Thread Error: Target IP address [%s] is not correct!\n", remoteIP.data());
+            return;
+        }
+
+        if (!_sym) {
+            _sessionRecv->setSchedulingTimeout (10000);
+            _sessionRecv->setExpireTimeout(1000000);
+
+            _sessionSend->setSchedulingTimeout(10000);
+            _sessionSend->setExpireTimeout(1000000);
+        } else {
+            _session->setSchedulingTimeout(10000);
+            _session->setExpireTimeout(1000000);
+        }
+
+        if (!_sym) {
+            _debug("! AudioRTP Thread: Added session destination %s:%d\n", remote_ip.getHostname(), remotePort );
+            if ( !_sessionRecv->addDestination(remote_ip, (unsigned short) remotePort) ) {
+                _debug("AudioRTP Thread Error: could not connect to port %d\n",  remotePort);
+                return;
+            }
+            if (!_sessionSend->addDestination (remote_ip, (unsigned short) remotePort)) {
+                _debug("! ARTP Thread Error: could not connect to port %d\n",  remotePort);
+                return;
+            }
+
+            bool payloadIsSet = false;
+            if (_audiocodec) {
+                if (_audiocodec->hasDynamicPayload()) {
+                    payloadIsSet = _sessionRecv->setPayloadFormat(ost::DynamicPayloadFormat((ost::PayloadType) _audiocodec->getPayload(), _audiocodec->getClockRate()));
+                } else {
+                    payloadIsSet= _sessionRecv->setPayloadFormat(ost::StaticPayloadFormat((ost::StaticPayloadType) _audiocodec->getPayload()));
+                    payloadIsSet = _sessionSend->setPayloadFormat(ost::StaticPayloadFormat((ost::StaticPayloadType) _audiocodec->getPayload()));
+                }
+            }
+            _sessionSend->setMark(true);
+        } else {
+
+            _debug("AudioRTP Thread: Added session destination %s:%d\n", remote_ip.getHostname(), remotePort );
+
+            if (!_session->addDestination (remote_ip, (unsigned short) remotePort)) {
+                _debug ("could not connect to port %d\n", remotePort);
+                return;
+            }
+
+            bool payloadIsSet = false;
+            if (_audiocodec) {
+                if (_audiocodec->hasDynamicPayload()) {
+                    payloadIsSet = _session->setPayloadFormat(ost::DynamicPayloadFormat((ost::PayloadType) _audiocodec->getPayload(), _audiocodec->getClockRate()));
+                } else {
+                    payloadIsSet = _session->setPayloadFormat(ost::StaticPayloadFormat((ost::StaticPayloadType) _audiocodec->getPayload()));
+                }
+            }
+        }
+
+
+    } catch(...) {
+        _debugException("! ARTP Failure: initialisation failed");
+        throw;
+    }*/
 
 }
 
diff --git a/src/call.cpp b/src/call.cpp
index 32cc4d7bcda73c5da7f5fb5f38d4eac563d92f33..b1625d346e3bc726bb6c48c66cf91a49e1323ad5 100644
--- a/src/call.cpp
+++ b/src/call.cpp
@@ -22,14 +22,10 @@
 
 Call::Call(const CallID& id, Call::CallType type)
            : _callMutex()
-           , _codecMap()
-           , _audioCodec()
            , _audioStarted(false)    
            , _localIPAddress("") 
            , _localAudioPort(0)
            , _localExternalAudioPort(0)
-           , _remoteIPAddress("")
-           , _remoteAudioPort(0)
            , _id(id) 
            , _type(type) 
            , _connectionState(Call::Disconnected)
@@ -85,12 +81,6 @@ Call::getState()
   return _callState;
 }
 
-CodecDescriptor& 
-Call::getCodecMap()
-{
-  return _codecMap;
-}
-
 const std::string& 
 Call::getLocalIp()
 {
@@ -105,26 +95,6 @@ Call::getLocalAudioPort()
   return _localAudioPort;
 }
 
-unsigned int 
-Call::getRemoteAudioPort()
-{
-  ost::MutexLock m(_callMutex);  
-  return _remoteAudioPort;
-}
-
-const std::string& 
-Call::getRemoteIp()
-{
-  ost::MutexLock m(_callMutex);  
-  return _remoteIPAddress;
-}
-
-AudioCodecType 
-Call::getAudioCodec()
-{
-  return _audioCodec;  
-}
-
 void 
 Call::setAudioStart(bool start)
 {
diff --git a/src/call.h b/src/call.h
index 6b247e036017d684056f9db64a59d8a1460d35ae..d82ff7ba583c2253571532ddcd7f80561cf3aad2 100644
--- a/src/call.h
+++ b/src/call.h
@@ -23,7 +23,6 @@
 #include <cc++/thread.h> // for mutex
 #include <sstream>
 
-#include "audio/codecDescriptor.h"
 #include "plug-in/audiorecorder/audiorecord.h"
 
 /* 
@@ -145,20 +144,7 @@ class Call{
      */
     bool isAudioStarted();
 
-    // AUDIO
-    /** 
-     * Set internal codec Map: initialization only, not protected 
-     * @param map The codec map
-     */
-    void setCodecMap(const CodecDescriptor& map) { _codecMap = map; } 
-
-    /** 
-     * Get internal codec Map: initialization only, not protected 
-     * @return CodecDescriptor	The codec map
-     */
-    CodecDescriptor& getCodecMap();
-
-    /** 
+        /** 
      * Set my IP [not protected] 
      * @param ip  The local IP address
      */
@@ -194,24 +180,6 @@ class Call{
      */
     unsigned int getLocalAudioPort();
 
-    /** 
-     * Return audio port at destination [mutex protected] 
-     * @return unsigned int The remote audio port
-     */
-    unsigned int getRemoteAudioPort();
-
-    /** 
-     * Return IP of destination [mutex protected]
-     * @return const std:string	The remote IP address
-     */
-    const std::string& getRemoteIp();
-
-    /** 
-     * Return audio codec [mutex protected]
-     * @return AudioCodecType The payload of the codec
-     */
-    AudioCodecType getAudioCodec();
-
     /**
      * @return Return the file name for this call
      */
@@ -246,30 +214,6 @@ class Call{
     /** Protect every attribute that can be changed by two threads */
     ost::Mutex _callMutex;
 
-    /** 
-     * Set remote's IP addr. [not protected]
-     * @param ip  The remote IP address
-     */
-    void setRemoteIP(const std::string& ip)    { _remoteIPAddress = ip; }
-
-    /** 
-     * Set remote's audio port. [not protected]
-     * @param port  The remote audio port
-     */
-    void setRemoteAudioPort(unsigned int port) { _remoteAudioPort = port; }
-
-    /** 
-     * Set the audio codec used.  [not protected] 
-     * @param audioCodec  The payload of the codec
-     */
-    void setAudioCodec(AudioCodecType audioCodec) { _audioCodec = audioCodec; }
-
-    /** Codec Map */
-    CodecDescriptor _codecMap;
-
-    /** Codec pointer */
-    AudioCodecType _audioCodec;
-
     bool _audioStarted;
 
     // Informations about call socket / audio
@@ -283,13 +227,7 @@ class Call{
     /** Port assigned to my machine by the NAT, as seen by remote peer (he connects there) */
     unsigned int _localExternalAudioPort;
 
-    /** Remote's IP address */
-    std::string  _remoteIPAddress;
-
-    /** Remote's audio port */
-    unsigned int _remoteAudioPort;
-
-
+    
   private:  
   
     /** Unique ID of the call */
diff --git a/src/iaxcall.cpp b/src/iaxcall.cpp
index 05327d77d6a15719bf26ce6b394a08ba33a992a1..c2fc71c6ba70db21e319975479a6a4df8eec571c 100644
--- a/src/iaxcall.cpp
+++ b/src/iaxcall.cpp
@@ -112,3 +112,16 @@ IAXCall::getFirstMatchingFormat(int needles)
   }
   return 0;
 }
+
+CodecDescriptor& IAXCall::getCodecMap()
+{
+  return _codecMap;
+}
+
+AudioCodecType IAXCall::getAudioCodec()
+{
+  return _audioCodec;  
+}
+
+
+
diff --git a/src/iaxcall.h b/src/iaxcall.h
index b572a7418bb9fc7b24153a10f8938f2b27afa3ae..0a728248c9c114aad21aaaf6306eb080a8a05875 100644
--- a/src/iaxcall.h
+++ b/src/iaxcall.h
@@ -21,6 +21,8 @@
 #define IAXCALL_H
 
 #include "call.h"
+#include "audio/codecDescriptor.h"
+
 #include <iax2/iax-client.h>
 #include <iax2/frame.h>
 
@@ -90,11 +92,41 @@ public:
      */
     int getFirstMatchingFormat(int needles);
 
+    // AUDIO
+    /** 
+     * Set internal codec Map: initialization only, not protected 
+     * @param map The codec map
+     */
+    void setCodecMap(const CodecDescriptor& map) { _codecMap = map; } 
+
+    /** 
+     * Get internal codec Map: initialization only, not protected 
+     * @return CodecDescriptor	The codec map
+     */
+    CodecDescriptor& getCodecMap();
+
+    /** 
+     * Return audio codec [mutex protected]
+     * @return AudioCodecType The payload of the codec
+     */
+    AudioCodecType getAudioCodec();
 
 private:
     /** Each call is associated with an iax_session */
     struct iax_session* _session;
 
+    /** 
+     * Set the audio codec used.  [not protected] 
+     * @param audioCodec  The payload of the codec
+     */
+    void setAudioCodec(AudioCodecType audioCodec) { _audioCodec = audioCodec; }
+
+    /** Codec Map */
+    CodecDescriptor _codecMap;
+
+    /** Codec pointer */
+    AudioCodecType _audioCodec;
+
     /**
      * Format currently in use in the conversation,
      * sent in each outgoing voice packet.
diff --git a/src/sdp.cpp b/src/sdp.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..011875e2ef90491bac7b74e8f51711e5f600a5c7
--- /dev/null
+++ b/src/sdp.cpp
@@ -0,0 +1,445 @@
+/*
+ *  Copyright (C) 2009 Savoir-Faire Linux inc.
+ *
+ *  Author: Emmanuel Milou <emmanuel.milou@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 3 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 "sdp.h"
+#include "global.h"
+#include "manager.h"
+
+
+static const pj_str_t STR_AUDIO = { (char*)"audio", 5};
+static const pj_str_t STR_VIDEO = { (char*)"video", 5};
+static const pj_str_t STR_IN = { (char*)"IN", 2 };
+static const pj_str_t STR_IP4 = { (char*)"IP4", 3};
+static const pj_str_t STR_IP6 = { (char*)"IP6", 3};
+static const pj_str_t STR_RTP_AVP = { (char*)"RTP/AVP", 7 };
+static const pj_str_t STR_SDP_NAME = { (char*)"sflphone", 8 };
+static const pj_str_t STR_SENDRECV = { (char*)"sendrecv", 8 };
+
+Sdp::Sdp( pj_pool_t *pool ) 
+    : _local_media_cap(), _session_media(0),  _ip_addr( "" ), _local_offer( NULL ), _negociated_offer(NULL), _negociator(NULL), _pool(NULL), _local_extern_audio_port(0) 
+{
+    _pool = pool;
+}
+
+Sdp::~Sdp() {
+
+    //unsigned int k;
+
+    /*
+    for( k=0; k<_session_media.size(); k++ ){
+        delete _session_media[k];
+        _session_media[k] = 0;
+    }*/
+
+    //for( k=0; k<_local_media_cap.size(); k++ ){
+      //  delete _local_media_cap[k];
+        //_local_media_cap[k] = 0;
+    //}
+}
+
+void Sdp::set_media_descriptor_line( sdpMedia *media, pjmedia_sdp_media** p_med ) {
+
+    pjmedia_sdp_media* med;
+    pjmedia_sdp_rtpmap rtpmap;
+    pjmedia_sdp_attr *attr;
+    AudioCodec *codec;
+    int count, i;
+    std::string tmp;
+
+    med = PJ_POOL_ZALLOC_T( _pool, pjmedia_sdp_media );
+
+    // Get the right media format
+    pj_strdup(_pool, &med->desc.media,
+            ( media->get_media_type() == MIME_TYPE_AUDIO ) ? &STR_AUDIO : &STR_VIDEO );
+    med->desc.port_count = 1;
+    med->desc.port = media->get_port();
+    pj_strdup (_pool, &med->desc.transport, &STR_RTP_AVP);
+
+    // Media format ( RTP payload )
+    count = media->get_media_codec_list().size();
+    med->desc.fmt_count = count;
+
+    // add the payload list
+    for(i=0; i<count; i++){
+        codec = media->get_media_codec_list()[i];
+        tmp = this->convert_int_to_string (codec->getPayload ()); 
+        _debug ("%s\n", tmp.c_str());
+        pj_strdup2( _pool, &med->desc.fmt[i], tmp.c_str());
+
+        // Add a rtpmap field for each codec
+        // We could add one only for dynamic payloads because the codecs with static RTP payloads
+        // are entirely defined in the RFC 3351, but if we want to add other attributes like an asymmetric
+        // connection, the rtpmap attribute will be useful to specify for which codec it is applicable
+        rtpmap.pt = med->desc.fmt[i];
+        rtpmap.enc_name = pj_str( (char*) codec->getCodecName().c_str() );
+        rtpmap.clock_rate = codec->getClockRate();
+        // Add the channel number only if different from 1
+        if( codec->getChannel() > 1 )
+            rtpmap.param = pj_str( (char*) codec->getChannel() );
+        else
+            rtpmap.param.slen = 0;
+        pjmedia_sdp_rtpmap_to_attr( _pool, &rtpmap, &attr );
+        med->attr[med->attr_count++] = attr;
+    }
+
+    // Add the direction stream
+    attr = (pjmedia_sdp_attr*)pj_pool_zalloc( _pool, sizeof(pjmedia_sdp_attr) );
+    pj_strdup2( _pool, &attr->name, media->get_stream_direction_str().c_str());
+    med->attr[ med->attr_count++] = attr;
+
+    *p_med = med;
+}
+
+int Sdp::create_local_offer (){
+    pj_status_t status;
+
+    _debug ("Create local offer\n");
+    // Build local media capabilities
+    set_local_media_capabilities ();
+
+    // Reference: RFC 4566 [5]
+
+    /* Create and initialize basic SDP session */
+    this->_local_offer = PJ_POOL_ZALLOC_T(_pool, pjmedia_sdp_session);
+    this->_local_offer->conn = PJ_POOL_ZALLOC_T(_pool, pjmedia_sdp_conn);
+
+    /* Initialize the fields of the struct */
+    sdp_add_protocol();
+    sdp_add_origin();
+    sdp_add_session_name();
+    sdp_add_connection_info();
+    sdp_add_timing();
+    //sdp_addAttributes( _pool );
+    sdp_add_media_description( );
+
+    //toString ();
+
+    // Validate the sdp session
+    status = pjmedia_sdp_validate( this->_local_offer );
+    if (status != PJ_SUCCESS)
+        return status;
+
+    return PJ_SUCCESS;
+}
+
+int Sdp::create_initial_offer(  ){
+    pj_status_t status;
+    pjmedia_sdp_neg_state state;
+
+    _debug ("Create initial offer\n");
+    // Build the SDP session descriptor
+    create_local_offer( );
+
+    // Create the SDP negociator instance with local offer
+    status = pjmedia_sdp_neg_create_w_local_offer( _pool, get_local_sdp_session(), &_negociator);
+    state = pjmedia_sdp_neg_get_state( _negociator );
+
+    PJ_ASSERT_RETURN( status == PJ_SUCCESS, 1 );
+
+    return PJ_SUCCESS;
+}
+
+int Sdp::receiving_initial_offer( pjmedia_sdp_session* remote ){
+    // Create the SDP negociator instance by calling
+    // pjmedia_sdp_neg_create_w_remote_offer with the remote offer, and by providing the local offer ( optional )
+
+    pj_status_t status;
+    pjmedia_sdp_neg_state state;
+
+    _debug ("Receiving initial offer\n");
+
+    // Create the SDP negociator instance by calling
+    // pjmedia_sdp_neg_create_w_remote_offer with the remote offer, and by providing the local offer ( optional )
+
+    // Build the local offer to respond
+    create_local_offer(  );
+
+    // Retrieve some useful remote information
+    this->fetch_media_transport_info_from_remote_sdp (remote);
+
+    status = pjmedia_sdp_neg_create_w_remote_offer( _pool,
+            get_local_sdp_session(), remote, &_negociator );
+    state = pjmedia_sdp_neg_get_state( _negociator );
+    PJ_ASSERT_RETURN( status == PJ_SUCCESS, 1 );
+
+    return PJ_SUCCESS;
+}
+
+void Sdp::sdp_add_protocol( void ){
+    this->_local_offer->origin.version = 0;
+}
+
+void Sdp::sdp_add_origin( void ){
+    pj_time_val tv;
+    pj_gettimeofday(&tv);
+
+    this->_local_offer->origin.user = pj_str(pj_gethostname()->ptr);
+    // Use Network Time Protocol format timestamp to ensure uniqueness.
+    this->_local_offer->origin.id = tv.sec + 2208988800UL;
+    // The type of network ( IN for INternet )
+    this->_local_offer->origin.net_type = STR_IN;
+    // The type of address
+    this->_local_offer->origin.addr_type = STR_IP4;
+    // The address of the machine from which the session was created
+    this->_local_offer->origin.addr = pj_str( (char*)_ip_addr.c_str() );
+}
+
+void Sdp::sdp_add_session_name( void ){
+    this->_local_offer->name = STR_SDP_NAME;
+}
+
+
+void Sdp::sdp_add_connection_info( void ){
+    this->_local_offer->conn->net_type = _local_offer->origin.net_type;
+    this->_local_offer->conn->addr_type = _local_offer->origin.addr_type;
+    this->_local_offer->conn->addr = _local_offer->origin.addr;
+}
+
+
+void Sdp::sdp_add_timing( void ){
+    // RFC 3264: An offer/answer model session description protocol
+    // As the session is created and destroyed through an external signaling mean (SIP), the line
+    // should have a value of "0 0".
+
+    this->_local_offer->time.start = this->_local_offer->time.stop = 0;
+}
+
+void Sdp::sdp_add_attributes( ){
+    pjmedia_sdp_attr *a;
+    this->_local_offer->attr_count = 1;
+    a =  PJ_POOL_ZALLOC_T(_pool, pjmedia_sdp_attr);
+    a->name=STR_SENDRECV;
+    _local_offer->attr[0] = a;
+}
+
+
+void Sdp::sdp_add_media_description( ){
+    pjmedia_sdp_media* med;
+    int nb_media, i;
+
+    med = PJ_POOL_ZALLOC_T(_pool, pjmedia_sdp_media);
+    nb_media = get_local_media_cap().size();
+    this->_local_offer->media_count = nb_media;
+
+    for( i=0; i<nb_media; i++ ){
+        set_media_descriptor_line( get_local_media_cap()[i], &med );
+        this->_local_offer->media[i] = med;
+    }
+}
+
+
+std::string Sdp::media_to_string( void ){
+    int size, i;
+    std::ostringstream res;
+
+    size = _local_media_cap.size();
+    for( i = 0; i < size ; i++ ){
+        res << _local_media_cap[i]->to_string();
+    }
+
+    res << std::endl;
+    return res.str();
+}
+
+void Sdp::clean_session_media(){
+    _session_media.clear();
+}
+
+void Sdp::set_negociated_offer( const pjmedia_sdp_session *sdp ){
+
+    int nb_media, nb_codecs;
+    int i,j, port;
+    pjmedia_sdp_media *current;
+    sdpMedia *media;
+    std::string type, dir;
+    CodecsMap codecs_list;
+    CodecsMap::iterator iter;
+    AudioCodec *codec_to_add;
+
+    _negociated_offer = (pjmedia_sdp_session*)sdp;
+
+    //this->fetch_remote_ip_from_sdp ((pjmedia_sdp_session*)sdp);
+
+    codecs_list = Manager::instance().getCodecDescriptorMap().getCodecsMap();
+
+    // retrieve the media information
+    nb_media = _negociated_offer->media_count;
+    for( i=0; i<nb_media ; i++ ){
+        // Retrieve the media 
+        current = _negociated_offer->media[i];
+        type = current->desc.media.ptr;
+        port = current->desc.port;
+        media = new sdpMedia( type, port );
+        // Retrieve the payload
+        nb_codecs = current->desc.fmt_count;  // Must be one
+        for( j=0 ; j<nb_codecs ; j++ ){
+            iter = codecs_list.find((AudioCodecType)atoi(current->desc.fmt[j].ptr));  
+            if (iter==codecs_list.end())
+                return;
+            media->add_codec(iter->second);
+        }
+        _session_media.push_back(media);
+    }
+}
+
+AudioCodec* Sdp::get_session_media( void ){
+
+    int nb_media;
+    int nb_codec;
+
+    nb_media = _session_media.size();
+    nb_codec = _session_media[0]->get_media_codec_list().size();
+
+    return _session_media[0]->get_media_codec_list()[0];
+}
+
+
+void Sdp::toString (void) {
+
+    std::ostringstream sdp;
+    int count, i;
+
+    sdp <<  "origin= " <<  _local_offer->origin.user.ptr << "\n";
+    sdp << "origin.id= " << _local_offer->origin.id << "\n";
+    sdp << "origin.version= " << _local_offer->origin.version<< "\n";
+    sdp << "origin.net_type= " << _local_offer->origin.net_type.ptr<< "\n";
+    sdp << "origin.addr_type= " << _local_offer->origin.addr_type.ptr<< "\n";
+
+    sdp << "name=" << _local_offer->name.ptr<< "\n";
+
+    sdp << "conn.net_type=" << _local_offer->conn->net_type.ptr<< "\n";
+    sdp << "conn.addr_type=" << _local_offer->conn->addr_type.ptr<< "\n";
+    sdp << "conn.addr=" << _local_offer->conn->addr.ptr<< "\n";
+
+    sdp << "start=" <<_local_offer->time.start<< "\n";
+    sdp << "stop=" <<_local_offer->time.stop<< "\n";
+
+    sdp << "attr_count=" << _local_offer->attr_count << "\n";
+    sdp << "media_count=" << _local_offer->media_count << "\n";
+    sdp << "m=" << _local_offer->media[0]->desc.media.ptr << " ";
+    sdp << _local_offer->media[0]->desc.port << " ";
+    sdp << _local_offer->media[0]->desc.transport.ptr << " ";
+    count = _local_offer->media[0]->desc.fmt_count;
+    for (i=0; i<count; i++) {
+        sdp << _local_offer->media[0]->desc.fmt[i].ptr << " ";
+    }
+    sdp << "\n";
+
+    _debug ("LOCAL SDP: \n%s\n", sdp.str().c_str());
+
+}
+
+void Sdp::set_local_media_capabilities () {
+
+    CodecOrder selected_codecs;
+    int i;
+    sdpMedia *audio;
+    CodecsMap codecs_list;
+    CodecsMap::iterator iter;
+
+    // Clean it first
+    _local_media_cap.clear();
+
+    _debug ("Fetch local media capabilities .......... %i\n" , get_local_extern_audio_port());
+
+    /* Only one audio media used right now */
+    audio = new sdpMedia(MIME_TYPE_AUDIO);
+    audio->set_port (get_local_extern_audio_port());
+
+    /* We retrieve the codecs selected by the user */
+    selected_codecs = Manager::instance().getCodecDescriptorMap().getActiveCodecs(); 
+    codecs_list = Manager::instance().getCodecDescriptorMap().getCodecsMap();
+    for (i=0; i<selected_codecs.size(); i++){
+        iter=codecs_list.find(selected_codecs[i]);  
+        if (iter!=codecs_list.end()){
+            audio->add_codec (iter->second);
+        }
+    } 
+    _local_media_cap.push_back (audio);
+    _debug ("%s\n", audio->to_string ().c_str());
+}
+
+void Sdp::attribute_port_to_all_media (int port) {
+
+    std::vector<sdpMedia*> medias;
+    int i, size;    
+
+    set_local_extern_audio_port (port);
+
+    medias = get_local_media_cap (); 
+    size = medias.size();
+
+    for(i=0; i<size; i++) {
+        medias[i]->set_port (port);
+    }   
+}
+
+std::string Sdp::convert_int_to_string (int value) {
+    std::ostringstream result;
+    result << value;
+    return result.str();
+}
+
+void Sdp::fetch_remote_ip_from_sdp (pjmedia_sdp_session *r_sdp) {
+
+    std::string remote_ip;
+
+    remote_ip = r_sdp->conn->addr.ptr;
+    _debug("**************************************************            Remote Audio IP: %s\n", remote_ip.c_str());
+    this->set_remote_ip(remote_ip);
+}
+
+void Sdp::fetch_remote_audio_port_from_sdp (pjmedia_sdp_media *r_media){
+
+    int remote_port;
+    
+    remote_port = r_media->desc.port;
+    _debug("            Remote Audio Port: %d\n", remote_port);
+    this->set_remote_audio_port(remote_port);
+}
+
+void Sdp::fetch_media_transport_info_from_remote_sdp (pjmedia_sdp_session *remote_sdp) {
+
+    pjmedia_sdp_media *r_media;
+
+    this->get_remote_sdp_media_from_offer (remote_sdp, &r_media);
+
+    if (r_media==NULL){
+        _debug("SDP Failure: no remote sdp media found in the remote offer\n");
+        return;
+    }
+    
+    this->fetch_remote_audio_port_from_sdp (r_media);
+    this->fetch_remote_ip_from_sdp (remote_sdp);
+}
+
+void Sdp::get_remote_sdp_media_from_offer (pjmedia_sdp_session* remote_sdp, pjmedia_sdp_media** r_media){
+    int count, i;
+
+    count = remote_sdp->media_count;
+    *r_media =  NULL;
+    for(i = 0; i < count; ++i) {
+        if(pj_stricmp2(&remote_sdp->media[i]->desc.media, "audio") == 0) {
+            *r_media = remote_sdp->media[i];
+            return;
+        }
+    }
+}
+
diff --git a/src/sdp.h b/src/sdp.h
new file mode 100644
index 0000000000000000000000000000000000000000..9bbd0d5344e43b37594a759067e9a9f4b82f7695
--- /dev/null
+++ b/src/sdp.h
@@ -0,0 +1,310 @@
+/*
+ *  Copyright (C) 2009 Savoir-Faire Linux inc.
+ *
+ *  Author: Emmanuel Milou <emmanuel.milou@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 3 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 _SDP_H
+#define _SDP_H
+
+#include <pjmedia/sdp.h>
+#include <pjmedia/sdp_neg.h>
+#include <pjsip/sip_transport.h>
+#include <pjlib.h>
+#include <pj/pool.h>
+#include <pj/assert.h>
+
+#include "audio/codecDescriptor.h"
+#include "sdpmedia.h"
+
+class Sdp {
+
+    public:
+        
+        /*
+         * Class Constructor.
+         *
+         * @param ip_addr
+         */
+        Sdp(pj_pool_t *pool);
+
+        /* Class destructor */
+        ~Sdp();
+
+        /*
+         * Read accessor. Get the list of the local media capabilities. 
+         *
+         * @return std::vector<sdpMedia*>   the vector containing the different media
+         */
+        std::vector<sdpMedia*> get_local_media_cap( void ) { return _local_media_cap; }
+
+         /*
+         *  Read accessor. Get the sdp session information
+         *
+         *  @return pjmedia_sdp_session   The structure that describes a SDP session
+         */
+        pjmedia_sdp_session* get_local_sdp_session( void ) { return _local_offer; }
+
+        /*
+         * Write accessor. Set the local IP address that will be used in the sdp session
+         */
+        void set_ip_address( std::string ip_addr ) { _ip_addr = ip_addr; }
+
+        /*
+         * Read accessor. Get the local IP address
+         */
+        std::string get_ip_address( void ) { return _ip_addr; }
+        
+        /*
+         * Build the local SDP offer
+         */
+        int create_local_offer( );
+
+        /*
+         * Build the sdp media section
+         * Add rtpmap field if necessary
+         *
+         * @param media     The media to add to SDP
+         * @param med   The structure to receive the media section
+         */
+        void set_media_descriptor_line( sdpMedia* media, pjmedia_sdp_media** p_med );
+
+        /*
+         * On building an invite outside a dialog, build the local offer and create the
+         * SDP negociator instance with it.
+         */
+        int create_initial_offer( );
+
+         /*
+         * On receiving an invite outside a dialog, build the local offer and create the
+         * SDP negociator instance with the remote offer.
+         *
+         * @param remote    The remote offer
+         */
+        int receiving_initial_offer( pjmedia_sdp_session* remote );
+        
+        /*
+         * Remove all media in the session media vector.
+         */
+        void clean_session_media();
+
+        /*
+         * Return a string description of the media added to the session,
+         * ie the local media capabilities
+         */
+        std::string media_to_string( void );
+
+        /*
+         * Return the codec of the first media after negociation
+         */
+        AudioCodec* get_session_media( void );
+
+        /*
+         * read accessor. Return the negociated offer
+         *
+         * @return pjmedia_sdp_session  The negociated offer
+         */
+        pjmedia_sdp_session* get_negociated_offer( void ){
+            return _negociated_offer;
+        }
+
+         /*
+         * Start the sdp negociation.
+         *
+         * @return pj_status_t  0 on success
+         *                      1 otherwise
+         */
+        pj_status_t start_negociation( void ){
+            return pjmedia_sdp_neg_negotiate(
+                       _pool, _negociator, 0);
+        }
+
+         /*
+         * Retrieve the negociated sdp offer from the sip payload.
+         *
+         * @param sdp   the negociated offer
+         */
+        void set_negociated_offer( const pjmedia_sdp_session *sdp );
+
+        /*
+         * Attribute the specified port to every medias provided
+         * This is valid only because we are using one media
+         * We should change this to support multiple medias
+         *
+         * @param port  The media port
+         */
+        void attribute_port_to_all_media (int port);
+
+        void  set_local_extern_audio_port(int port){ _local_extern_audio_port = port; }
+
+        int  get_local_extern_audio_port (void){ return _local_extern_audio_port; }
+
+        void toString (void);
+
+        /** 
+         * Set remote's IP addr. [not protected]
+         * @param ip  The remote IP address
+         */
+        void set_remote_ip(const std::string& ip)    { _remote_ip_addr = ip; }
+        
+        /** 
+         * Return IP of destination [mutex protected]
+         * @return const std:string	The remote IP address
+         */
+        const std::string& get_remote_ip() { return _remote_ip_addr; }
+
+        /** 
+         * Set remote's audio port. [not protected]
+         * @param port  The remote audio port
+         */
+        void set_remote_audio_port(unsigned int port) { _remote_audio_port = port; }
+
+        /** 
+         * Return audio port at destination [mutex protected] 
+         * @return unsigned int The remote audio port
+         */
+        unsigned int get_remote_audio_port() { return _remote_audio_port; }
+
+        void fetch_media_transport_info_from_remote_sdp (pjmedia_sdp_session *remote_sdp);
+    private:
+        /** Codec Map */
+        std::vector<sdpMedia*> _local_media_cap;
+
+        /* The media that will be used by the session (after the SDP negociation) */
+        std::vector<sdpMedia*> _session_media;
+
+        /** negociator */
+        pjmedia_sdp_neg *_negociator;
+
+        /** IP address */
+        std::string _ip_addr;
+
+        /** Remote's IP address */
+        std::string  _remote_ip_addr;
+        
+        /** Local SDP */
+        pjmedia_sdp_session *_local_offer;
+
+        /* The negociated SDP offer */
+        // Explanation: each endpoint's offer is negociated, and a new sdp offer results from this
+        // negociation, with the compatible media from each part 
+        pjmedia_sdp_session *_negociated_offer;
+
+        /** Local audio port */
+        int _local_extern_audio_port;
+
+        /** Remote's audio port */
+        unsigned int _remote_audio_port;
+
+        // The pool to allocate memory
+        pj_pool_t *_pool;
+
+        Sdp(const Sdp&); //No Copy Constructor
+        Sdp& operator=(const Sdp&); //No Assignment Operator
+
+        void set_local_media_capabilities ();
+
+        /*
+         *  Mandatory field: Origin ("o=")
+         *  Gives the originator of the session.
+         *  Serves as a globally unique identifier for this version of this session description.
+         */
+        void sdp_add_origin( void );
+
+        /*
+         *  Mandatory field: Protocol version ("v=")
+         *  Add the protocol version in the SDP session description
+         */
+        void sdp_add_protocol( void );
+
+        /*
+         *  Optional field: Connection data ("c=")
+         *  Contains connection data.
+         */
+        void sdp_add_connection_info( void );
+        
+        /*
+         *  Mandatory field: Session name ("s=")
+         *  Add a textual session name.
+         */
+        void sdp_add_session_name( void );
+
+        /*
+         *  Optional field: Session information ("s=")
+         *  Provides textual information about the session.
+         */
+        void sdp_add_session_info( void ){}
+
+        /*
+         *  Optional field: Uri ("u=")
+         *  Add a pointer to additional information about the session.
+         */
+        void sdp_add_uri( void ) {}
+
+        /*
+         *  Optional fields: Email address and phone number ("e=" and "p=")
+         *  Add contact information for the person responsible for the conference.
+         */
+        void sdp_add_email( void ) {}
+
+        /*
+         *  Optional field: Bandwidth ("b=")
+         *  Denotes the proposed bandwidth to be used by the session or the media .
+         */
+        void sdp_add_bandwidth( void ) {}
+
+        /*
+         *  Mandatory field: Timing ("t=")
+         *  Specify the start and the stop time for a session.
+         */
+        void sdp_add_timing( void );
+
+        /*
+         * Optional field: Time zones ("z=")
+         */
+        void sdp_add_time_zone( void ) {}
+
+        /*
+         * Optional field: Encryption keys ("k=")
+         */
+        void sdp_add_encryption_key( void ) {}
+
+        /*
+         * Optional field: Attributes ("a=")
+         */
+        void sdp_add_attributes( );
+
+        /*
+         * Mandatory field: Media descriptions ("m=")
+         */
+        void sdp_add_media_description();
+
+        std::string convert_int_to_string (int value);
+
+        void fetch_remote_ip_from_sdp (pjmedia_sdp_session *r_sdp);
+        
+        void fetch_remote_audio_port_from_sdp (pjmedia_sdp_media *r_media);
+
+        void get_remote_sdp_media_from_offer (pjmedia_sdp_session* r_sdp, pjmedia_sdp_media** r_media);
+
+//////////////////////////////////////////////////////////////////3
+////////////////////////////////////////////////////////////////////
+              
+};
+
+
+#endif
diff --git a/src/sdpmedia.cpp b/src/sdpmedia.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..fe2ef7615ca00e81a2de5cbc57c6366bdc6ef26a
--- /dev/null
+++ b/src/sdpmedia.cpp
@@ -0,0 +1,158 @@
+/*
+ *
+ *  Copyright (C) 2009 Savoir-Faire Linux inc.
+ *
+ *  Author: Emmanuel Milou <emmanuel.milou@savoirfairelinux.com>
+ *
+ * This file 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 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Sropulpof 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 Sropulpof.  If not, see <http:*www.gnu.org*licenses*>.
+ */
+
+#include "sdpmedia.h"
+#include <string.h>
+#include <sstream>
+#include <iostream>
+
+static const char* streamDirectionStr[] =
+{
+    "sendrecv",
+    "sendonly",
+    "recvonly",
+    "inactive"
+};
+
+static const char* mediaTypeStr[] =
+{
+    "audio",
+    "video",
+    "application",
+    "text",
+    "image",
+    "message"
+};
+
+sdpMedia::sdpMedia( int type )
+    : _media_type( (mediaType)type ), _codec_list(0), _port( 0 ), _stream_type( SEND_RECEIVE ){}
+
+
+sdpMedia::sdpMedia( std::string type, int port, std::string dir)
+    : _media_type( (mediaType)-1), _codec_list(0), _port(port),
+    _stream_type((streamDirection)-1){
+    unsigned int i;
+    const char* tmp;
+
+    for( i=0 ; i<MEDIA_COUNT ; i++){
+        tmp = mediaTypeStr[i];
+        if( strcmp(type.c_str(), tmp) == 0 ){
+            _media_type = (mediaType)i;
+            break;
+        }
+    }
+
+    if( strcmp( dir.c_str(), "default") == 0 )
+        dir = DEFAULT_STREAM_DIRECTION;
+    for( i=0; i<DIR_COUNT; i++ ){
+        tmp = streamDirectionStr[i];
+        if( strcmp(dir.c_str(), tmp) == 0){
+            _stream_type = (streamDirection)i;
+            break;
+        }
+    }
+}
+
+
+sdpMedia::~sdpMedia()
+{
+    int i;
+    for(i=0; i<(int)_codec_list.size(); i++)
+        delete _codec_list[i];
+}
+
+
+std::string sdpMedia::get_media_type_str( void ){
+    std::string value;
+
+    // Test the range to be sure we know the media
+    if( _media_type >= 0 && _media_type < MEDIA_COUNT )
+        value = mediaTypeStr[ _media_type ];
+    else
+        value = "unknown";
+    return value;
+}
+
+
+void sdpMedia::add_codec( AudioCodec* codec ){
+    
+    _codec_list.push_back (codec);
+}
+
+void sdpMedia::remove_codec( std::string codecName )
+{
+    // Look for the codec by its encoding name
+    int i;
+    int size;
+    std::string enc_name;
+    std::vector<AudioCodec*>::iterator iter;
+
+    size = _codec_list.size();
+    std::cout << "vector size: " << size << std::endl;
+
+    for( i=0 ; i<size ; i++ ){
+        std::cout << _codec_list[i]->getCodecName().c_str() << std::endl;
+        if( strcmp(_codec_list[i]->getCodecName().c_str(), codecName.c_str()) == 0 ){
+            std::cout << "erase " <<_codec_list[i]->getCodecName() << std::endl;
+            iter = _codec_list.begin()+i;
+            _codec_list.erase(iter);
+            break;
+        }
+    }
+}
+
+
+void sdpMedia::clear_codec_list( void ) {
+    // Erase every codecs from the list
+    _codec_list.clear();
+}
+
+
+std::string sdpMedia::get_stream_direction_str( void ) {
+    std::string value;
+
+    // Test the range of the value
+    if( _stream_type >= 0 && _stream_type < DIR_COUNT )
+        value = streamDirectionStr[ _stream_type ];
+    else
+        value = "unknown";
+    return value;
+}
+
+
+std::string sdpMedia::to_string( void ){
+    std::ostringstream display;
+    int size, i;
+
+    size = _codec_list.size();
+
+    display << get_media_type_str();
+    display << ":" << get_port();
+    display << ":";
+    for(i=0; i<size; i++){
+        display << _codec_list[i]->getCodecName() << "/";
+    }
+
+    display << ":" << get_stream_direction_str() << std::endl;
+
+    return display.str();
+}
+
+
diff --git a/src/sdpmedia.h b/src/sdpmedia.h
new file mode 100644
index 0000000000000000000000000000000000000000..7a089e517ed2888e9c01b5b9ecbb482be1d8a4ac
--- /dev/null
+++ b/src/sdpmedia.h
@@ -0,0 +1,165 @@
+/*
+ *  Copyright (C) 2009 Savoir-Faire Linux inc.
+ *
+ *  Author: Emmanuel Milou <emmanuel.milou@savoirfairelinux.com>
+ *
+ * This file 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 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Sropulpof 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 Sropulpof.  If not, see <http:*www.gnu.org*licenses*>.
+ */
+
+#ifndef _SDP_MEDIA
+#define _SDP_MEDIA
+
+#include <vector>
+
+#include "audio/codecDescriptor.h"
+
+#define DEFAULT_STREAM_DIRECTION    "sendrecv"
+
+#define MIME_TYPE_AUDIO     0
+#define MIME_TYPE_VIDEO     1
+#define MIME_TYPE_UNKNOWN   2
+
+/*
+ * @file sdpmedia.h
+ * @brief   A class to describe a media. It can be either a video codec or an audio codec.
+ *          it maintains internally a list of codecs to use in the SDP session and negociation
+ */
+
+/*
+ * This enum contains the different media stream direction.
+ * To be added in the SDP attributes
+ * The last one is only here to have to size information, otherwise the enum struct doesn't provide any means to know it
+ */
+enum streamDirection {
+    SEND_RECEIVE,
+    SEND_ONLY,
+    RECEIVE_ONLY,
+    INACTIVE,
+    DIR_COUNT
+};
+
+/*
+ * This enum contains the different media types.
+ * To be added in the SDP attributes
+ * The last one is only here to have to size information, otherwise the enum struct doesn't provide any means to know it
+ */
+enum mediaType {
+    AUDIOMEDIA,
+    VIDEO,
+    APPLICATION,
+    TEXT,
+    IMAGE,
+    MESSAGE,
+    MEDIA_COUNT
+};
+
+typedef enum streamDirection streamDirection;
+typedef enum mediaType mediaType;
+
+#include "audio/codecs/audiocodec.h"
+
+class sdpMedia
+{
+    public:
+        sdpMedia( int type );
+        sdpMedia( std::string type, int port, std::string dir = DEFAULT_STREAM_DIRECTION);
+        ~sdpMedia();
+
+        /*
+         * Read accessor. Return the list of codecs
+         */
+        std::vector<AudioCodec*> get_media_codec_list() { return _codec_list; }
+
+        /*
+         * Read accessor. Return the type of media
+         */
+        mediaType get_media_type() { return _media_type; }
+
+        /*
+         * Read accessor. Return the type of media
+         */
+        std::string get_media_type_str();
+
+        /*
+         * Set the media type
+         */
+        void set_media_type( int type ) { _media_type = (mediaType)type; }
+
+        /*
+         * Read accessor. Return the transport port
+         */
+        int get_port() { return _port; }
+
+        /*
+         * Write accessor. Set the transport port
+         */
+        void set_port( int port ) { _port = port; }
+
+        /*
+         * Add a codec in the current media codecs vector
+         *
+         * @param payload     The payload type
+         */
+        void add_codec( AudioCodec *codec );
+
+        /*
+         * Remove a codec from the current media codecs vector
+         *
+         * @param codec_name    The codec encoding name
+         */
+        void remove_codec( std::string codec_name );
+
+        /*
+         * Remove all the codecs from the list
+         */
+        void clear_codec_list( void );
+
+        /*
+         * Return a string description of the current media
+         */ 
+        std::string to_string( void );
+
+        /*
+         * Set the stream direction of the current media
+         * ie: sendrecv, sendonly,...
+         */
+        void set_stream_direction( int direction ) { _stream_type = (streamDirection)direction; }
+
+        /*
+         * Get the stream direction of the current media
+         * ie: sendrecv, sendonly,...
+         */
+        streamDirection get_stream_direction( void ) { return _stream_type; }
+
+        /*
+         * Get the stream direction string description of the current media
+         * ie: sendrecv, sendonly,...
+         */
+        std::string get_stream_direction_str( void );
+
+    private:
+        /* The type of media */
+        mediaType _media_type;
+
+        /* The media codec vector */
+        std::vector< AudioCodec* > _codec_list;
+
+        /* the transport port */
+        int _port;
+
+        /* The stream direction */
+        streamDirection _stream_type;
+};
+
+#endif // _SDP_MEDIA
diff --git a/src/sipcall.cpp b/src/sipcall.cpp
index 74a183c84f47f3c75025f99eac799e26be4480a7..43aabe062073070ac69a3b22bdaf8dc945cac5ca 100644
--- a/src/sipcall.cpp
+++ b/src/sipcall.cpp
@@ -23,301 +23,25 @@
 #include "sipcall.h"
 #include "global.h" // for _debug
 
-#define _SENDRECV 0
-#define _SENDONLY 1
-#define _RECVONLY 2
 
-SIPCall::SIPCall(const CallID& id, Call::CallType type) : Call(id, type)
+SIPCall::SIPCall(const CallID& id, Call::CallType type, pj_pool_t *pool) : Call(id, type)
             , _cid(0)
             , _did(0)
             , _tid(0)
-            , _localSDP(NULL)
-            , _negociator(NULL)
-            , _ipAddr("")
             , _xferSub(NULL)
             , _invSession(NULL)
+            , _local_sdp(0)
 {
+    _local_sdp = new Sdp (pool);
   _debug("SIPCALL::Constructor for this clss is called \n");
 }
 
 SIPCall::~SIPCall() 
 {
 
-  _debug("SIPCALL::Destructor for this clss is called \n");
+    delete _local_sdp; _local_sdp = 0;
+    _debug("SIPCALL::Destructor for this clss is called \n");
 }
 
 
-bool 
-SIPCall::SIPCallInvite(pjsip_rx_data *rdata, pj_pool_t *pool)
-{
-  pj_status_t status;
-  
-  // We retrieve the remote sdp offer in the rdata struct to begin the negociation
-  pjmedia_sdp_session* remote_sdp = getRemoteSDPFromRequest(rdata);
-  if (remote_sdp == 0) {
-    return false;
-  }
-
-  // Have to do some stuff here with the SDP
-  _localSDP = PJ_POOL_ZALLOC_T(pool, pjmedia_sdp_session);
-  _localSDP->conn =  PJ_POOL_ZALLOC_T(pool, pjmedia_sdp_conn);
-  
-  _localSDP->origin.version = 0;
-  sdpAddOrigin();
-  _localSDP->name = pj_str((char*)"sflphone");
-  sdpAddConnectionInfo();
-  _localSDP->time.start = _localSDP->time.stop = 0;
-  sdpAddMediaDescription(pool);
-  
-  status = pjmedia_sdp_validate( _localSDP );
-  if (status != PJ_SUCCESS) {
-    _debug("Can not generate valid local sdp\n");
-    return false;
-  }
-  
-  _debug("Before create negociator!\n");
-  status = pjmedia_sdp_neg_create_w_remote_offer(pool, _localSDP, remote_sdp, &_negociator);
-  if (status != PJ_SUCCESS) {
-      _debug("Can not create negociator\n");
-      return false;
-  }
-  _debug("After create negociator!\n");
-  
-  pjmedia_sdp_media* remote_med = getRemoteMedia(remote_sdp);
-  if (remote_med == 0) {
-    _debug("SIP Failure: unable to get remote media\n");
-    return false;
-  }
-
-  _debug("Before set audio!\n");
-  if (!setRemoteAudioFromSDP(remote_sdp, remote_med)) {
-    _debug("SIP Failure: unable to set IP address and port from SDP\n");
-    return false;
-  }
-
-  _debug("Before set codec!\n");
-  if (!setAudioCodecFromSDP(remote_med)) {
-    _debug("SIP Failure: unable to set audio codecs from the remote SDP\n");
-    return false;
-  }
-
-  return true;
-}
-
-bool
-SIPCall::SIPCallAnsweredWithoutHold(pjsip_rx_data *rdata)
-{
-  pjmedia_sdp_session* remote_sdp = getRemoteSDPFromRequest(rdata);
-  if (remote_sdp == NULL) {
-    _debug("SIP Failure: no remote sdp\n");
-    return false;
-  }
-
-  pjmedia_sdp_media* remote_med = getRemoteMedia(remote_sdp);
-  if (remote_med==NULL) {
-    return false;
-  }
-  
-  _debug("Before set audio!\n");
-  if (!setRemoteAudioFromSDP(remote_sdp, remote_med)) {
-    _debug("SIP Failure: unable to set IP address and port from SDP\n");
-    return false;
-  }
-
-  _debug("Before set codec!\n");
-  if (!setAudioCodecFromSDP(remote_med)) {
-    _debug("SIP Failure: unable to set audio codecs from the remote SDP\n");
-    return false;
-  }
-
-  return true;
-}
-
-
-pjmedia_sdp_session* 
-SIPCall::getRemoteSDPFromRequest(pjsip_rx_data *rdata)
-{
-    pjmedia_sdp_session *sdp;
-    pjsip_msg *msg;
-    pjsip_msg_body *body;
-
-    msg = rdata->msg_info.msg;
-    body = msg->body;
-
-    pjmedia_sdp_parse( rdata->tp_info.pool, (char*)body->data, body->len, &sdp );
-
-    return sdp;
-}
-
-bool 
-SIPCall::setRemoteAudioFromSDP(pjmedia_sdp_session* remote_sdp, pjmedia_sdp_media *remote_med)
-{
-  std::string remoteIP(remote_sdp->conn->addr.ptr, remote_sdp->conn->addr.slen);
-  _debug("            Remote Audio IP: %s\n", remoteIP.data());
-  setRemoteIP(remoteIP);
-  int remotePort = remote_med->desc.port; 
-  _debug("            Remote Audio Port: %d\n", remotePort);
-  setRemoteAudioPort(remotePort);
-  
-  return true;
-}
-
-bool 
-SIPCall::setAudioCodecFromSDP(pjmedia_sdp_media* remote_med)
-{
-  // Remote Payload
-  int payLoad = -1;
-  int codecCount = remote_med->desc.fmt_count;
-  for(int i = 0; i < codecCount; i++) {
-      payLoad = atoi(remote_med->desc.fmt[i].ptr);
-      if (_codecMap.isActive((AudioCodecType)payLoad))
-          break;
-          
-      payLoad = -1;
-  }
-  
-  if(payLoad != -1) {
-    _debug("            Payload: %d\n", payLoad);
-    setAudioCodec((AudioCodecType)payLoad);
-  } else
-    return false;
-  
-  return true;
-}
 
-void SIPCall::sdpAddOrigin( void )
-{
-    pj_time_val tv;
-    pj_gettimeofday(&tv);
-
-    _localSDP->origin.user = pj_str(pj_gethostname()->ptr);
-    // Use Network Time Protocol format timestamp to ensure uniqueness.
-    _localSDP->origin.id = tv.sec + 2208988800UL;
-    // The type of network ( IN for INternet )
-    _localSDP->origin.net_type = pj_str((char*)"IN"); //STR_IN;
-    // The type of address
-    _localSDP->origin.addr_type = pj_str((char*)"IP4"); //STR_IP4;
-    // The address of the machine from which the session was created
-    _localSDP->origin.addr = pj_str( (char*)_ipAddr.c_str() );    
-}
-
-void SIPCall::sdpAddConnectionInfo( void )
-{
-    _localSDP->conn->net_type = _localSDP->origin.net_type;
-    _localSDP->conn->addr_type = _localSDP->origin.addr_type;
-    _localSDP->conn->addr = _localSDP->origin.addr;
-}
-
-void SIPCall::sdpAddMediaDescription(pj_pool_t* pool)
-{
-    pjmedia_sdp_media* med;
-    pjmedia_sdp_attr *attr;
-    pjmedia_sdp_rtpmap rtpMap;
-    //int nbMedia, i;
-
-    med = PJ_POOL_ZALLOC_T(pool, pjmedia_sdp_media);
-    //nbMedia = getSDPMediaList().size();
-    _localSDP->media_count = 1;
-    
-    med->desc.media = pj_str((char*)"audio");
-    med->desc.port_count = 1;
-    med->desc.port = getLocalExternAudioPort();
-    med->desc.transport = pj_str((char*)"RTP/AVP");
-    
-    CodecOrder::iterator itr;
-
-    itr = _codecMap.getActiveCodecs().begin();
-    int count = _codecMap.getActiveCodecs().size();
-    med->desc.fmt_count = count;
-    
-    int i = 0;
-
-    while(itr != _codecMap.getActiveCodecs().end()) {
-        std::ostringstream format;
-        format << *itr;
-        pj_strdup2(pool, &med->desc.fmt[i], format.str().data());
-        
-        rtpMap.pt = med->desc.fmt[i];
-        rtpMap.enc_name = pj_str((char *)_codecMap.getCodecName(*itr).data());
-        rtpMap.clock_rate = _codecMap.getSampleRate(*itr);
-        if(_codecMap.getChannel(*itr) > 1) {
-            std::ostringstream channel;
-            channel << _codecMap.getChannel(*itr);
-            rtpMap.param = pj_str((char *)channel.str().data());
-        } else
-            rtpMap.param.slen = 0;
-        
-        pjmedia_sdp_rtpmap_to_attr( pool, &rtpMap, &attr );
-        med->attr[i] = attr;
-        i++;
-        itr++;
-    }
-    
-    //FIXME! Add the direction stream
-    attr = (pjmedia_sdp_attr*)pj_pool_zalloc( pool, sizeof(pjmedia_sdp_attr) );
-    pj_strdup2( pool, &attr->name, "sendrecv");
-    med->attr[ i++] = attr;
-    med->attr_count = i;
-
-    _localSDP->media[0] = med;
-    /*for( i=0; i<nbMedia; i++ ){
-        getMediaDescriptorLine( getSDPMediaList()[i], pool, &med );
-        this->_local_offer->media[i] = med;
-    } */
-    
-}
-
-pjmedia_sdp_media* SIPCall::getRemoteMedia(pjmedia_sdp_session *remote_sdp)
-{
-    int count, i;
-    
-    count = remote_sdp->media_count;
-    for(i = 0; i < count; ++i) {
-        if(pj_stricmp2(&remote_sdp->media[i]->desc.media, "audio") == 0)
-            return remote_sdp->media[i];
-    }
-    
-    return NULL;
-}
-
-bool SIPCall::startNegociation(pj_pool_t *pool)
-{
-    pj_status_t status;
-    _debug("Before negotiate!\n");
-    status = pjmedia_sdp_neg_negotiate(pool, _negociator, 0);
-    
-    return (status == PJ_SUCCESS);
-}
-
-bool SIPCall::createInitialOffer(pj_pool_t *pool)
-{
-  pj_status_t status;
-
-  // Have to do some stuff here with the SDP
-  _localSDP = PJ_POOL_ZALLOC_T(pool, pjmedia_sdp_session);
-  _localSDP->conn =  PJ_POOL_ZALLOC_T(pool, pjmedia_sdp_conn);
-  
-  _localSDP->origin.version = 0;
-  sdpAddOrigin();
-  _localSDP->name = pj_str((char*)"sflphone");
-  sdpAddConnectionInfo();
-  _localSDP->time.start = _localSDP->time.stop = 0;
-  sdpAddMediaDescription(pool);
-  
-  _debug("Before validate SDP!\n");
-  status = pjmedia_sdp_validate( _localSDP );
-  if (status != PJ_SUCCESS) {
-    _debug("Can not generate valid local sdp %d\n", status);
-    return false;
-  }
-  
-  _debug("Before create negociator!\n");
-  // Create the SDP negociator instance with local offer
-  status = pjmedia_sdp_neg_create_w_local_offer( pool, _localSDP, &_negociator);
-  //state = pjmedia_sdp_neg_get_state( _negociator );
-
-  PJ_ASSERT_RETURN( status == PJ_SUCCESS, 1 );
-
-  return true;
-    
-}
diff --git a/src/sipcall.h b/src/sipcall.h
index 2ef3d2793451e85bd1fd48151428959cfd7db854..fd0c01bea6569e1c2cf3e51d703259acfd090cf4 100644
--- a/src/sipcall.h
+++ b/src/sipcall.h
@@ -23,7 +23,7 @@
 
 #include "call.h"
 #include "sipvoiplink.h"
-#include "audio/codecDescriptor.h"
+#include "sdp.h"
 
 class AudioCodec;
 
@@ -41,7 +41,7 @@ class SIPCall : public Call
      * @param type  The type of the call. Could be Incoming
      *						 Outgoing
      */
-    SIPCall(const CallID& id, Call::CallType type);
+    SIPCall(const CallID& id, Call::CallType type, pj_pool_t *pool );
 
     /**
      * Destructor
@@ -78,127 +78,37 @@ class SIPCall : public Call
      */
     int  getTid() { return _tid; }
     
+    
     /** 
      * Transaction identifier
      * @param tid SIP transaction id
      */
     void setTid(int tid) { _tid = tid; } 
 
-    /**
-     * Setup incoming call, and verify for errors, before ringing the user.
-     * @param pjsip_rx_data *rdata
-     * @param pj_pool_t *pool
-     * @return bool True on success
-     *		    false otherwise
-     */
-    bool SIPCallInvite(pjsip_rx_data *rdata, pj_pool_t *pool);
-
-    bool SIPCallAnsweredWithoutHold(pjsip_rx_data *rdata);
- 
-    /**
-     * Save IP Address
-     * @param ip std::string 
-     * @return void
-     */
-    void setIp(std::string ip) {_ipAddr = ip;}
-
-    /**
-     * Get the local SDP 
-     * @param void
-     * @return _localSDP pjmedia_sdp_session
-     */
-    pjmedia_sdp_session* getLocalSDPSession( void ) { return _localSDP; }
-    
-    /**
-     * Begin negociation of media information between caller and callee
-     * @param pj_pool_t *pool
-     * @return bool True if ok
-     */
-    bool startNegociation(pj_pool_t *pool);
-
-    /**
-     * Create the localSDP, media negociation and codec information
-     * @param pj_pool_t *pool
-     * @return void
-     */
-    bool createInitialOffer(pj_pool_t *pool);
-    
     void setXferSub(pjsip_evsub* sub) {_xferSub = sub;}
     pjsip_evsub *getXferSub() {return _xferSub;}
     
     void setInvSession(pjsip_inv_session* inv) {_invSession = inv;}
     pjsip_inv_session *getInvSession() {return _invSession;}
     
-  private:
-
-    // Copy Constructor
-    SIPCall(const SIPCall& rh);
+    Sdp* getLocalSDP (void) { return _local_sdp; }
 
-    // Assignment Operator
-    SIPCall& operator=( const SIPCall& rh);
+    void setLocalSDP (Sdp *local_sdp) { _local_sdp = local_sdp; }
 
-    /**
-     * Get a valid remote SDP or return a 400 bad request response if invalid
-     * @param
-     * @return
-     */
-    pjmedia_sdp_session* getRemoteSDPFromRequest(pjsip_rx_data *rdata);
-
-    /**
-     * Get a valid remote media
-     * @param remote_sdp pjmedia_sdp_session*
-     * @return pjmedia_sdp_media*. A valid sdp_media_t or 0
-     */
-    pjmedia_sdp_media* getRemoteMedia(pjmedia_sdp_session *remote_sdp);
-
-    /**
-     * Set Audio Port and Audio IP from Remote SDP Info
-     * @param remote_med Remote Media info
-     * @param remote_sdp Remote SDP pointer
-     * @return bool True if everything is set correctly
-     */
-    bool setRemoteAudioFromSDP(pjmedia_sdp_session* remote_sdp, pjmedia_sdp_media* remote_med);
+  private:
 
-    /**
-     * Set Audio Codec with the remote choice
-     * @param remote_med Remote Media info
-     * @return bool True if everything is set correctly
-     */
-    bool setAudioCodecFromSDP(pjmedia_sdp_media* remote_med);
+    Sdp *_local_sdp;
 
-    /** SIP call id */
     int _cid;
-
-    /** SIP domain id */
     int _did;
-    
-    /** SIP transaction id */
     int _tid;
 
-    /** Local SDP */
-    pjmedia_sdp_session *_localSDP;
+    // Copy Constructor
+    SIPCall(const SIPCall& rh);
 
-    /** negociator */
-    pjmedia_sdp_neg *_negociator;
-    
-    /**
-     * Set origin information for local SDP
-     */
-    void sdpAddOrigin( void );
+    // Assignment Operator
+    SIPCall& operator=( const SIPCall& rh);
     
-    /**
-     * Set connection information for local SDP
-     */
-    void sdpAddConnectionInfo( void );
-    /**
-     * Set media information including codec for localSDP
-     * @param  pj_pool_t* pool
-     * @return void
-     */
-    void sdpAddMediaDescription(pj_pool_t* pool);
-
-    /** IP address */
-    std::string _ipAddr;
     
     pjsip_evsub *_xferSub;
     pjsip_inv_session *_invSession;
diff --git a/src/sipvoiplink.cpp b/src/sipvoiplink.cpp
index 61bf0cb49ffc1d4910b60e5899e0c0d4a1b56666..acb8d8b0e5e38efb266f586b9cff5a078b7f8ea2 100644
--- a/src/sipvoiplink.cpp
+++ b/src/sipvoiplink.cpp
@@ -25,8 +25,28 @@
 #include "sipaccount.h"
 #include "audio/audiortp.h"
 
+#define CAN_REINVITE    1
+
 /**************** EXTERN VARIABLES AND FUNCTIONS (callbacks) **************************/
 
+/*
+ * Retrieve the SDP of the peer contained in the offer
+ *
+ * @param rdata The request data
+ * @param r_sdp The pjmedia_sdp_media to stock the remote SDP
+ */
+void get_remote_sdp_from_offer( pjsip_rx_data *rdata, pjmedia_sdp_session** r_sdp );
+
+int getModId();
+
+/**
+ *  * Set audio (SDP) configuration for a call
+ *   * localport, localip, localexternalport
+ *    * @param call a SIPCall valid pointer
+ *     * @return bool True
+ *      */
+bool setCallAudioLocal(SIPCall* call, std::string localIP, bool stun, std::string server);
+
 /*
  *  The global pool factory
  */
@@ -53,20 +73,11 @@ pjsip_module _mod_ua;
 pj_thread_t *thread;
 pj_thread_desc desc;
 
-
 /**
  * Get the number of voicemail waiting in a SIP message
  */
 void set_voicemail_info( AccountID account, pjsip_msg_body *body );
 
-/**
- * Set audio (SDP) configuration for a call
- * localport, localip, localexternalport
- * @param call a SIPCall valid pointer
- * @return bool True
- */
-bool setCallAudioLocal(SIPCall* call, std::string localIP, bool stun, std::string server);
-
 // Documentated from the PJSIP Developer's Guide, available on the pjsip website/
 
 /*
@@ -107,6 +118,8 @@ void call_on_forked(pjsip_inv_session *inv, pjsip_event *e);
  */
 void call_on_tsx_changed(pjsip_inv_session *inv, pjsip_transaction *tsx, pjsip_event *e);
 
+void on_rx_offer( pjsip_inv_session *inv, const pjmedia_sdp_session *offer );
+
 /*
  * Registration callback
  */
@@ -205,6 +218,7 @@ SIPVoIPLink::terminate()
         delete _evThread; _evThread = NULL;
     }
 
+
     /* Clean shutdown of pjsip library */
     if( initDone() )
     {
@@ -244,7 +258,21 @@ SIPVoIPLink::terminateOneCall(const CallID& id)
     }
 }
 
+void get_remote_sdp_from_offer( pjsip_rx_data *rdata, pjmedia_sdp_session** r_sdp ){
+    pjmedia_sdp_session *sdp;
+    pjsip_msg *msg;
+    pjsip_msg_body *body;
 
+    // Get the message
+    msg = rdata->msg_info.msg;
+    // Get the body message
+    body = msg->body;
+
+    // Parse the remote request to get the sdp session
+    pjmedia_sdp_parse( rdata->tp_info.pool, (char*)body->data, body->len, &sdp );
+
+    *r_sdp = sdp;
+}
 
     void
 SIPVoIPLink::getEvent()
@@ -261,7 +289,7 @@ SIPVoIPLink::getEvent()
 
 int SIPVoIPLink::sendRegister( AccountID id )
 {
-  _debug("sendRegister called!!!!!!!!!!!!!!!!!!!!!!! \n");
+    _debug("sendRegister called!!!!!!!!!!!!!!!!!!!!!!! \n");
     pj_status_t status;
     int expire_value;
     char contactTmp[256];
@@ -407,7 +435,7 @@ SIPVoIPLink::newOutgoingCall(const CallID& id, const std::string& toUrl)
 {
     Account* account;
 
-    SIPCall* call = new SIPCall(id, Call::Outgoing);
+    SIPCall* call = new SIPCall(id, Call::Outgoing, _pool);
 
     if (call) {
         account = dynamic_cast<SIPAccount *>(Manager::instance().getAccount(Manager::instance().getAccountFromCall(id)));
@@ -419,14 +447,17 @@ SIPVoIPLink::newOutgoingCall(const CallID& id, const std::string& toUrl)
             delete call; call=0;
             return call;
         }
-        //call->setPeerNumber(toUrl);
+
         call->setPeerNumber(getSipTo(toUrl, account->getHostname()));
-      
+        setCallAudioLocal(call, getLocalIPAddress(), useStun(), getStunServer());
+
         call->initRecFileName();
 
         _debug("Try to make a call to: %s with call ID: %s\n", toUrl.data(), id.data());
-        // we have to add the codec before using it in SIPOutgoingInvite...
-        call->setCodecMap(Manager::instance().getCodecDescriptorMap());
+        // Building the local SDP offer
+        call->getLocalSDP()->set_ip_address(getLocalIP());
+        call->getLocalSDP()->create_initial_offer();
+
         if ( SIPOutgoingInvite(call) ) {
             call->setConnectionState(Call::Progressing);
             call->setState(Call::Active);
@@ -438,7 +469,7 @@ SIPVoIPLink::newOutgoingCall(const CallID& id, const std::string& toUrl)
     return call;
 }
 
-    bool
+    bool 
 SIPVoIPLink::answer(const CallID& id)
 {
 
@@ -446,6 +477,8 @@ SIPVoIPLink::answer(const CallID& id)
     SIPCall *call;
     pj_status_t status;
     pjsip_tx_data *tdata;
+    Sdp *local_sdp;
+    pjsip_inv_session *inv_session;
 
     _debug("SIPVoIPLink::answer: start answering \n");
 
@@ -456,15 +489,19 @@ SIPVoIPLink::answer(const CallID& id)
         return false;
     }
 
-    // User answered the incoming call, tell peer this news
-    if (call->startNegociation(_pool)) {
-        // Create and send a 200(OK) response
+    local_sdp = call->getLocalSDP();
+    inv_session = call->getInvSession();
+    status = local_sdp->start_negociation ();
+
+    if (status == PJ_SUCCESS) {
         _debug("SIPVoIPLink::answer:UserAgent: Negociation success! : call %s \n", call->getCallId().c_str());
-        status = pjsip_inv_answer(call->getInvSession(), PJSIP_SC_OK, NULL, NULL, &tdata);
+        // Create and send a 200(OK) response
+        status = pjsip_inv_answer(inv_session, PJSIP_SC_OK, NULL, NULL, &tdata);
         PJ_ASSERT_RETURN(status == PJ_SUCCESS, 1);
-        status = pjsip_inv_send_msg(call->getInvSession(), tdata);
+        status = pjsip_inv_send_msg(inv_session, tdata);
         PJ_ASSERT_RETURN(status == PJ_SUCCESS, 1);
 
+        // Start the RTP sessions
         _debug("SIPVoIPLink::answer: Starting AudioRTP when answering : call %s \n", call->getCallId().c_str());
         if (_audiortp->createNewSession(call) >= 0) {
             call->setAudioStart(true);
@@ -475,10 +512,21 @@ SIPVoIPLink::answer(const CallID& id)
             _debug("SIPVoIPLink::answer: Unable to start sound when answering %s/%d\n", __FILE__, __LINE__);
         }
     }
-    _debug("SIPVoIPLink::answer: fail terminate call %s \n",call->getCallId().c_str());
-    terminateOneCall(call->getCallId());
-    removeCall(call->getCallId());
-    return false;
+    else {
+        // Create and send a 488/Not acceptable here
+        // because the SDP negociation failed
+        status = pjsip_inv_answer( inv_session, PJSIP_SC_NOT_ACCEPTABLE_HERE, NULL, NULL,
+                &tdata );
+        PJ_ASSERT_RETURN( status == PJ_SUCCESS, 1 );
+        status = pjsip_inv_send_msg( inv_session, tdata );
+        PJ_ASSERT_RETURN( status == PJ_SUCCESS, 1 );
+
+        // Terminate the call
+        _debug("SIPVoIPLink::answer: fail terminate call %s \n",call->getCallId().c_str());
+        terminateOneCall(call->getCallId());
+        removeCall(call->getCallId());
+        return false;
+    }
 }
 
     bool
@@ -575,9 +623,6 @@ SIPVoIPLink::onhold(const CallID& id)
 {
 
     pj_status_t status;
-    pjsip_tx_data *tdata;
-    pjmedia_sdp_attr *attr;
-    pjmedia_sdp_session* local_sdp;
     SIPCall* call;
 
     call = getSIPCall(id);
@@ -589,43 +634,54 @@ SIPVoIPLink::onhold(const CallID& id)
     call->setAudioStart(false);
     call->setState(Call::Hold);
     _debug("* SIP Info: Stopping AudioRTP for onhold action\n");
-    //_mutexSIP.enterMutex();
     _audiortp->closeRtpSession();
-    //_mutexSIP.leaveMutex();
 
-    local_sdp = call->getLocalSDPSession();
+    /* Create re-INVITE with new offer */
+    status = inv_session_reinvite (call, "sendonly");
+
+    return (status == PJ_SUCCESS);
+}
+
+int SIPVoIPLink::inv_session_reinvite (SIPCall *call, std::string direction) {
+
+    pj_status_t status;
+    pjsip_tx_data *tdata;
+    pjmedia_sdp_session *local_sdp;
+    pjmedia_sdp_attr *attr;
+
+    local_sdp = call->getLocalSDP()->get_local_sdp_session();
 
     if( local_sdp == NULL ){
         _debug("! SIP Failure: unable to find local_sdp\n");
         return false;
     }
 
-    /* Create re-INVITE with new offer */
-    // Remove all the attributes with the specified name
+    // reinvite only if connected
+    // Build the local SDP offer
+    status = call->getLocalSDP()->create_initial_offer( );
     pjmedia_sdp_media_remove_all_attr(local_sdp->media[0], "sendrecv");
-    attr = pjmedia_sdp_attr_create(_pool, "sendonly", NULL);
+    attr = pjmedia_sdp_attr_create(_pool, direction.c_str(), NULL);
     pjmedia_sdp_media_add_attr(local_sdp->media[0], attr);
+    PJ_ASSERT_RETURN( status == PJ_SUCCESS, 1 );
 
-    status = pjsip_inv_reinvite( call->getInvSession(), NULL, local_sdp, &tdata);
-    if( status != PJ_SUCCESS )
-    {
-        _debug("On hold: creation of the Re-invite request failed\n");
-        return false;
-    }
-    /* Send the request */
-    status = pjsip_inv_send_msg( call->getInvSession(), tdata);
+    // Build the reinvite request
+    status = pjsip_inv_reinvite( call->getInvSession(), NULL,
+            local_sdp, &tdata );
+    PJ_ASSERT_RETURN( status == PJ_SUCCESS, 1 );
 
-    return (status == PJ_SUCCESS);
+    // Send it
+    status = pjsip_inv_send_msg( call->getInvSession(), tdata );
+    PJ_ASSERT_RETURN( status == PJ_SUCCESS, 1 );
+
+    return PJ_SUCCESS;
 }
 
+
     bool 
 SIPVoIPLink::offhold(const CallID& id)
 {
     SIPCall *call;
     pj_status_t status;
-    pjsip_tx_data *tdata;
-    pjmedia_sdp_attr *attr;
-    pjmedia_sdp_session* local_sdp;
 
     call = getSIPCall(id);
 
@@ -634,28 +690,9 @@ SIPVoIPLink::offhold(const CallID& id)
         return false; 
     }
 
-    local_sdp = call->getLocalSDPSession();
-    if( local_sdp == NULL ){
-        _debug("! SIP Failure: unable to find local_sdp\n");
-        return false;
-    }
-
     /* Create re-INVITE with new offer */
-    // Remove all the attributes with the specified name
-    pjmedia_sdp_media_remove_all_attr(local_sdp->media[0], "sendonly");
-    attr = pjmedia_sdp_attr_create(_pool, "sendrecv", NULL);
-    pjmedia_sdp_media_add_attr(local_sdp->media[0], attr);
-
-    status = pjsip_inv_reinvite( call->getInvSession(), NULL, local_sdp , &tdata);
-    if( status != PJ_SUCCESS )
-    {
-        _debug("Off hold: creation of the Re-invite request failed\n");
-        return false;
-    }
-
-    /* Send the request */
-    status = pjsip_inv_send_msg( call->getInvSession(), tdata);
-    if( status != PJ_SUCCESS )
+    status = inv_session_reinvite (call, "sendrecv");
+    if (status != PJ_SUCCESS)
         return false;
 
     // Enable audio
@@ -802,15 +839,15 @@ SIPVoIPLink::isRecording(const CallID& id)
 }
 
 
-std::string 
+    std::string 
 SIPVoIPLink::getCurrentCodecName()
 {
 
-  SIPCall *call = getSIPCall(Manager::instance().getCurrentCallId());  
+    SIPCall *call = getSIPCall(Manager::instance().getCurrentCallId());  
 
-  AudioCodec *ac = call->getCodecMap().getCodec(call->getAudioCodec());
+    AudioCodec *ac = call->getLocalSDP()->get_session_media();
 
-  return ac->getCodecName();
+    return ac->getCodecName();
 }
 
     bool 
@@ -893,6 +930,7 @@ SIPVoIPLink::SIPStartCall(SIPCall* call, const std::string& subject UNUSED)
     pj_str_t from, to, contact;
     AccountID id;
     SIPAccount *account;
+    pjsip_inv_session *inv;
 
     if (!call) 
         return false;
@@ -920,15 +958,8 @@ SIPVoIPLink::SIPStartCall(SIPCall* call, const std::string& subject UNUSED)
             &dialog);
     PJ_ASSERT_RETURN(status == PJ_SUCCESS, false);
 
-    setCallAudioLocal(call, getLocalIPAddress(), useStun(), getStunServer());
-    call->setIp(getLocalIP());
-
-    // Building the local SDP offer
-    call->createInitialOffer(_pool);
-
     // Create the invite session for this call
-    pjsip_inv_session *inv;
-    status = pjsip_inv_create_uac(dialog, call->getLocalSDPSession(), 0, &inv);
+    status = pjsip_inv_create_uac(dialog, call->getLocalSDP()->get_local_sdp_session(), 0, &inv);
     PJ_ASSERT_RETURN(status == PJ_SUCCESS, false);
 
     // Set auth information
@@ -979,28 +1010,6 @@ std::string SIPVoIPLink::getSipTo(const std::string& to_url, std::string hostnam
             return true;
         }
 
-    bool setCallAudioLocal(SIPCall* call, std::string localIP, bool stun, std::string server) 
-    {
-        // Setting Audio
-        unsigned int callLocalAudioPort = RANDOM_LOCAL_PORT;
-        unsigned int callLocalExternAudioPort = callLocalAudioPort;
-        if (stun) {
-            // If use Stun server
-            if (Manager::instance().behindNat(server, callLocalAudioPort)) {
-                callLocalExternAudioPort = Manager::instance().getFirewallPort();
-            }
-        }
-        _debug("            Setting local audio port to: %d\n", callLocalAudioPort);
-        _debug("            Setting local audio port (external) to: %d\n", callLocalExternAudioPort);
-
-        // Set local audio port for SIPCall(id)
-        call->setLocalIp(localIP);
-        call->setLocalAudioPort(callLocalAudioPort);
-        call->setLocalExternAudioPort(callLocalExternAudioPort);
-
-        return true;
-    }
-
     void
         SIPVoIPLink::SIPCallServerFailure(SIPCall *call) 
         {
@@ -1064,17 +1073,25 @@ std::string SIPVoIPLink::getSipTo(const std::string& to_url, std::string hostnam
     void
         SIPVoIPLink::SIPCallAnswered(SIPCall *call, pjsip_rx_data *rdata)
         {
-            //SIPCall* call = dynamic_cast<SIPCall *>(theCall);//findSIPCallWithCid(event->cid);
+
+            pjmedia_sdp_session *r_sdp;    
+
             if (!call) {
                 _debug("! SIP Failure: unknown call\n");
                 return;
             }
-            //call->setDid(event->did);
 
             if (call->getConnectionState() != Call::Connected) {
-                //call->SIPCallAnswered(event);
-                call->SIPCallAnsweredWithoutHold(rdata);
+                _debug ("Get remote SDP from offer\n");
+                get_remote_sdp_from_offer (rdata, &r_sdp);
+                if (r_sdp==NULL) {
+                    _debug("SIP Failure: no remote sdp session\n");
+                    return;
+                }
+                _debug ("Get remote media information from offer\n");
+                call->getLocalSDP()->fetch_media_transport_info_from_remote_sdp (r_sdp);
 
+                _debug ("Update call state\n");
                 call->setConnectionState(Call::Connected);
                 call->setState(Call::Active);
 
@@ -1089,13 +1106,12 @@ std::string SIPVoIPLink::getSipTo(const std::string& to_url, std::string hostnam
                 }
             } else {
                 _debug("* SIP Info: Answering call (on/off hold to send ACK)\n");
-                //call->SIPCallAnswered(event);
             }
         }
 
 
-SIPCall*
-SIPVoIPLink::getSIPCall(const CallID& id) 
+    SIPCall*
+        SIPVoIPLink::getSIPCall(const CallID& id) 
         {
             Call* call = getCall(id);
             if (call) {
@@ -1105,9 +1121,9 @@ SIPVoIPLink::getSIPCall(const CallID& id)
         }
 
 
-void SIPVoIPLink::setStunServer( const std::string &server )
-{
-         if(server != "") {
+    void SIPVoIPLink::setStunServer( const std::string &server )
+    {
+        if(server != "") {
 
             useStun(true);
             _stunServer = server;
@@ -1260,6 +1276,7 @@ void SIPVoIPLink::setStunServer( const std::string &server )
         inv_cb.on_new_session = &call_on_forked;
         inv_cb.on_media_update = &call_on_media_update;
         inv_cb.on_tsx_state_changed = &call_on_tsx_changed;
+        inv_cb.on_rx_offer = &on_rx_offer;
 
         // Initialize session invite module 
         status = pjsip_inv_usage_init(_endpt, &inv_cb);
@@ -1343,8 +1360,8 @@ void SIPVoIPLink::setStunServer( const std::string &server )
 
         // Init bound address to ANY
         pj_memset(&bound_addr, 0, sizeof (bound_addr));
-        
-       
+
+
         bound_addr.sin_addr.s_addr = pj_htonl(PJ_INADDR_ANY);
         bound_addr.sin_port = pj_htons((pj_uint16_t) _localPort);
         bound_addr.sin_family = PJ_AF_INET;
@@ -1354,10 +1371,10 @@ void SIPVoIPLink::setStunServer( const std::string &server )
 
         _debug("bound_addr.sin_port %i \n", bound_addr.sin_port);
 
-        
+
         _debug("UserAgent: Use IP: %s\n", _localExternAddress.data());
-        
-        
+
+
         // Create UDP-Server (default port: 5060)
         strcpy(tmpIP, _localExternAddress.data());
         pj_strdup2(_pool, &a_name.host, tmpIP);
@@ -1451,7 +1468,7 @@ void SIPVoIPLink::setStunServer( const std::string &server )
         /* Done. */    
     }
 
-    int SIPVoIPLink::getModId(){
+    int getModId(){
         return _mod_ua.id;
     }
 
@@ -1490,18 +1507,40 @@ void SIPVoIPLink::setStunServer( const std::string &server )
             Manager::instance().startVoiceMessageNotification(account, voicemail);
     }
 
+    void SIPVoIPLink::handle_reinvite (SIPCall *call) {
+    
+        // Close the previous RTP session
+        _audiortp->closeRtpSession ();
+        call->setAudioStart (false);
+    
+        // Create a new one with new info
+        if (_audiortp->createNewSession (call) >= 0) {
+            call->setAudioStart (true);
+        }
+    }
+
+
     /*******************************/
     /*   CALLBACKS IMPLEMENTATION  */
     /*******************************/
 
     void call_on_state_changed( pjsip_inv_session *inv, pjsip_event *e){
 
-        PJ_UNUSED_ARG(inv);
+        SIPCall *call;
+        AccountID accId;
+        SIPVoIPLink *link;
+        pjsip_rx_data *rdata;
+
+        _debug (" *****************************  NEW CALL STATE %i **************************\n", inv->state);        
 
-        SIPCall *call = reinterpret_cast<SIPCall*> (inv->mod_data[_mod_ua.id]);
+        /* Retrieve the call information */
+        call = reinterpret_cast<SIPCall*> (inv->mod_data[_mod_ua.id]);
         if(!call)
             return;
 
+        //Retrieve the body message
+        rdata = e->body.tsx_state.src.rdata;
+
         /* If this is an outgoing INVITE that was created because of
          * REFER/transfer, send NOTIFY to transferer.
          */
@@ -1558,135 +1597,90 @@ void SIPVoIPLink::setStunServer( const std::string &server )
                 }
             }
         }
-    }
+        else {
 
-    void call_on_media_update( pjsip_inv_session *inv UNUSED, pj_status_t status UNUSED) {
-        _debug("call_on_media_updated\n");
-    }
-
-    void call_on_forked(pjsip_inv_session *inv, pjsip_event *e){
-        _debug("call_on_forked\n");
-    }
-
-    void call_on_tsx_changed(pjsip_inv_session *inv, pjsip_transaction *tsx, pjsip_event *e){
-
-        pjsip_rx_data *rdata;
-        AccountID accId;
-        SIPCall *call;
-        SIPVoIPLink *link;
-        pjsip_msg *msg;
-
-        if(pj_strcmp2(&tsx->method.name, "INFO") == 0) {
-            // Receive a INFO message, ingore it!
-            return;
-        }
-
-        //Retrieve the body message
-        rdata = e->body.tsx_state.src.rdata;
-
-        if (tsx->role == PJSIP_ROLE_UAC) {
-            switch (tsx->state) {
-                case PJSIP_TSX_STATE_TERMINATED:
-                    if (tsx->status_code == 200 &&
-                            pjsip_method_cmp(&tsx->method, pjsip_get_refer_method()) != 0) {
-                        // Peer answered the outgoing call
-                        _debug("UserAgent: Peer answered the outgoing call!\n");
-                        call = reinterpret_cast<SIPCall *> (inv->mod_data[_mod_ua.id]);
-                        if (call == NULL)
-                            return;
+            // The call is ringing
+            if (inv->state == PJSIP_INV_STATE_EARLY){
+                _debug ("*************************** PJSIP_INV_STATE_EARLY - PEER RINGING ***********************************\n");
+                call->setConnectionState(Call::Ringing);
+                Manager::instance().peerRingingCall(call->getCallId());
+            }
 
-                        //_debug("UserAgent: The call id is %s\n", call->getCallId().data());
+            // We receive a ACK - The connection is established
+            else if( inv->state == PJSIP_INV_STATE_CONFIRMED ){
+                _debug ("*************************** PJSIP_INV_STATE_CONFIRMED ***********************************\n");
+                accId = Manager::instance().getAccountFromCall(call->getCallId());
+                link = dynamic_cast<SIPVoIPLink *> (Manager::instance().getAccountLink(accId));
+                if (link)
+                    link->SIPCallAnswered(call, rdata);
+            }
 
+            else if( inv->state == PJSIP_INV_STATE_DISCONNECTED ){
+                _debug ("*************************** PJSIP_INV_STATE_DISCONNECTED  %i***********************************\n", inv->cause);
+                switch( inv->cause )
+                {
+                    /* The call terminates normally - BYE / CANCEL */
+                    case PJSIP_SC_OK:
+                    case PJSIP_SC_DECLINE:
                         accId = Manager::instance().getAccountFromCall(call->getCallId());
                         link = dynamic_cast<SIPVoIPLink *> (Manager::instance().getAccountLink(accId));
-                        if (link)
-                            link->SIPCallAnswered(call, rdata);
-                    } else if (tsx->status_code / 100 == 5) {
-                        _debug("UserAgent: 5xx error message received\n");
-                    }
-                    break;
-                case PJSIP_TSX_STATE_PROCEEDING:
-                    // Peer is ringing for the outgoing call
-                    msg = rdata->msg_info.msg;
-
-                    call = reinterpret_cast<SIPCall *> (inv->mod_data[_mod_ua.id]);
-                    if (call == NULL)
-                        return;
-
-                    if (msg->line.status.code == 180) {
-                        _debug("UserAgent: Peer is ringing!\n");
-
-                        call->setConnectionState(Call::Ringing);
-                        Manager::instance().peerRingingCall(call->getCallId());
-                    }
-                    break;
-                case PJSIP_TSX_STATE_COMPLETED:
-                    if (tsx->status_code == 407 || tsx->status_code == 401) //FIXME
-                        break;
-                    if (tsx->status_code / 100 == 6 || tsx->status_code / 100 == 4) {
-                        // We get error message of outgoing call from server
-                        _debug("UserAgent: Server error message is received!\n");
-                        call = reinterpret_cast<SIPCall *> (inv->mod_data[_mod_ua.id]);
-                        if (call == NULL) {
-                            _debug("UserAgent: Call has been removed!\n");
-                            return;
+                        if (link) {
+                            link->SIPCallClosed(call);
                         }
+                        break; 
+
+                    /* The call connection failed */
+                    case PJSIP_SC_NOT_FOUND:            /* peer not found */
+                    case PJSIP_SC_REQUEST_TIMEOUT:      /* request timeout */
+                    case PJSIP_SC_NOT_ACCEPTABLE_HERE:  /* no compatible codecs */
+                    case PJSIP_SC_NOT_ACCEPTABLE_ANYWHERE:
+                    case PJSIP_SC_UNSUPPORTED_MEDIA_TYPE:
                         accId = Manager::instance().getAccountFromCall(call->getCallId());
                         link = dynamic_cast<SIPVoIPLink *> (Manager::instance().getAccountLink(accId));
                         if (link) {
                             link->SIPCallServerFailure(call);
                         }
-                    }
-                    break;
-                default:
-                    break;
-            } // end of switch
+                        break;
+                    
+                    default:
+                        _debug ("sipvoiplink.cpp - line 1635 : Unhandled call state. This is probably a bug.\n");
+                        break;
+                }
+            }
 
-        } else {
-            switch (tsx->state) {
-                case PJSIP_TSX_STATE_TRYING:
-                    if (pjsip_method_cmp(&tsx->method, pjsip_get_refer_method()) == 0) {
-                        // Peer ask me to transfer call to another number.
-                        _debug("UserAgent: Incoming REFER request!\n");
-                        //onCallTransfered(inv, e->body.tsx_state.src.rdata);
-                    }
-                    break;
-                case PJSIP_TSX_STATE_COMPLETED:
-                    if (tsx->status_code == 200 && tsx->method.id == PJSIP_BYE_METHOD) {
-                        // Peer hangup the call
-                        _debug("UserAgent: Peer hangup(bye) message is received!\n");
-                        call = reinterpret_cast<SIPCall *> (inv->mod_data[_mod_ua.id]);
-                        if (call == NULL) {
-                            _debug("UserAgent: Call has been removed!\n");
-                            return;
-                        }
-                        accId = Manager::instance().getAccountFromCall(call->getCallId());
-                        link = dynamic_cast<SIPVoIPLink *> (Manager::instance().getAccountLink(accId));
-                        if (link) {
-                            link->SIPCallClosed(call);
-                        }
-                    } else if (tsx->status_code == 200 && tsx->method.id == PJSIP_CANCEL_METHOD) {
-                        // Peer refuse the call
-                        _debug("UserAgent: Cancel message is received!\n");
-                        call = reinterpret_cast<SIPCall *> (inv->mod_data[_mod_ua.id]);
-                        if (call == NULL) {
-                            _debug("UserAgent: Call has been removed!\n");
-                            return;
-                        }
 
-                        accId = Manager::instance().getAccountFromCall(call->getCallId());
-                        link = dynamic_cast<SIPVoIPLink *> (Manager::instance().getAccountLink(accId));
-                        if (link) {
-                            link->SIPCallClosed(call);
-                        }
-                    }
-                    break;
-                default:
-                    break;
-            } // end of switch
         }
     }
 
+    void call_on_media_update( pjsip_inv_session *inv, pj_status_t status) {
+        _debug("call_on_media_updated\n");
+
+        const pjmedia_sdp_session *r_sdp;
+        SIPCall *call;
+
+        if (status != PJ_SUCCESS) {
+            _debug ("Error while negociating the offer\n");
+            return;
+        }
+
+        // Get the new sdp, result of the negociation
+        pjmedia_sdp_neg_get_active_local( inv->neg, &r_sdp );
+
+        call = reinterpret_cast<SIPCall *> (inv->mod_data[getModId()]);
+        // Clean the resulting sdp offer to create a new one (in case of a reinvite)
+        call->getLocalSDP()->clean_session_media();
+        // Set the fresh negociated one
+        call->getLocalSDP()->set_negociated_offer( r_sdp );
+    }
+
+    void call_on_forked(pjsip_inv_session *inv, pjsip_event *e){
+        _debug("call_on_forked\n");
+    }
+
+    void call_on_tsx_changed(pjsip_inv_session *inv, pjsip_transaction *tsx, pjsip_event *e){
+        _debug ("call_on_tsx_changed\n");
+    }
+
     void regc_cb(struct pjsip_regc_cbparam *param){
 
         //AccountID *id = static_cast<AccountID *> (param->token);
@@ -1754,6 +1748,8 @@ void SIPVoIPLink::setStunServer( const std::string &server )
             SIPVoIPLink *link;
             CallID id;
             SIPCall* call;
+            pjsip_inv_session *inv;
+            pjmedia_sdp_session *r_sdp;
 
             // voicemail part
             std::string method_name;
@@ -1840,7 +1836,7 @@ void SIPVoIPLink::setStunServer( const std::string &server )
 
             // Generate a new call ID for the incoming call!
             id = Manager::instance().getNewCallID();
-            call = new SIPCall(id, Call::Incoming);
+            call = new SIPCall(id, Call::Incoming, _pool);
 
             /* If an error occured at the call creation */
             if (!call) {
@@ -1848,43 +1844,32 @@ void SIPVoIPLink::setStunServer( const std::string &server )
                 return false;
             }
 
+            // Have to do some stuff with the SDP
             // Set the codec map, IP, peer number and so on... for the SIPCall object
             setCallAudioLocal(call, link->getLocalIPAddress(), link->useStun(), link->getStunServer());
-            call->setCodecMap(Manager::instance().getCodecDescriptorMap());
+            // We retrieve the remote sdp offer in the rdata struct to begin the negociation
+            call->getLocalSDP()->set_ip_address(link->getLocalIPAddress());
+            get_remote_sdp_from_offer( rdata, &r_sdp );
+            call->getLocalSDP()->receiving_initial_offer( r_sdp );
+
             call->setConnectionState(Call::Progressing);
-            call->setIp(link->getLocalIPAddress());
             call->setPeerNumber(peerNumber);
 
             call->initRecFileName();
 
-            /* Call the SIPCallInvite function to generate the local sdp,
-             * remote sdp and negociator.
-             * This function is also used to set the parameters of audio RTP, including:
-             *     local IP and port number 
-             *     remote IP and port number
-             *     possilbe audio codec will be used in this call
-             */
-            if (call->SIPCallInvite(rdata, _pool)) {
-
-                // Notify UI there is an incoming call
-                if (Manager::instance().incomingCall(call, account_id)) {
-                    // Add this call to the callAccountMap in ManagerImpl
-                    Manager::instance().getAccountLink(account_id)->addCall(call);
-                } else {
-                    // Fail to notify UI
-                    delete call;
-                    call = NULL;
-                    _debug("UserAgent: Fail to notify UI!\n");
-                    return false;
-                }
+            // Notify UI there is an incoming call
+            if (Manager::instance().incomingCall(call, account_id)) {
+                // Add this call to the callAccountMap in ManagerImpl
+                Manager::instance().getAccountLink(account_id)->addCall(call);
             } else {
-                // Fail to collect call information
+                // Fail to notify UI
                 delete call;
                 call = NULL;
-                _debug("UserAgent: Call SIPCallInvite failed!\n");
+                _debug("UserAgent: Fail to notify UI!\n");
                 return false;
             }
 
+
             /* Create the local dialog (UAS) */
             status = pjsip_dlg_create_uas(pjsip_ua_instance(), rdata, NULL, &dialog);
             if (status != PJ_SUCCESS) {
@@ -1894,8 +1879,7 @@ void SIPVoIPLink::setStunServer( const std::string &server )
             }
 
             // Specify media capability during invite session creation
-            pjsip_inv_session *inv;
-            status = pjsip_inv_create_uas(dialog, rdata, call->getLocalSDPSession(), 0, &inv);
+            status = pjsip_inv_create_uas(dialog, rdata, call->getLocalSDP()->get_local_sdp_session(), 0, &inv);
             PJ_ASSERT_RETURN(status == PJ_SUCCESS, 1);
 
             // Associate the call in the invite session
@@ -2306,3 +2290,58 @@ void SIPVoIPLink::setStunServer( const std::string &server )
             _debug("UserAgent: Xfer server subscription terminated\n");
         }    
     }
+
+    void on_rx_offer( pjsip_inv_session *inv, const pjmedia_sdp_session *offer ){
+        
+        _debug ( "********************************* REINVITE RECEIVED *******************************\n" );
+
+#ifdef CAN_REINVITE
+        _debug ("reinvite                                                  SIP\n");
+
+        SIPCall *call;
+        pj_status_t status;
+        AccountID accId;
+        SIPVoIPLink *link;
+
+        call = (SIPCall*)inv->mod_data[getModId()];
+        if (!call)
+            return;
+
+        accId = Manager::instance().getAccountFromCall(call->getCallId());
+        link = dynamic_cast<SIPVoIPLink *> (Manager::instance().getAccountLink(accId));
+
+        call->getLocalSDP()->receiving_initial_offer( (pjmedia_sdp_session*)offer);
+        status=pjsip_inv_set_sdp_answer( call->getInvSession(), call->getLocalSDP()->get_local_sdp_session() );
+        if (link)
+            link->handle_reinvite (call);
+#endif
+
+    }
+
+/*****************************************************************************************************************/
+
+
+    bool setCallAudioLocal(SIPCall* call, std::string localIP, bool stun, std::string server) {
+        // Setting Audio
+        unsigned int callLocalAudioPort = RANDOM_LOCAL_PORT;
+        unsigned int callLocalExternAudioPort = callLocalAudioPort;
+        if (stun) {
+            // If use Stun server
+            if (Manager::instance().behindNat(server, callLocalAudioPort)) {
+                callLocalExternAudioPort = Manager::instance().getFirewallPort();
+            }
+        }
+        _debug("            Setting local audio port to: %d\n", callLocalAudioPort);
+        _debug("            Setting local audio port (external) to: %d\n", callLocalExternAudioPort);
+
+        // Set local audio port for SIPCall(id)
+        call->setLocalIp(localIP);
+        call->setLocalAudioPort(callLocalAudioPort);
+        call->setLocalExternAudioPort(callLocalExternAudioPort);
+
+        call->getLocalSDP()->attribute_port_to_all_media (callLocalExternAudioPort);
+
+        return true;
+    }
+
+
diff --git a/src/sipvoiplink.h b/src/sipvoiplink.h
index fef56310f9c5f8fe66c24d0d9d1c72c8d30ea320..3180dd5c2b6a6e1972cd62cbd4939a43c89b589a 100644
--- a/src/sipvoiplink.h
+++ b/src/sipvoiplink.h
@@ -33,7 +33,6 @@
 #include <pjnath/stun_config.h>
 ///////////////////////////////
 
-
 class EventThread;
 class SIPCall;
 class AudioRtp;
@@ -113,7 +112,7 @@ class SIPVoIPLink : public VoIPLink
         /**
          * Answer the call
          * @param id The call identifier
-         * @return bool True on success
+         * @return int True on success
          */
         bool answer(const CallID& id);
 
@@ -267,6 +266,13 @@ class SIPVoIPLink : public VoIPLink
          */
         void SIPCallReleased(SIPCall *call);
 
+        /**
+         * Handle a re-invite request by the remote peer.
+         * A re-invite is an invite request inside a dialog.
+         * When receiving a re-invite, we close the current rtp session and create a new one with the updated information
+         */
+        void handle_reinvite (SIPCall *call);
+
         /**
          * SIPCall accessor
          * @param id  The call identifier
@@ -304,6 +310,8 @@ class SIPVoIPLink : public VoIPLink
          */
          std::string getCurrentCodecName();
       
+        int inv_session_reinvite (SIPCall *call, std::string direction="");
+        
 
     private:
         /**
@@ -316,7 +324,6 @@ class SIPVoIPLink : public VoIPLink
         static SIPVoIPLink* _instance;
 
         void busy_sleep(unsigned msec);
-        int getModId();
 
         /** 
          * Initialize the PJSIP library
diff --git a/src/user_cfg.h b/src/user_cfg.h
index fea650490eb60e5e34d77339b086c5610442ab47..a5ab0625f91101b9fa943d9bddef934b4049ecfb 100644
--- a/src/user_cfg.h
+++ b/src/user_cfg.h
@@ -45,8 +45,6 @@
 #define VOLUME_MICRO		"Volume.micro"	      /** Mic volume */
 #define RECORD_PATH             "Record.path"          /** Recording path */
 
-#define VIDEO			"Video"		      /** Section Video */
-
 #define PREFERENCES		"Preferences"		  /** Section Preferences */
 #define CONFIG_DIALPAD		"Dialpad.display"	  /** Display dialpad preferences */
 #define CONFIG_SEARCHBAR	"Searchbar.display"	  /** Whether or nor display the search bar */