[asterisk-scf-commits] asterisk-scf/integration/sip.git branch "party-id" created.

Commits to the Asterisk SCF project code repositories asterisk-scf-commits at lists.digium.com
Fri Oct 7 17:16:06 CDT 2011


branch "party-id" has been created
        at  3fff8394ae39b9151fc277e18e8249fca07b6882 (commit)

- Log -----------------------------------------------------------------
commit 3fff8394ae39b9151fc277e18e8249fca07b6882
Author: Mark Michelson <mmichelson at digium.com>
Date:   Fri Oct 7 17:14:58 2011 -0500

    Set session owner ID based on parsed data.

diff --git a/src/PJSipSessionModule.cpp b/src/PJSipSessionModule.cpp
index 2192f88..cb70181 100644
--- a/src/PJSipSessionModule.cpp
+++ b/src/PJSipSessionModule.cpp
@@ -430,6 +430,7 @@ protected:
         mSession->setDialog(mInv->dlg);
 
         mSession->setTelephonyEventSourcesAndSinks(mCaller->getConfig());
+        mSession->setSessionOwnerId(mCallerID);
 
         // Create an SDP offer or answer
         const pjmedia_sdp_session *remote_sdp = NULL;
@@ -1210,6 +1211,7 @@ protected:
                 }
             }
         }
+        mSession->setSessionOwnerId(mConnected);
         return Complete;
     }
 
diff --git a/src/SipSession.cpp b/src/SipSession.cpp
index 3db5ee3..2c2b9e5 100755
--- a/src/SipSession.cpp
+++ b/src/SipSession.cpp
@@ -936,6 +936,12 @@ void SipSession::setSelfAsCaller()
     mImplPriv->mSessionCookies[dialed->ice_id()] = dialed;
 }
 
+void SipSession::setSessionOwnerId(const SessionOwnerIdPtr& owner)
+{
+    mImplPriv->mSessionCookies[owner->ice_id()] = owner;
+    mImplPriv->cookiesUpdated();
+}
+
 class CheckDirectConnectionsOperation : public SuspendableWork
 {
 public:
diff --git a/src/SipSession.h b/src/SipSession.h
index 50da5f9..3ac4ba2 100644
--- a/src/SipSession.h
+++ b/src/SipSession.h
@@ -348,6 +348,9 @@ public:
 
     void setSelfAsCaller();
 
+    //Must be called from a queued operation
+    void setSessionOwnerId(const AsteriskSCF::SessionCommunications::PartyIdentification::V1::SessionOwnerIdPtr& owner);
+
 private:
     SipSession(const Ice::ObjectAdapterPtr&, const SipEndpointPtr&, const std::string&,
         const std::vector<AsteriskSCF::SessionCommunications::V1::SessionListenerPrx>&,         

commit e80f5d91f5454462a110a261eca4038112124b02
Author: Mark Michelson <mmichelson at digium.com>
Date:   Fri Oct 7 16:16:08 2011 -0500

    Parse connected line data on SIP responses.

diff --git a/src/PJSipSessionModule.cpp b/src/PJSipSessionModule.cpp
index c175836..2192f88 100644
--- a/src/PJSipSessionModule.cpp
+++ b/src/PJSipSessionModule.cpp
@@ -406,8 +406,9 @@ public:
             pjsip_inv_session *inv,
             pjsip_tx_data *tdata,
             pjsip_dialog *replacedDialog,
-            const std::string destination)
-        : mSessionModule(module), mCaller(caller), mSessionRouter(router), mInv(inv), mTdata(tdata), mReplacedDialog(replacedDialog), mDestination(destination) { }
+            const std::string destination,
+            const CallerPtr& callerID)
+        : mSessionModule(module), mCaller(caller), mSessionRouter(router), mInv(inv), mTdata(tdata), mReplacedDialog(replacedDialog), mDestination(destination), mCallerID(callerID) { }
 
 protected:
     SuspendableWorkResult initial(const SuspendableWorkListenerPtr&)
@@ -529,9 +530,10 @@ private:
     pjsip_dialog *mReplacedDialog;
     const std::string mDestination;
     SipSessionPtr mSession;
+    CallerPtr mCallerID;
 };
 
-void getIds(const char *headerName, pjsip_rx_data *rdata, IdSeq& ids)
+void PJSipSessionModule::getIds(const char *headerName, pjsip_rx_data *rdata, IdSeq& ids)
 {
     pj_str_t hdrName;
     pj_cstr(&hdrName, headerName);
@@ -566,6 +568,21 @@ CallerPtr PJSipSessionModule::getCallerID(pjsip_rx_data *rdata)
     return caller;
 }
 
+ConnectedLinePtr PJSipSessionModule::getConnectedID(pjsip_rx_data *rdata)
+{
+    ConnectedLinePtr connected(new ConnectedLine);
+    getIds("P-Asserted-Identity", rdata, connected->ids);
+    if (!connected->ids.empty())
+    {
+        return connected;
+    }
+
+    //There were no P-Asserted-Identity headers present. Maybe
+    //they've used Remote-Party-ID instead...
+    getIds("Remote-Party-ID", rdata, connected->ids);
+    return connected;
+}
+
 void PJSipSessionModule::handleNewInvite(pjsip_rx_data *rdata)
 {
     //What do we do here?
@@ -727,10 +744,8 @@ void PJSipSessionModule::handleNewInvite(pjsip_rx_data *rdata)
     //Now let's see if they've identified themselves somehow...
     CallerPtr callerID = getCallerID(rdata);
 
-    // See if any SDP was present on this INVITE
-    
     lg(Debug) << "Queueing a SessionCreationOperation";
-    sessionWork->enqueueWork(new SessionCreationOperation(this, caller, mSessionRouter, inv_session, tdata, replaced_dlg, destination));
+    sessionWork->enqueueWork(new SessionCreationOperation(this, caller, mSessionRouter, inv_session, tdata, replaced_dlg, destination, callerID));
 }
 
 void PJSipSessionModule::handleRefer(pjsip_inv_session *inv, pjsip_rx_data *rdata)
@@ -1106,10 +1121,11 @@ class HandleInviteResponseOperation : public SipQueueableOperation
 {
 public:
     HandleInviteResponseOperation(int respCode, const int invState,
-            const SipSessionPtr& session) :
+            const SipSessionPtr& session, const ConnectedLinePtr& connected) :
         mRespCode(respCode),
         mInvState(invState),
-        mSession(session)
+        mSession(session),
+        mConnected(connected)
     {
     }
 
@@ -1216,6 +1232,7 @@ private:
     int mRespCode;
     const int mInvState;
     SipSessionPtr mSession;
+    ConnectedLinePtr mConnected;
 };
 
 void PJSipSessionModule::handleInviteResponse(pjsip_inv_session* inv,
@@ -1224,6 +1241,9 @@ void PJSipSessionModule::handleInviteResponse(pjsip_inv_session* inv,
     int respCode = rdata->msg_info.msg->line.status.code;
     PJSipSessionModInfo *session_mod_info = (PJSipSessionModInfo*)inv->mod_data[mModule.id];
     SipSessionPtr session = session_mod_info->getSessionPtr();
+
+    ConnectedLinePtr connected = getConnectedID(rdata);
+
     //Commented because they are currently unused. They
     //will be once the individual cases are mapped out.
     //pjsip_dialog *dlg = pjsip_rdata_get_dlg(rdata);
@@ -1233,7 +1253,7 @@ void PJSipSessionModule::handleInviteResponse(pjsip_inv_session* inv,
     //to add code to handle.
 
     lg(Debug) << "Queuing a HandleInviteResponseOperation";
-    enqueueSessionWork(new HandleInviteResponseOperation(respCode, inv->state, session), inv);
+    enqueueSessionWork(new HandleInviteResponseOperation(respCode, inv->state, session, connected), inv);
 }
 
 class TransactionStateOperation : public SipQueueableOperation
diff --git a/src/PJSipSessionModule.h b/src/PJSipSessionModule.h
index a107219..c28e055 100644
--- a/src/PJSipSessionModule.h
+++ b/src/PJSipSessionModule.h
@@ -140,7 +140,9 @@ public:
 
 private:
     void handleNewInvite(pjsip_rx_data *rdata);
+    void getIds(const char *headerName, pjsip_rx_data *rdata, AsteriskSCF::SessionCommunications::PartyIdentification::V1::IdSeq& ids);
     AsteriskSCF::SessionCommunications::PartyIdentification::V1::CallerPtr getCallerID(pjsip_rx_data *rdata);
+    AsteriskSCF::SessionCommunications::PartyIdentification::V1::ConnectedLinePtr getConnectedID(pjsip_rx_data *rdata);
     void handleInviteResponse(pjsip_inv_session *inv, pjsip_rx_data *rdata, pjsip_dialog *dlg);
     void handleRefer(pjsip_inv_session *inv, pjsip_rx_data *rdata);
     void handleInfo(pjsip_inv_session *inv, pjsip_rx_data *rdata);

commit 9d4f48a5bf3fe0be58fcd0c0eb4260be64de6005
Author: Mark Michelson <mmichelson at digium.com>
Date:   Fri Oct 7 15:04:48 2011 -0500

    Streamline the ID extraction routine some.
    
    This will make it much easier to get IDs from arbitrary headers
    easily on all types of messages.

diff --git a/src/PJSipSessionModule.cpp b/src/PJSipSessionModule.cpp
index 4c3222a..c175836 100644
--- a/src/PJSipSessionModule.cpp
+++ b/src/PJSipSessionModule.cpp
@@ -531,21 +531,15 @@ private:
     SipSessionPtr mSession;
 };
 
-CallerPtr PJSipSessionModule::getCallerID(pjsip_rx_data *rdata)
+void getIds(const char *headerName, pjsip_rx_data *rdata, IdSeq& ids)
 {
-    //Strategy: If there is a P-Asserted-Identity header (or headers)
-    //present, then use those to fill the caller ID information in. If
-    //there is not a P-Asserted-Identity header, then use the From header
-    //to fill in this information.
-
-    pj_str_t pai;
-    pj_cstr(&pai, "P-Asserted-Identity");
-    pjsip_fromto_hdr *paiHdr = (pjsip_fromto_hdr *) &rdata->msg_info.msg->hdr;
+    pj_str_t hdrName;
+    pj_cstr(&hdrName, headerName);
 
-    CallerPtr caller(new Caller);
-    while ((paiHdr = (pjsip_fromto_hdr *) pjsip_msg_find_hdr_by_name(rdata->msg_info.msg, &pai, paiHdr->next)))
+    pjsip_fromto_hdr *hdr = (pjsip_fromto_hdr *) &rdata->msg_info.msg->hdr;
+    while ((hdr = (pjsip_fromto_hdr *) pjsip_msg_find_hdr_by_name(rdata->msg_info.msg, &hdrName, hdr->next)))
     {
-        pjsip_name_addr *idNameAddr = (pjsip_name_addr*) paiHdr->uri;
+        pjsip_name_addr *idNameAddr = (pjsip_name_addr*) hdr->uri;
 
         NamePtr name(new Name(std::string(pj_strbuf(&idNameAddr->display), pj_strlen(&idNameAddr->display))));
 
@@ -553,9 +547,14 @@ CallerPtr PJSipSessionModule::getCallerID(pjsip_rx_data *rdata)
         NumberPtr number (new Number(std::string(pj_strbuf(&idURI->user), pj_strlen(&idURI->user))));
 
         IdPtr id(new Id(name, number));
-        caller->ids.push_back(id);
+        ids.push_back(id);
     }
+}
 
+CallerPtr PJSipSessionModule::getCallerID(pjsip_rx_data *rdata)
+{
+    CallerPtr caller(new Caller);
+    getIds("P-Asserted-Identity", rdata, caller->ids); 
     if (!caller->ids.empty())
     {
         return caller;
@@ -563,14 +562,7 @@ CallerPtr PJSipSessionModule::getCallerID(pjsip_rx_data *rdata)
 
     //There were no P-Asserted-Identity headers present. On an incoming call, we'll get caller ID from the
     //From header instead.
-    pjsip_name_addr *from = (pjsip_name_addr *) rdata->msg_info.from->uri;
-    NamePtr name(new Name(std::string(pj_strbuf(&from->display), pj_strlen(&from->display))));
-    pjsip_sip_uri *fromURI = (pjsip_sip_uri *) pjsip_uri_get_uri(from);
-    NumberPtr number(new Number(std::string(pj_strbuf(&fromURI->user),  pj_strlen(&fromURI->user))));
-
-    IdPtr id(new Id(name, number));
-    caller->ids.push_back(id);
-
+    getIds("From", rdata, caller->ids);
     return caller;
 }
 

commit bc4bd784fbed179b74e0d37926ac3601fb4577d5
Author: Mark Michelson <mmichelson at digium.com>
Date:   Fri Oct 7 14:29:55 2011 -0500

    * Use From header for caller ID if no PAI is present
    * Don't use generic string header. use fromto header instead.

diff --git a/src/PJSipSessionModule.cpp b/src/PJSipSessionModule.cpp
index 66562fb..4c3222a 100644
--- a/src/PJSipSessionModule.cpp
+++ b/src/PJSipSessionModule.cpp
@@ -540,18 +540,12 @@ CallerPtr PJSipSessionModule::getCallerID(pjsip_rx_data *rdata)
 
     pj_str_t pai;
     pj_cstr(&pai, "P-Asserted-Identity");
-    pjsip_generic_string_hdr *paiHdr = (pjsip_generic_string_hdr *) &rdata->msg_info.msg->hdr;
+    pjsip_fromto_hdr *paiHdr = (pjsip_fromto_hdr *) &rdata->msg_info.msg->hdr;
 
     CallerPtr caller(new Caller);
-    while ((paiHdr = (pjsip_generic_string_hdr *) pjsip_msg_find_hdr_by_name(rdata->msg_info.msg, &pai, paiHdr->next)))
+    while ((paiHdr = (pjsip_fromto_hdr *) pjsip_msg_find_hdr_by_name(rdata->msg_info.msg, &pai, paiHdr->next)))
     {
-        //The reason for the use of a string here instead of just passing paiHdr->hvalue to
-        //pjsip_parse_uri() is that the documentation is quite clear that the string passed to
-        //pjsip_parse_uri() must be null-terminated. pj_str_t strings are not null-terminated.
-        //If there's a better way of doing this, let me know, because this just feels weird, especially
-        //with the cast.
-        std::string URI(pj_strbuf(&paiHdr->hvalue), pj_strlen(&paiHdr->hvalue));
-        pjsip_name_addr *idNameAddr = (pjsip_name_addr*) pjsip_parse_uri(rdata->tp_info.pool, (char *)URI.c_str(), URI.size(), PJSIP_PARSE_URI_AS_NAMEADDR);
+        pjsip_name_addr *idNameAddr = (pjsip_name_addr*) paiHdr->uri;
 
         NamePtr name(new Name(std::string(pj_strbuf(&idNameAddr->display), pj_strlen(&idNameAddr->display))));
 
@@ -561,6 +555,22 @@ CallerPtr PJSipSessionModule::getCallerID(pjsip_rx_data *rdata)
         IdPtr id(new Id(name, number));
         caller->ids.push_back(id);
     }
+
+    if (!caller->ids.empty())
+    {
+        return caller;
+    }
+
+    //There were no P-Asserted-Identity headers present. On an incoming call, we'll get caller ID from the
+    //From header instead.
+    pjsip_name_addr *from = (pjsip_name_addr *) rdata->msg_info.from->uri;
+    NamePtr name(new Name(std::string(pj_strbuf(&from->display), pj_strlen(&from->display))));
+    pjsip_sip_uri *fromURI = (pjsip_sip_uri *) pjsip_uri_get_uri(from);
+    NumberPtr number(new Number(std::string(pj_strbuf(&fromURI->user),  pj_strlen(&fromURI->user))));
+
+    IdPtr id(new Id(name, number));
+    caller->ids.push_back(id);
+
     return caller;
 }
 

commit cf506fd0d7be69ef2e8b061387b21e92d36afc2a
Author: Mark Michelson <mmichelson at digium.com>
Date:   Fri Oct 7 14:06:48 2011 -0500

    Parse the P-Asserted-Identity header on incoming INVITEs.

diff --git a/src/PJSipSessionModule.cpp b/src/PJSipSessionModule.cpp
index 9504d47..66562fb 100644
--- a/src/PJSipSessionModule.cpp
+++ b/src/PJSipSessionModule.cpp
@@ -70,6 +70,7 @@ using namespace AsteriskSCF::System::ThreadPool::V1;
 using namespace AsteriskSCF::System::WorkQueue::V1;
 using namespace AsteriskSCF::WorkQueue;
 using namespace AsteriskSCF::Core::Discovery::V1;
+using namespace AsteriskSCF::SessionCommunications::PartyIdentification::V1;
 
 PJSipSessionModInfo::PJSipSessionModInfo(pjsip_inv_session *inv_session,
     const SipSessionPtr& session, const SessionWorkPtr& sessionWork) :
@@ -530,6 +531,39 @@ private:
     SipSessionPtr mSession;
 };
 
+CallerPtr PJSipSessionModule::getCallerID(pjsip_rx_data *rdata)
+{
+    //Strategy: If there is a P-Asserted-Identity header (or headers)
+    //present, then use those to fill the caller ID information in. If
+    //there is not a P-Asserted-Identity header, then use the From header
+    //to fill in this information.
+
+    pj_str_t pai;
+    pj_cstr(&pai, "P-Asserted-Identity");
+    pjsip_generic_string_hdr *paiHdr = (pjsip_generic_string_hdr *) &rdata->msg_info.msg->hdr;
+
+    CallerPtr caller(new Caller);
+    while ((paiHdr = (pjsip_generic_string_hdr *) pjsip_msg_find_hdr_by_name(rdata->msg_info.msg, &pai, paiHdr->next)))
+    {
+        //The reason for the use of a string here instead of just passing paiHdr->hvalue to
+        //pjsip_parse_uri() is that the documentation is quite clear that the string passed to
+        //pjsip_parse_uri() must be null-terminated. pj_str_t strings are not null-terminated.
+        //If there's a better way of doing this, let me know, because this just feels weird, especially
+        //with the cast.
+        std::string URI(pj_strbuf(&paiHdr->hvalue), pj_strlen(&paiHdr->hvalue));
+        pjsip_name_addr *idNameAddr = (pjsip_name_addr*) pjsip_parse_uri(rdata->tp_info.pool, (char *)URI.c_str(), URI.size(), PJSIP_PARSE_URI_AS_NAMEADDR);
+
+        NamePtr name(new Name(std::string(pj_strbuf(&idNameAddr->display), pj_strlen(&idNameAddr->display))));
+
+        pjsip_sip_uri *idURI = (pjsip_sip_uri *) pjsip_uri_get_uri(idNameAddr);
+        NumberPtr number (new Number(std::string(pj_strbuf(&idURI->user), pj_strlen(&idURI->user))));
+
+        IdPtr id(new Id(name, number));
+        caller->ids.push_back(id);
+    }
+    return caller;
+}
+
 void PJSipSessionModule::handleNewInvite(pjsip_rx_data *rdata)
 {
     //What do we do here?
@@ -688,6 +722,9 @@ void PJSipSessionModule::handleNewInvite(pjsip_rx_data *rdata)
         lg(Debug) << "Call is destined for " << destination;
     }
 
+    //Now let's see if they've identified themselves somehow...
+    CallerPtr callerID = getCallerID(rdata);
+
     // See if any SDP was present on this INVITE
     
     lg(Debug) << "Queueing a SessionCreationOperation";
diff --git a/src/PJSipSessionModule.h b/src/PJSipSessionModule.h
index 9305f0f..a107219 100644
--- a/src/PJSipSessionModule.h
+++ b/src/PJSipSessionModule.h
@@ -140,6 +140,7 @@ public:
 
 private:
     void handleNewInvite(pjsip_rx_data *rdata);
+    AsteriskSCF::SessionCommunications::PartyIdentification::V1::CallerPtr getCallerID(pjsip_rx_data *rdata);
     void handleInviteResponse(pjsip_inv_session *inv, pjsip_rx_data *rdata, pjsip_dialog *dlg);
     void handleRefer(pjsip_inv_session *inv, pjsip_rx_data *rdata);
     void handleInfo(pjsip_inv_session *inv, pjsip_rx_data *rdata);

commit 621bee585d88c664857a403cc9eb4022dcb504db
Author: Mark Michelson <mmichelson at digium.com>
Date:   Fri Oct 7 12:10:12 2011 -0500

    Add connected line information to INVITE responses.

diff --git a/src/SipSession.cpp b/src/SipSession.cpp
index 3b18a12..3db5ee3 100755
--- a/src/SipSession.cpp
+++ b/src/SipSession.cpp
@@ -1523,6 +1523,7 @@ public:
         // If the indication produced a packet send it out
         if (status == PJ_SUCCESS)
         {
+            addConnected(packet);
             pjsip_inv_send_msg(mImplPriv->mInviteSession, packet);
         }
 
@@ -1531,6 +1532,41 @@ public:
     }
 
 private:
+    void addConnected(pjsip_tx_data *packet)
+    {
+        AsteriskSCF::SessionCommunications::V1::SessionCookieDict::const_iterator iter =
+            mImplPriv->mSessionCookies.find(ConnectedLine::ice_staticId());
+
+        if (iter == mImplPriv->mSessionCookies.end())
+        {
+            lg(Debug) << "No Connected line cookie present";
+            return;
+        }
+
+        CallerPtr caller = CallerPtr::dynamicCast(iter->second);
+        for (IdSeq::iterator id = caller->ids.begin(); id != caller->ids.end(); ++id)
+        {
+            std::string connectedName = (*id)->partyName->partyName;
+            std::string connectedNumber = (*id)->partyNumber->partyNumber;
+
+            pj_str_t paiHeader;
+            pj_cstr(&paiHeader, "P-Asserted-Identity");
+            if (connectedName.empty())
+            {
+                connectedName = connectedNumber;
+            }
+            pj_str_t paiValue;
+            std::stringstream ss;
+            ss << "\"" << connectedName << "\" <" << connectedNumber << "@" << /*XXX WTF goes here? */ "..." << ">;party=called";
+            pj_cstr(&paiValue, ss.str().c_str());
+
+            pjsip_generic_string_hdr *hdr =
+                pjsip_generic_string_hdr_create(packet->pool, &paiHeader, &paiValue);
+
+            pjsip_msg_add_hdr(packet->msg, (pjsip_hdr*) hdr);
+        }
+    }
+
     AsteriskSCF::SessionCommunications::V1::AMD_Session_indicatePtr mCb;
     AsteriskSCF::SessionCommunications::V1::IndicationPtr mIndication;
     boost::shared_ptr<SipSessionPriv> mImplPriv;

commit b6d1c108babdd3564101ddc567182860e75a99e3
Author: Mark Michelson <mmichelson at digium.com>
Date:   Fri Oct 7 11:34:38 2011 -0500

    Add caller information on outgoing INVITEs.

diff --git a/src/SipSession.cpp b/src/SipSession.cpp
index 3182731..3b18a12 100755
--- a/src/SipSession.cpp
+++ b/src/SipSession.cpp
@@ -1970,6 +1970,8 @@ public:
 
         addReferredBy(packet);
 
+        addCaller(packet);
+
         // Boom! Houston, we have transmission.
         pjsip_inv_send_msg(mImplPriv->mInviteSession, packet);
         return Complete;
@@ -2011,6 +2013,41 @@ private:
 
         pjsip_msg_add_hdr(packet->msg, (pjsip_hdr*) hdr);
     }
+
+    void addCaller(pjsip_tx_data *packet)
+    {
+        AsteriskSCF::SessionCommunications::V1::SessionCookieDict::const_iterator iter =
+            mImplPriv->mSessionCookies.find(Caller::ice_staticId());
+
+        if (iter == mImplPriv->mSessionCookies.end())
+        {
+            lg(Debug) << "No Caller cookie present";
+            return;
+        }
+
+        CallerPtr caller = CallerPtr::dynamicCast(iter->second);
+        for (IdSeq::iterator id = caller->ids.begin(); id != caller->ids.end(); ++id)
+        {
+            std::string callerName = (*id)->partyName->partyName;
+            std::string callerNumber = (*id)->partyNumber->partyNumber;
+
+            pj_str_t paiHeader;
+            pj_cstr(&paiHeader, "P-Asserted-Identity");
+            if (callerName.empty())
+            {
+                callerName = callerNumber;
+            }
+            pj_str_t paiValue;
+            std::stringstream ss;
+            ss << "\"" << callerName << "\" <" << callerNumber << "@" << /*XXX WTF goes here? */ "..." << ">;party=calling";
+            pj_cstr(&paiValue, ss.str().c_str());
+
+            pjsip_generic_string_hdr *hdr =
+                pjsip_generic_string_hdr_create(packet->pool, &paiHeader, &paiValue);
+
+            pjsip_msg_add_hdr(packet->msg, (pjsip_hdr*) hdr);
+        }
+    }
     SipSessionPtr mSession;
     boost::shared_ptr<SipSessionPriv> mImplPriv;
 };

commit f9c355bfc60299b4ef25d5375aa53aacc9fee9e8
Author: Mark Michelson <mmichelson at digium.com>
Date:   Thu Oct 6 13:41:27 2011 -0500

    Fix 64 bit builds where size_t and int are different sizes.

diff --git a/src/SipClientRegistration.cpp b/src/SipClientRegistration.cpp
index a4e03d5..9aee763 100644
--- a/src/SipClientRegistration.cpp
+++ b/src/SipClientRegistration.cpp
@@ -15,6 +15,7 @@
  */
 
 #include "SipClientRegistration.h"
+#include <boost/numeric/conversion/cast.hpp>
 
 using namespace AsteriskSCF::System::Logging;
 
@@ -212,7 +213,7 @@ void SipRegistrationClient::createPJSIPRegistration(
             &serverURL,
             &fromURL,
             &toURL,
-            pjContacts.size(),
+            boost::numeric_cast<int>(pjContacts.size()),
             &pjContacts.front(),
             confItem->defaultExpiration
             );
@@ -289,7 +290,7 @@ void SipRegistrationClient::sendRegister()
     std::vector<pj_str_t> contacts;
     std::transform(mContacts.begin(), mContacts.end(), std::back_inserter(contacts), MakeContact(mReg));
 
-    pjsip_regc_update_contact(mReg, contacts.size(), &contacts.front());
+    pjsip_regc_update_contact(mReg, boost::numeric_cast<int>(contacts.size()), &contacts.front());
 
     pjsip_tx_data *tdata;
     pjsip_regc_register(mReg, PJ_TRUE, &tdata);
@@ -391,7 +392,7 @@ void SipRegistrationClient::authenticate(pjsip_rx_data *rdata)
             }
             if (creds.size() != 0)
             {
-                pjsip_regc_set_credentials(mReg, creds.size(), &creds.front());
+                pjsip_regc_set_credentials(mReg, boost::numeric_cast<int>(creds.size()), &creds.front());
                 sendRegister();
             }
             return;

commit 9920aea9b6e4647f41f3464e605d282154c9f9b9
Author: Mark Michelson <mmichelson at digium.com>
Date:   Thu Oct 6 11:16:08 2011 -0500

    Use the proper name for the constant for default registration since it has changed.

diff --git a/config/SipConfigurator.py b/config/SipConfigurator.py
index 01acf32..c7c9f6f 100755
--- a/config/SipConfigurator.py
+++ b/config/SipConfigurator.py
@@ -130,7 +130,7 @@ class SipSectionVisitors(Configurator.SectionVisitors):
         item = AsteriskSCF.Configuration.SipSessionManager.V1.SipClientRegistrationItem()
 
         mapper.map('aor', item, 'aor', 'registration', config.get, None)
-        mapper.map('expiration', item, 'defaultExpiration', 'registration', config.getint, AsteriskSCF.Configuration.SipSessionManager.V1.DefaultExpiration)
+        mapper.map('expiration', item, 'defaultExpiration', 'registration', config.getint, AsteriskSCF.Configuration.SipSessionManager.V1.DefaultRegistrationExpirationSeconds)
         handler = RegistrationContactHandler(config)
         mapper.map('contacts', item, 'contacts', 'registration', handler.get, None)
 

commit 0ca99918a255c76ca856ce1a1f4090b6d18834c2
Author: Mark Michelson <mmichelson at digium.com>
Date:   Wed Oct 5 17:02:55 2011 -0500

    Clarify documentation and change name of the method used to respond to an authentication challenge.

diff --git a/slice/AsteriskSCF/Configuration/SipSessionManager/SipConfigurationIf.ice b/slice/AsteriskSCF/Configuration/SipSessionManager/SipConfigurationIf.ice
index 6b74279..49f0d96 100644
--- a/slice/AsteriskSCF/Configuration/SipSessionManager/SipConfigurationIf.ice
+++ b/slice/AsteriskSCF/Configuration/SipSessionManager/SipConfigurationIf.ice
@@ -591,7 +591,7 @@ struct ContactInfo
 
 sequence<ContactInfo> ContactInfoSeq;
 
-const int DefaultExpiration = 3600;
+const int DefaultRegistrationExpirationSeconds = 3600;
 
 class SipClientRegistrationItem extends SipConfigurationItem
 {
@@ -606,8 +606,8 @@ class SipClientRegistrationItem extends SipConfigurationItem
     ContactInfoSeq contacts;
     /**
      * The expiration to use for any contacts
-     * with no explicit expiration set. Units
-     * for expiration are seconds.
+     * with no explicit expiration set (i.e. a 0 expiration).
+     * Units for expiration are seconds.
      */
     int defaultExpiration;
 };
diff --git a/src/SipClientRegistration.cpp b/src/SipClientRegistration.cpp
index ba624f7..a4e03d5 100644
--- a/src/SipClientRegistration.cpp
+++ b/src/SipClientRegistration.cpp
@@ -373,7 +373,7 @@ void SipRegistrationClient::authenticate(pjsip_rx_data *rdata)
         ClientAuthSeq auths;
         Ice::StringSeq realms = getRealms(rdata);
 
-        HookResult result = (*iter)->getCredentials(mEndpointName, realms, auths);
+        HookResult result = (*iter)->respondToChallenge(mEndpointName, realms, auths);
         if (result.status == Succeeded)
         {
             std::vector<pjsip_cred_info> creds;

commit 929a1cff9ce65f6e5b18f3d0dc0cf761b3683f47
Merge: 5e0ba08 1094f86
Author: Mark Michelson <mmichelson at digium.com>
Date:   Wed Oct 5 11:10:44 2011 -0500

    Merge branch 'master' into client-registration


commit 1094f862471a5cdc8955aecca1bbbeebba31b44c
Author: Joshua Colp <jcolp at digium.com>
Date:   Wed Oct 5 12:56:44 2011 -0300

    Only initialize pjlib once.

diff --git a/src/Component.cpp b/src/Component.cpp
index 37e6a7f..0e0a591 100644
--- a/src/Component.cpp
+++ b/src/Component.cpp
@@ -414,11 +414,6 @@ void Component::onPreInitialize()
 {
     try
     {
-        // Initialize PJSIP
-        // NOTE: Should use PJSipManager::create now.
-        mPJSipManager = PJSipManager::create(getName(), getCommunicator()->getProperties());
-        lg(Debug) << "Created PJSIP manager";
-
         //As nice as it is of IceBox to provide us with a communicator,
         //we're going to create our own so that we can provide it with a threadhook.
         //Yes, this could be done via a plugin, but this is easier. Go away.
@@ -426,6 +421,11 @@ void Component::onPreInitialize()
         id.threadHook = new AsteriskSCF::PJLib::ThreadHook("Ice");
         id.properties = getCommunicator()->getProperties();
 
+        // Initialize PJSIP
+        // NOTE: Should use PJSipManager::create now.
+        mPJSipManager = PJSipManager::create(getName(), getCommunicator()->getProperties());
+        lg(Debug) << "Created PJSIP manager";
+
         setCommunicator(Ice::initialize(id));
     }
     catch(const std::exception& e)
diff --git a/src/PJSipManager.cpp b/src/PJSipManager.cpp
index e4f1054..803edac 100644
--- a/src/PJSipManager.cpp
+++ b/src/PJSipManager.cpp
@@ -267,13 +267,6 @@ PJSipManager::PJSipManager() :
 {
     memset(&mCachingPool, 0, sizeof(mCachingPool));
 
-    pj_status_t status = pj_init();
-    if (fail(status))
-    {
-        const char* message = "Failed to Initialize PJSIP";
-        logger(Error) << message;
-        throw InternalInitializationException(message);
-    }
     // The third parameter is just copied from
     // example code from PJLIB. This can be adjusted
     // if necessary.
@@ -291,7 +284,7 @@ PJSipManager::PJSipManager() :
         throw InternalInitializationException(message);
     }
     
-    status = pj_thread_create(mMemoryPool, "SIP", (pj_thread_proc *) &monitorThread,
+    pj_status_t status = pj_thread_create(mMemoryPool, "SIP", (pj_thread_proc *) &monitorThread,
         this, PJ_THREAD_DEFAULT_STACK_SIZE * 2, 0, &mPjThread);
     if (fail(status))
     {

commit 5e0ba080e24eaa73a77601f50733047fc4b4aff3
Merge: 83d4e07 030ca07
Author: Mark Michelson <mmichelson at digium.com>
Date:   Tue Oct 4 18:25:42 2011 -0500

    Merge branch 'master' into client-registration
    
    Conflicts:
    	src/Component.cpp


commit 83d4e0737de244e6c1a64e8dac6dd12c04f8ec96
Author: Mark Michelson <mmichelson at digium.com>
Date:   Tue Oct 4 17:34:42 2011 -0500

    Set the replica proxy in the endpoint factory after it has actually been initialized.

diff --git a/src/Component.cpp b/src/Component.cpp
index 405ee50..53974e8 100644
--- a/src/Component.cpp
+++ b/src/Component.cpp
@@ -529,8 +529,7 @@ void Component::createPrimaryServices()
                     getBackplaneAdapter(),
                     mPJSipManager,
                     getServiceLocator(),
-                    sipReplicationContext,
-                    getReplicaProxy()));
+                    sipReplicationContext));
         lg(Debug) << "Created SIP endpoint factory";
 
 	    // Locate the Routing Service so that we can do routing. This is done here so it can be
@@ -575,6 +574,10 @@ void Component::createBackplaneServices()
             getBackplaneAdapter()->addWithUUID(mConfigurationService));
         lg(Debug) << "Created SIP Configuration Implementation";
 
+        // We have to wait until this point to add the replica proxy to
+        // the endpoint factory because prior to this point the replica hasn't
+        // been created.
+        mEndpointFactory->setReplicaProxy(getReplicaProxy());
     }
     catch(const Ice::Exception& e)
     {
diff --git a/src/SipConfiguration.cpp b/src/SipConfiguration.cpp
index ab28759..a505fff 100644
--- a/src/SipConfiguration.cpp
+++ b/src/SipConfiguration.cpp
@@ -1888,9 +1888,7 @@ void ConfigurationServiceImpl::setConfiguration(const AsteriskSCF::System::Confi
 
         void visitSipRegistrationGroup(const SipRegistrationGroupPtr& group)
         {
-            std::cout << "!!!!!!!!!!!!!! How's it going? !!!!!!!!!!!!" << std::endl;
             genericSet<SipRegistrationGroupPtr>(mImpl->getData(), group);
-            std::cout << "!!!!!!!!!!!!!! FINE? !!!!!!!!!!!!" << std::endl;
         }
         void visitIdentityGroup(const IdentityGroupPtr& group)
         {
diff --git a/src/SipEndpointFactory.cpp b/src/SipEndpointFactory.cpp
index 2be256d..4b8682c 100644
--- a/src/SipEndpointFactory.cpp
+++ b/src/SipEndpointFactory.cpp
@@ -20,6 +20,7 @@
 #include "SipEndpointFactory.h"
 
 using namespace AsteriskSCF::System::Logging;
+using namespace AsteriskSCF::System::Component::V1;
 
 namespace
 {
@@ -77,5 +78,10 @@ void SipEndpointFactory::generateRoutingDestinations(AsteriskSCF::Core::Routing:
     }
 }
 
+void SipEndpointFactory::setReplicaProxy(const ReplicaPrx& replica)
+{
+    mReplica = replica;
+}
+
 }; // end SipSessionManager
 }; // end AsteriskSCF
diff --git a/src/SipEndpointFactory.h b/src/SipEndpointFactory.h
index fbefdd2..7d792b5 100644
--- a/src/SipEndpointFactory.h
+++ b/src/SipEndpointFactory.h
@@ -43,14 +43,12 @@ public:
             const Ice::ObjectAdapterPtr& backplaneAdapter,
             const PJSipManagerPtr& manager,
             const AsteriskSCF::Core::Discovery::V1::ServiceLocatorPrx& serviceLocator,
-            const SipReplicationContextPtr& replicationContext,
-            const AsteriskSCF::System::Component::V1::ReplicaPrx& replica) :
+            const SipReplicationContextPtr& replicationContext) :
         mAdapter(adapter),
         mBackplaneAdapter(backplaneAdapter),
         mManager(manager),
         mServiceLocator(serviceLocator),
-        mReplicationContext(replicationContext),
-        mReplica(replica){};
+        mReplicationContext(replicationContext) { }
 
     SipEndpointPtr createEndpoint(std::string);
 
@@ -60,6 +58,8 @@ public:
 
     void generateRoutingDestinations(AsteriskSCF::Core::Routing::V1::RegExSeq&);
 
+    void setReplicaProxy(const AsteriskSCF::System::Component::V1::ReplicaPrx& replica);
+
 private:
     /**
      * A pointer to the object adapter that endpoints will be added to.

commit 030ca07ce06155cc17518f07099650ab7b862d4a
Author: Ken Hunt <ken.hunt at digium.com>
Date:   Tue Oct 4 12:07:29 2011 -0500

    Passing the component's ComponentService discovery category to the base Component (in constructor), namespace flattening was causing it to select the wrong category.

diff --git a/src/Component.cpp b/src/Component.cpp
index 1d63c04..37e6a7f 100644
--- a/src/Component.cpp
+++ b/src/Component.cpp
@@ -112,7 +112,7 @@ class Component : public AsteriskSCF::Component::Component
 {
 public:
     Component()
-        :  AsteriskSCF::Component::Component(lg, ComponentServiceDiscoveryCategory),
+        :  AsteriskSCF::Component::Component(lg, AsteriskSCF::SIP::V1::ComponentServiceDiscoveryCategory),
            mListeningToReplicator(false)
     {
     }

commit d686a273766e9ee293d9050c9dbfc3748b62eeaf
Merge: b634595 ee3a950
Author: Mark Michelson <mmichelson at digium.com>
Date:   Tue Oct 4 10:55:45 2011 -0500

    Merge branch 'master' into client-registration

diff --cc src/SipEndpoint.cpp
index 3371038,2e59ea0..822fbe7
--- a/src/SipEndpoint.cpp
+++ b/src/SipEndpoint.cpp
@@@ -327,75 -319,19 +338,86 @@@ void SipEndpoint::setSecureTransport(en
  void SipEndpoint::setDTMFMethod(AsteriskSCF::Configuration::SipSessionManager::V1::SipDTMFOption dtmf)
  {
      mImplPriv->mConfig.sessionConfig.dtmf = dtmf;
+     if (mImplPriv->mConfig.sessionConfig.dtmf ==
+             AsteriskSCF::Configuration::SipSessionManager::V1::RFC4733)
+     {
+         //For RFC 4733, we need to include information in the SDP about
+         //the format, so we need to add a new format to the endpoint's
+         //configured formats.
+ 
+         //XXX For now, we're just adding some hard-coded values. We should probably
+         //be a bit more flexible here in the face of changes or something.
+         addFormat("rfc4733", 8000, 0, Ice::StringSeq());
+     }
  }
  
 +class MatchRegistration
 +{
 +public:
 +    MatchRegistration(const std::string& aor)
 +        : mAOR(aor) { }
 +
 +    bool operator()(const SipClientRegistrationItemPtr& item)
 +    {
 +        return item->aor == mAOR;
 +    }
 +private:
 +    const std::string mAOR;
 +};
 +
 +void SipEndpoint::updateClientRegistrations(SipClientRegistrationItemSeq& items)
 +{
 +    lg(Debug) << "Updating client registrations for endpoint " << mImplPriv->mName;
 +
 +    //First step is to find registrations that exist for this endpoint but
 +    //that no longer appear in configuration. These must be KILLED!!!!!
 +    
 +    for (std::map<std::string, SipRegistrationClientPtr>::iterator iter = mImplPriv->mClientRegistrations.begin(); 
 +            iter != mImplPriv->mClientRegistrations.end(); )
 +    {
 +        SipClientRegistrationItemSeq::iterator toRemove = std::find_if(items.begin(), items.end(), MatchRegistration(iter->first));
 +        if (toRemove != items.end())
 +        {
 +            iter->second->destroy();
 +            mImplPriv->mClientRegistrations.erase(iter++);
 +        }
 +        else
 +        {
 +            ++iter;
 +        }
 +    }
 +
 +    //Next we go through the configured registrations and either update existing
 +    //client registrations or create new ones.
 +    for (SipClientRegistrationItemSeq::iterator item = items.begin();
 +            item != items.end(); ++item)
 +    {
 +        std::map<std::string, SipRegistrationClientPtr>::iterator iter =
 +            mImplPriv->mClientRegistrations.find((*item)->aor);
 +
 +        if (iter != mImplPriv->mClientRegistrations.end())
 +        {
 +            //Updating one that exists
 +            iter->second->updateRegistration(*item, mImplPriv->mManager->getEndpoint(), this);
 +        }
 +        else
 +        {
 +            //New one!
 +            mImplPriv->mClientRegistrations[(*item)->aor] =
 +                new SipRegistrationClient(
 +                        *item,
 +                        mImplPriv->mManager->getEndpoint(),
 +                        this,
 +                        mImplPriv->mManager->getClientRegistrationManager(),
 +                        mImplPriv->mReplicationContext,
 +                        mImplPriv->mBackplaneAdapter,
 +                        mImplPriv->mReplica);
 +
 +            mImplPriv->mClientRegistrations[(*item)->aor]->activate();
 +        }
 +    }
 +}
 +
  void SipEndpoint::setRTPOverIPv6(bool enabled)
  {
      mImplPriv->mConfig.sessionConfig.rtpOverIPv6 = enabled;

commit d1c51b7c05833b65bffdc3599253dd6690580d34
Author: Joshua Colp <jcolp at digium.com>
Date:   Mon Oct 3 20:04:29 2011 -0300

    Add T.38 UDPTL support.

diff --git a/config/Sip.config b/config/Sip.config
index 7946dba..e72b415 100644
--- a/config/Sip.config
+++ b/config/Sip.config
@@ -89,8 +89,32 @@ direction=both
 securetransport=none
 # Whether to use IPv6 for media transport or not
 rtpoveripv6=no
+# Whether to use IPv6 for UDPTL transport or not
+udptloveripv6=no
+
+#
+# Configure endpoint to create ICE enabled UDPTL streams. Disabled by default.
+#
+# udptloverice=false
+
+#
+# Configure endpoint to enable TURN support for ICE enabled UDPTL streams. ICE must be enabled
+# for this to have an effect. Disable by default.
+#
+# udptlwithturn=false
+
 # Allowable media formats for the endpoint. Each format is separated using , and follows the format
 # <name>/<sample rate>@<frame size>;<format specific parameters>
+#
+# If you would like to enable T.38 you can specify t38udptl here. This will enable T.38 with no overridden
+# datagram and no error correction scheme. To override the datagram add maxdatagram with a value in the format
+# specific parameters section. To enable error correction add errorcorrect with either fec, redundancy, or none
+# as the value.
+#
+# Example of T.38 with an overridden max datagram of 400: t38udptl;maxdatagram=400
+# Example of T.38 with fec error correction: t38udptl;errorcorrect=fec
+# Example of T.38 with overridden max datagram and fec error correction: t38udptl;maxdatagram=400&errorcorrect=fec
+#
 formats=ulaw/8000,alaw/8000
 
 # Whether media should be allowed to flow directly between endpoints or not
diff --git a/config/SipConfigurator.py b/config/SipConfigurator.py
index 5505f2a..f6c09b7 100755
--- a/config/SipConfigurator.py
+++ b/config/SipConfigurator.py
@@ -206,6 +206,11 @@ class SipSectionVisitors(Configurator.SectionVisitors):
         item = AsteriskSCF.Configuration.SipSessionManager.V1.DirectMediaItem()
         mapper.map('directmedia', item, 'enabled', 'directmedia', config.getboolean, None)
 
+        item = AsteriskSCF.Configuration.SipSessionManager.V1.SipUDPTLMediaServiceItem()
+        mapper.map('udptloveripv6', item, 'requireIPv6', 'udptlmediaservice', config.getboolean, None)
+        mapper.map('udptloverice', item, 'enableICE', 'udptlmediaservice', config.getboolean, None)
+        mapper.map('udptlwithturn', item, 'enableTURN', 'udptlmediaservice', config.getboolean, None)
+
         item = AsteriskSCF.Configuration.SipSessionManager.V1.SipCryptoCertificateItem()
         mapper.map('certificateauthorityfile', item, 'certificateAuthority', 'cryptocert', config.get, None)
         mapper.map('certificatefile', item, 'certificate', 'cryptocert', config.get, None)
@@ -263,21 +268,43 @@ class SipSectionVisitors(Configurator.SectionVisitors):
             formats = config.get(section, 'formats')
             configuredFormats = formats.split(',')
             for format in configuredFormats:
-                name, found, rest = format.partition('/')
-                sampleRate, found, rest = rest.partition('@')
-                frameSize, found, formatSpecific = rest.partition(';')
-
                 item = AsteriskSCF.Configuration.SipSessionManager.V1.SipMediaFormatItem()
-                item.name = name
-                if sampleRate:
-                    item.sampleRate = sampleRate
-                if frameSize:
-                    item.frameSize = frameSize
+
+                front, found, rest = format.partition('/')
+                if found:
+                    item.name = front
+                else:
+                    rest = front
+
+                front, found, rest = rest.partition('@')
+                if found:
+                    if item.name:
+                        item.sampleRate = front
+                    else:
+                        item.name = front
+                else:
+                    rest = front
+
+                front, found, rest = rest.partition(';')
+                if found:
+                    if item.name:
+                        item.frameSize = front
+                    else:
+                        item.name = front
+                else:
+                    rest = front
+
                 item.formatSpecific = [ ]
-                if formatSpecific:
-                    item.formatSpecific.append(formatSpecific)
 
-                group.configurationItems[format] = item
+                if not item.name:
+                    item.name = format
+
+                if item.name:
+                    while rest:
+                        front, found, rest = rest.partition('&')
+                        item.formatSpecific.append(front)
+
+                    group.configurationItems[format] = item
         except:
             print 'No configured formats for endpoint ' + section
 
diff --git a/slice/AsteriskSCF/Configuration/SipSessionManager/SipConfigurationIf.ice b/slice/AsteriskSCF/Configuration/SipSessionManager/SipConfigurationIf.ice
index c22c91b..3641291 100644
--- a/slice/AsteriskSCF/Configuration/SipSessionManager/SipConfigurationIf.ice
+++ b/slice/AsteriskSCF/Configuration/SipSessionManager/SipConfigurationIf.ice
@@ -334,6 +334,32 @@ class SipRTPMediaServiceItem extends SipConfigurationItem
 };
 
 /**
+ * UDPTL Media service configuration item
+ */
+class SipUDPTLMediaServiceItem extends SipConfigurationItem
+{
+    /**
+     * Name of the UDPTL media service to use
+     */
+    string mediaServiceName;
+
+    /**
+     * Whether to choose an IPv6 UDPTL media service or not
+     */
+    bool requireIPv6 = false;
+
+    /**
+     * Boolean for whether ICE is enabled
+     */
+    bool enableICE = false;
+
+    /**
+     * Boolean for whether TURN is enabled
+     */
+    bool enableTURN = false;
+};
+
+/**
  * Signaling NAT configuration item
  */
 class SipSignalingNATItem extends SipConfigurationItem
diff --git a/slice/AsteriskSCF/Replication/SipSessionManager/SipStateReplicationIf.ice b/slice/AsteriskSCF/Replication/SipSessionManager/SipStateReplicationIf.ice
index f982668..f9eab87 100644
--- a/slice/AsteriskSCF/Replication/SipSessionManager/SipStateReplicationIf.ice
+++ b/slice/AsteriskSCF/Replication/SipSessionManager/SipStateReplicationIf.ice
@@ -19,6 +19,7 @@
 #include <Ice/Identity.ice>
 #include <AsteriskSCF/Media/MediaIf.ice>
 #include <AsteriskSCF/Media/RTP/MediaRTPIf.ice>
+#include <AsteriskSCF/Media/UDPTL/MediaUDPTLIf.ice>
 #include <AsteriskSCF/SessionCommunications/SessionCommunicationsIf.ice>
 #include <AsteriskSCF/Core/Discovery/ServiceLocatorIf.ice>
 #include <AsteriskSCF/System/Component/ConfigurationIf.ice>
@@ -140,6 +141,7 @@ module V1
    };
 
    dictionary<string, AsteriskSCF::Media::RTP::V1::RTPSession*> RTPMediaSessionDict;
+   sequence<AsteriskSCF::Media::UDPTL::V1::UDPTLSession*> UDPTLMediaSessionSeq;
 
    class SipSessionStateItem extends SipStateItem
    {
@@ -153,6 +155,7 @@ module V1
       AsteriskSCF::Media::V1::StreamSinkSeq sinks;
       AsteriskSCF::Media::V1::StreamInformationDict streams;
       RTPMediaSessionDict rtpMediaSessions;
+      UDPTLMediaSessionSeq udptlMediaSessions;
       AsteriskSCF::SessionCommunications::V1::SessionListenerSeq listeners;
       AsteriskSCF::SessionCommunications::V1::Bridge *bridge;
       AsteriskSCF::SessionCommunications::V1::SessionCookieDict cookies;
diff --git a/src/NATOptions.h b/src/NATOptions.h
index 2319c50..5c71700 100644
--- a/src/NATOptions.h
+++ b/src/NATOptions.h
@@ -27,9 +27,11 @@ struct NATEndpointOptions
     bool enableICE;
     bool enableTURN;
     bool enableSIPSTUN;
+    bool enableUDPTLICE;
+    bool enableUDPTLTURN;
 
-    NATEndpointOptions(bool ice, bool turn, bool sip) :
-        enableICE(ice), enableTURN(turn), enableSIPSTUN(sip) 
+    NATEndpointOptions(bool ice, bool turn, bool sip, bool udptlice, bool udptlturn) :
+        enableICE(ice), enableTURN(turn), enableSIPSTUN(sip), enableUDPTLICE(udptlice), enableUDPTLTURN(udptlturn)
     {
     }
 };
diff --git a/src/PJSipSessionModule.cpp b/src/PJSipSessionModule.cpp
index 3b97fd4..9504d47 100644
--- a/src/PJSipSessionModule.cpp
+++ b/src/PJSipSessionModule.cpp
@@ -108,6 +108,7 @@ void PJSipSessionModInfo::updateSessionState(pjsip_inv_session *inv_session)
         mSessionState->sources = mSession->getMediaSources();
         mSessionState->sinks = mSession->getMediaSinks();
         mSessionState->rtpMediaSessions = mSession->getRTPMediaSessions();
+        mSessionState->udptlMediaSessions = mSession->getUDPTLMediaSessions();
         mSessionState->listeners = mSession->getListeners();
 	    mSessionState->streams = mSession->getStreams();
         try
@@ -1508,14 +1509,8 @@ private:
     ServiceLocatorPrx mServiceLocator;
 };
 
-void PJSipSessionModule::invOnMediaUpdate(pjsip_inv_session *inv, pj_status_t status)
+void PJSipSessionModule::invOnMediaUpdate(pjsip_inv_session *inv, pj_status_t)
 {
-    if (status != PJ_SUCCESS)
-    {
-        // We have nothing, zip, nada, kablamo, in common.
-        return;
-    }
-
     lg(Debug) << "Queuing HandleMediaUpdate";
     enqueueSessionWork(new HandleMediaUpdate(inv, mModule.id, mServiceLocator), inv);
 }
diff --git a/src/SipConfiguration.cpp b/src/SipConfiguration.cpp
index f4c07ef..cd00465 100644
--- a/src/SipConfiguration.cpp
+++ b/src/SipConfiguration.cpp
@@ -310,6 +310,11 @@ class EndpointConfigHelper : public boost::enable_shared_from_this<EndpointConfi
 	    mUpdates.push_back(boost::bind(&EndpointConfigHelper::updateMediaService, mConfig, service));
 	};
 
+        void visitSipUDPTLMediaServiceItem(const SipUDPTLMediaServiceItemPtr& service)
+        {
+            mUpdates.push_back(boost::bind(&EndpointConfigHelper::updateUDPTLMediaService, mConfig, service));
+        };
+
 	void visitSipEndpointTransportItem(const SipEndpointTransportItemPtr& transport)
 	{
 	    mUpdates.push_back(boost::bind(&EndpointConfigHelper::updateTransport, mConfig, transport));
@@ -460,6 +465,13 @@ public:
 	mEndpoint->setRTPOverIPv6(service->requireIPv6);
     }
 
+    void updateUDPTLMediaService(const SipUDPTLMediaServiceItemPtr& service)
+    {
+        mEndpoint->setUDPTLOverIPv6(service->requireIPv6);
+        mEndpoint->enableUDPTLICE(service->enableICE);
+        mEndpoint->enableUDPTLTURN(service->enableTURN);
+    }
+
     void updateTransport(const SipEndpointTransportItemPtr& transport)
     {
 	mEndpoint->setSecureTransport(translateCallDirection(transport->secureTransport));
diff --git a/src/SipEndpoint.cpp b/src/SipEndpoint.cpp
index d017a06..f03e3ac 100644
--- a/src/SipEndpoint.cpp
+++ b/src/SipEndpoint.cpp
@@ -337,12 +337,26 @@ void SipEndpoint::setRTPOverIPv6(bool enabled)
     mImplPriv->mConfig.sessionConfig.rtpOverIPv6 = enabled;
 }
 
-
 void SipEndpoint::setDirectMedia(bool enabled)
 {
     mImplPriv->mConfig.sessionConfig.directMedia = enabled;
 }
 
+void SipEndpoint::setUDPTLOverIPv6(bool enabled)
+{
+    mImplPriv->mConfig.sessionConfig.udptlOverIPv6 = enabled;
+}
+
+void SipEndpoint::enableUDPTLICE(bool enabled)
+{
+    mImplPriv->mConfig.sessionConfig.udptlOverICE = enabled;
+}
+
+void SipEndpoint::enableUDPTLTURN(bool enabled)
+{
+    mImplPriv->mConfig.sessionConfig.udptlWithTURN = enabled;
+}
+
 void SipEndpoint::setMediaNATOptions(bool useICE, bool useTURN)
 {
     mImplPriv->mConfig.sessionConfig.rtpOverICE = useICE;
@@ -446,8 +460,10 @@ AsteriskSCF::SessionCommunications::V1::SessionPrx SipEndpoint::createSession(
 	    true, 
 	    mImplPriv->mConfig, 
             NATEndpointOptions(mImplPriv->mConfig.sessionConfig.rtpOverICE, 
-                 mImplPriv->mConfig.sessionConfig.rtpICEIncludeTURN,
-                 mImplPriv->mConfig.transportConfig.enableNAT));
+                               mImplPriv->mConfig.sessionConfig.rtpICEIncludeTURN,
+                               mImplPriv->mConfig.transportConfig.enableNAT,
+                               mImplPriv->mConfig.sessionConfig.udptlOverICE,
+                               mImplPriv->mConfig.sessionConfig.udptlWithTURN));
 
     mImplPriv->mSessions.push_back(session);
 
@@ -475,7 +491,9 @@ AsteriskSCF::SipSessionManager::SipSessionPtr SipEndpoint::createSession(const s
 	     mImplPriv->mConfig, 
              NATEndpointOptions(mImplPriv->mConfig.sessionConfig.rtpOverICE, 
                                 mImplPriv->mConfig.sessionConfig.rtpICEIncludeTURN,
-                                mImplPriv->mConfig.transportConfig.enableNAT)
+                                mImplPriv->mConfig.transportConfig.enableNAT,
+                                mImplPriv->mConfig.sessionConfig.udptlOverICE,
+                                mImplPriv->mConfig.sessionConfig.udptlWithTURN)
 	     );
 
     mImplPriv->mSessions.push_back(session);
@@ -493,28 +511,32 @@ SipSessionPtr SipEndpoint::createSession
 		const Ice::Identity& controllerid,
                 const Ice::Identity& mediaid,
                 const AsteriskSCF::Replication::SipSessionManager::V1::RTPMediaSessionDict& mediasessions,
+                const AsteriskSCF::Replication::SipSessionManager::V1::UDPTLMediaSessionSeq& udptlMediaSessions,
                 const AsteriskSCF::Media::V1::StreamSourceSeq& sources,
                 const AsteriskSCF::Media::V1::StreamSinkSeq& sinks)
 {
     SipSessionPtr session = SipSession::create
-	    (mImplPriv->mAdapter, 
-	     this, 
-	     destination, 
-	     sessionid, 
-             controllerid, 
-	     mediaid, 
-	     mediasessions, 
-	     sources, 
-	     sinks, 
-	     mImplPriv->mManager, 
-             mImplPriv->mServiceLocator, 
-	     mImplPriv->mReplicationContext, 
-	     0,
-	     false, 
-	     mImplPriv->mConfig,
-             NATEndpointOptions(mImplPriv->mConfig.sessionConfig.rtpOverICE, 
-                                mImplPriv->mConfig.sessionConfig.rtpICEIncludeTURN,
-                                mImplPriv->mConfig.transportConfig.enableNAT));
+        (mImplPriv->mAdapter, 
+         this, 
+         destination, 
+         sessionid, 
+         controllerid, 
+         mediaid, 
+         mediasessions, 
+         udptlMediaSessions,
+         sources, 
+         sinks, 
+         mImplPriv->mManager, 
+         mImplPriv->mServiceLocator, 
+         mImplPriv->mReplicationContext, 
+         0,
+         false, 
+         mImplPriv->mConfig,
+         NATEndpointOptions(mImplPriv->mConfig.sessionConfig.rtpOverICE, 
+                            mImplPriv->mConfig.sessionConfig.rtpICEIncludeTURN,
+                            mImplPriv->mConfig.transportConfig.enableNAT,
+                            mImplPriv->mConfig.sessionConfig.udptlOverICE,
+                            mImplPriv->mConfig.sessionConfig.udptlWithTURN));
 
     mImplPriv->mSessions.push_back(session);
     return session;
@@ -767,6 +789,36 @@ SDPDescriptorPtr SipEndpoint::getDescriptor(const FormatPtr& format)
     return 0;
 }
 
+SDPDescriptorPtr SipEndpoint::getInterpretedDescriptor(const FormatPtr& format)
+{
+    for (std::vector<ConfiguredFormatPtr>::const_iterator configuredFormat = mImplPriv->mFormats.begin();
+         configuredFormat != mImplPriv->mFormats.end();
+         ++configuredFormat)
+    {
+        if ((*configuredFormat)->getFormat()->name == format->name)
+        {
+            return (*configuredFormat)->getDescriptorService()->getDescriptor(format);
+        }
+    }
+
+    return 0;
+}
+
+FormatPtr SipEndpoint::getFormat(const FormatPtr& format)
+{
+    for (std::vector<ConfiguredFormatPtr>::const_iterator configuredFormat = mImplPriv->mFormats.begin();
+         configuredFormat != mImplPriv->mFormats.end();
+         ++configuredFormat)
+    {
+        if ((*configuredFormat)->getFormat()->name == format->name)
+        {
+            return (*configuredFormat)->getFormat();
+        }
+    }
+
+    return 0;
+}
+
 StreamInformationDict SipEndpoint::getStreamTopology()
 {
     StreamInformationDict topology;
@@ -776,6 +828,12 @@ StreamInformationDict SipEndpoint::getStreamTopology()
          configuredFormat != mImplPriv->mFormats.end();
          ++configuredFormat)
     {
+        // Initial stream topology does not support T.38 streams
+        if ((*configuredFormat)->getDescriptor()->type == "image")
+        {
+            continue;
+        }
+
         // See if a stream already exists for this type
         StreamInformationDict::iterator stream = topology.find((*configuredFormat)->getDescriptor()->type);
 
diff --git a/src/SipEndpoint.h b/src/SipEndpoint.h
index 0a07081..037b1b3 100644
--- a/src/SipEndpoint.h
+++ b/src/SipEndpoint.h
@@ -161,6 +161,12 @@ public:
     bool rtpOverIPv6;
     // Whether we are allowing direct media or not
     bool directMedia;
+    // Whether we are using IPv6 for UDPTL transport or not.
+    bool udptlOverIPv6;
+    // Whether ICE is enabled for UDPTL.
+    bool udptlOverICE;
+    // Whether TURN is enabled for UDPTL.
+    bool udptlWithTURN;
     // The method by which we will transmit
     // DTMF to an endpoint
     AsteriskSCF::Configuration::SipSessionManager::V1::SipDTMFOption dtmf;
@@ -321,6 +327,7 @@ public:
     AsteriskSCF::SipSessionManager::SipSessionPtr createSession(const std::string&);
     AsteriskSCF::SipSessionManager::SipSessionPtr createSession(const std::string&, const Ice::Identity&, const Ice::Identity&,
                                                                 const Ice::Identity&, const AsteriskSCF::Replication::SipSessionManager::V1::RTPMediaSessionDict&,
+                                                                const AsteriskSCF::Replication::SipSessionManager::V1::UDPTLMediaSessionSeq&,
                                                                 const AsteriskSCF::Media::V1::StreamSourceSeq&, const AsteriskSCF::Media::V1::StreamSinkSeq&);
 
     void removeSession(const AsteriskSCF::SessionCommunications::V1::SessionPtr&);
@@ -336,6 +343,9 @@ public:
     void setSecureTransport(enum Direction);
     void setRTPOverIPv6(bool);
     void setDirectMedia(bool);
+    void setUDPTLOverIPv6(bool);
+    void enableUDPTLICE(bool);
+    void enableUDPTLTURN(bool);
     void addFormat(const std::string& name, int sampleRate, int frameSize, const Ice::StringSeq& formatSpecific);
 
     /**
@@ -345,11 +355,21 @@ public:
         const AsteriskSCF::Media::SDP::V1::SDPDescriptorPtr&);
     
     /**
-     * API call which returns a descriptor given a media format.
+     * API call which returns a locally cached descriptor given a media format.
      */
     AsteriskSCF::Media::SDP::V1::SDPDescriptorPtr getDescriptor(const AsteriskSCF::Media::V1::FormatPtr&);
 
     /**
+     * API call which returns a descriptor given a media format.
+     */
+    AsteriskSCF::Media::SDP::V1::SDPDescriptorPtr getInterpretedDescriptor(const AsteriskSCF::Media::V1::FormatPtr&);
+
+    /**
+     * API call which returns the local format given a media format.
+     */
+    AsteriskSCF::Media::V1::FormatPtr getFormat(const AsteriskSCF::Media::V1::FormatPtr&);
+
+    /**
      * API call which returns the stream topology to be used for an SDP offer.
      */
 
diff --git a/src/SipSession.cpp b/src/SipSession.cpp
index dce14ab..3182731 100755
--- a/src/SipSession.cpp
+++ b/src/SipSession.cpp
@@ -40,6 +40,9 @@
 #include <AsteriskSCF/Media/RTP/MediaRTPIf.h>
 #include <AsteriskSCF/Media/SDP/MediaSDPIf.h>
 #include <AsteriskSCF/Media/RTP/MediaRTCPIf.h>
+#include <AsteriskSCF/Media/UDPTL/MediaUDPTLIf.h>
+#include <AsteriskSCF/Media/Formats/T38UdptlFormat.h>
+#include <AsteriskSCF/Media/NetworkIf.h>
 #include <AsteriskSCF/SessionCookies/SipSessionManager/SipSessionCookiesIf.h>
 #include <AsteriskSCF/Collections/HandleSet.h>
 #include "NATOptions.h"
@@ -52,6 +55,9 @@ using namespace AsteriskSCF::Media::RTP::V1;
 using namespace AsteriskSCF::Media::V1;
 using namespace AsteriskSCF::Media;
 using namespace AsteriskSCF::Media::SDP::V1;
+using namespace AsteriskSCF::Media::UDPTL::V1;
+using namespace AsteriskSCF::Media::Formats::T38Udptl::V1;
+using namespace AsteriskSCF::Network::V1;
 using namespace AsteriskSCF::System::V1;
 using namespace AsteriskSCF::Helpers;
 using namespace std;
@@ -284,6 +290,11 @@ public:
     RTPMediaSessionDict mRTPSessions;
 
     /**
+     * A vector of UDPTL media sessions belonging to this session.
+     */
+    UDPTLMediaSessionSeq mUDPTLSessions;
+
+    /**
      * A vector of media sources associated with this endpoint.
      */
     AsteriskSCF::Media::V1::StreamSourceSeq mSources;
@@ -1276,37 +1287,39 @@ SipSessionPtr SipSession::create(const Ice::ObjectAdapterPtr& adapter,
  * Factory used by a standby component to create replicas. 
  */
 SipSessionPtr SipSession::create(const Ice::ObjectAdapterPtr& adapter, 
-                       const SipEndpointPtr& endpoint,
-                       const std::string& destination, 
-                       const Ice::Identity& sessionid,
-                       const Ice::Identity& controllerid,
-                       const Ice::Identity& mediaid, 
-                       const AsteriskSCF::Replication::SipSessionManager::V1::RTPMediaSessionDict& mediasessions,
-                       const AsteriskSCF::Media::V1::StreamSourceSeq& sources, 
-                       const AsteriskSCF::Media::V1::StreamSinkSeq& sinks,
-                       const PJSipManagerPtr& manager, 
-                       const AsteriskSCF::Core::Discovery::V1::ServiceLocatorPrx& serviceLocator,
-                       const SipReplicationContextPtr& replicationContext, 
-                       const AsteriskSCF::SessionCommunications::ExtensionPoints::V1::SessionCreationHookPrx& oneShotHook,
-                       bool isUAC, 
-                       const SipEndpointConfig &config,
-                       const NATEndpointOptions& natOptions)
+                                 const SipEndpointPtr& endpoint,
+                                 const std::string& destination, 
+                                 const Ice::Identity& sessionid,
+                                 const Ice::Identity& controllerid,
+                                 const Ice::Identity& mediaid, 
+                                 const AsteriskSCF::Replication::SipSessionManager::V1::RTPMediaSessionDict& mediasessions,
+                                 const AsteriskSCF::Replication::SipSessionManager::V1::UDPTLMediaSessionSeq& udptlMediaSessions,
+                                 const AsteriskSCF::Media::V1::StreamSourceSeq& sources, 
+                                 const AsteriskSCF::Media::V1::StreamSinkSeq& sinks,
+                                 const PJSipManagerPtr& manager, 
+                                 const AsteriskSCF::Core::Discovery::V1::ServiceLocatorPrx& serviceLocator,
+                                 const SipReplicationContextPtr& replicationContext, 
+                                 const AsteriskSCF::SessionCommunications::ExtensionPoints::V1::SessionCreationHookPrx& oneShotHook,
+                                 bool isUAC, 
+                                 const SipEndpointConfig &config,
+                                 const NATEndpointOptions& natOptions)
 {
     SipSessionPtr newSession = new SipSession(adapter, 
-                       endpoint,
-                       destination, 
-                       sessionid,
-                       controllerid,
-                       mediaid, 
-                       mediasessions,
-                       sources, 
-                       sinks,
-                       manager, 
-                       serviceLocator,
-                       replicationContext, 
-                       isUAC, 
-                       config,
-                       natOptions);
+                                              endpoint,
+                                              destination, 
+                                              sessionid,
+                                              controllerid,
+                                              mediaid, 
+                                              mediasessions,
+                                              udptlMediaSessions,
+                                              sources, 
+                                              sinks,
+                                              manager, 
+                                              serviceLocator,
+                                              replicationContext, 
+                                              isUAC, 
+                                              config,
+                                              natOptions);
 
     AsteriskSCF::SessionCommunications::ExtensionPoints::V1::SessionCreationHookSeq hooks =
         newSession->mImplPriv->mManager->getSessionModule()->getSessionCreationHooks();
@@ -1376,6 +1389,7 @@ SipSession::SipSession(const Ice::ObjectAdapterPtr& adapter,
                        const Ice::Identity& controllerid,
                        const Ice::Identity& mediaid,
                        const AsteriskSCF::Replication::SipSessionManager::V1::RTPMediaSessionDict& mediasessions,
+                       const AsteriskSCF::Replication::SipSessionManager::V1::UDPTLMediaSessionSeq& udptlMediaSessions,
                        const AsteriskSCF::Media::V1::StreamSourceSeq& sources,
                        const AsteriskSCF::Media::V1::StreamSinkSeq& sinks,
                        const PJSipManagerPtr& manager,
@@ -1401,6 +1415,7 @@ SipSession::SipSession(const Ice::ObjectAdapterPtr& adapter,
     adapter->addFacet(directMedia, sessionid, directMediaConnectionFacet);
 
     mImplPriv->mRTPSessions = mediasessions;
+    mImplPriv->mUDPTLSessions = udptlMediaSessions;
     mImplPriv->mSources = sources;
     mImplPriv->mSinks = sinks;
 
@@ -2434,6 +2449,19 @@ public:
                     lg(Error) << "Exception caught while trying to release a media session\n" << ex.what();
                 }
            }
+
+            for (UDPTLMediaSessionSeq::const_iterator i = mSessionPriv->mUDPTLSessions.begin();
+                 i != mSessionPriv->mUDPTLSessions.end(); ++i)
+            {
+                try
+                {
+                    (*i)->release();
+                }
+                catch (const Ice::Exception& ex)
+                {
+                    lg(Error) << "Exception caught while trying to release a udptl session\n" << ex.what();
+                }
+            }
         }
         mSessionPriv->mEndpoint->removeSession(mSession);
         return Complete;
@@ -2710,111 +2738,224 @@ pjmedia_sdp_session *SipSession::createSDPOffer(const AsteriskSCF::Media::V1::St
         // Update the stream with the actual formats
         stream->second->formats = formats;
 
-        RTPServiceLocatorParamsPtr params = new RTPServiceLocatorParams();
-        params->category = "rtp";
-        params->formats = stream->second->formats;
-        params->ipv6 = mImplPriv->mEndpoint->getConfig().sessionConfig.rtpOverIPv6;
+        // Determine what media this stream is carrying
+        AudioFormatPtr audio;
+        VideoFormatPtr video;
+	T38UdptlFormatPtr t38;
 
-        // Try to find a factory for RTP sessions matching what we need
-        RTPMediaServicePrx factory = RTPMediaServicePrx::uncheckedCast(mImplPriv->mServiceLocator->locate(params));
-
-        // If none exist we can't provide the stream
-        if (factory == 0)
+        // If this stream contains an audio or video format the stream is transported using RTP
+        if ((audio = AudioFormatPtr::dynamicCast(formats.front())) || (video = VideoFormatPtr::dynamicCast(formats.front())))
         {
-            continue;
-        }
+            RTPServiceLocatorParamsPtr params = new RTPServiceLocatorParams();
+            params->category = "rtp";
+            params->formats = stream->second->formats;
+            params->ipv6 = mImplPriv->mEndpoint->getConfig().sessionConfig.rtpOverIPv6;
+
+            // Try to find a factory for RTP sessions matching what we need
+            RTPMediaServicePrx factory = RTPMediaServicePrx::uncheckedCast(mImplPriv->mServiceLocator->locate(params));
+
+            if (factory == 0)
+            {
+                continue;
+            }
 
-        // Allocate a new RTP session to carry the media formats we have in common
+            // Allocate a new RTP session to carry the media formats we have in common
         
-        RTPOptionsPtr options(new RTPOptions());
-        RTPAllocationOutputsPtr outputs;
+            RTPOptionsPtr options(new RTPOptions());
+            RTPAllocationOutputsPtr outputs;
 
-        SipEndpointConfig& config = mImplPriv->mEndpoint->getConfig();
-        if (config.sessionConfig.dtmf == AsteriskSCF::Configuration::SipSessionManager::V1::RFC4733)
-        {
-            options->handleTelephonyEvents = true;
-        }
+            SipEndpointConfig& config = mImplPriv->mEndpoint->getConfig();
+            if (config.sessionConfig.dtmf == AsteriskSCF::Configuration::SipSessionManager::V1::RFC4733)
+            {
+                options->handleTelephonyEvents = true;
+            }
 
-        RTPSessionPrx session = factory->allocate(params, options, outputs);
+            RTPSessionPrx session = factory->allocate(params, options, outputs);
 
-        // Double check to make sure they actually gave us a sesson back... they could have had a problem
-        if (session == 0)
-        {
-            continue;
-        }
+            // Double check to make sure they actually gave us a sesson back... they could have had a problem
+            if (session == 0)
+            {
+                continue;
+            }
 
-        if (outputs)
-        {
-            mImplPriv->mExternalEventSources = outputs->eventSources;
-            mImplPriv->mExternalEventSinks = outputs->eventSinks;
-        }
+            if (outputs)
+            {
+                mImplPriv->mExternalEventSources = outputs->eventSources;
+                mImplPriv->mExternalEventSinks = outputs->eventSinks;
+            }
 
-        // RTP sessions should only provide a single sink, so grab it and update the connection details with that
-        // of the remote party
-        StreamSinkRTPPrx sink = StreamSinkRTPPrx::uncheckedCast(session->getSinks().front());
-        mImplPriv->mSinks.push_back(sink);
-    stream->second->sinks.push_back(sink);
+            // RTP sessions should only provide a single sink, so grab it and update the connection details with that
+            // of the remote party
+            StreamSinkRTPPrx sink = StreamSinkRTPPrx::uncheckedCast(session->getSinks().front());
+            mImplPriv->mSinks.push_back(sink);
+            stream->second->sinks.push_back(sink);
 
-        // Ditto goes for source
-        StreamSourceRTPPrx source = StreamSourceRTPPrx::uncheckedCast(session->getSources().front());
-        mImplPriv->mSources.push_back(source);
-    stream->second->sources.push_back(source);
+            // Ditto goes for source
+            StreamSourceRTPPrx source = StreamSourceRTPPrx::uncheckedCast(session->getSources().front());
+            mImplPriv->mSources.push_back(source);
+            stream->second->sources.push_back(source);
 
-        // Update the SIP session with some RTP session details
-        mImplPriv->mRTPSessions.insert(make_pair(boost::lexical_cast<std::string>(mImplPriv->mSDP->media_count), session));
+            // Update the SIP session with some RTP session details
+            mImplPriv->mRTPSessions.insert(make_pair(boost::lexical_cast<std::string>(mImplPriv->mSDP->media_count), session));
+         
+	    // Add the stream to the SDP
+	    pjmedia_sdp_media *media = allocate_from_pool<pjmedia_sdp_media>(mImplPriv->mDialog->pool);
 
-        // Add the stream to the SDP
-        pjmedia_sdp_media *media = allocate_from_pool<pjmedia_sdp_media>(mImplPriv->mDialog->pool);
+	    // The media count is purposely not incremented here since it is done when the stream is added to the sequence
+	    // of streams
+	    mImplPriv->mSDP->media[mImplPriv->mSDP->media_count] = media;
+	    pj_strdup2(mImplPriv->mDialog->pool, &media->desc.media, mImplPriv->mEndpoint->getDescriptor(
+                           stream->second->formats.front())->type.c_str());
 
-        // The media count is purposely not incremented here since it is done when the stream is added to the sequence
-        // of streams
-        mImplPriv->mSDP->media[mImplPriv->mSDP->media_count] = media;
-        pj_strdup2(mImplPriv->mDialog->pool, &media->desc.media, mImplPriv->mEndpoint->getDescriptor(
-                       stream->second->formats.front())->type.c_str());
+	    pj_strdup2(mImplPriv->mDialog->pool, &media->desc.transport, "RTP/AVP");
 
-        // TODO: This should not be hardcoded
-        pj_strdup2(mImplPriv->mDialog->pool, &media->desc.transport, "RTP/AVP");
+            // Add connection level details
+            media->conn = allocate_from_pool<pjmedia_sdp_conn>(mImplPriv->mDialog->pool);
+            pj_strdup2(mImplPriv->mDialog->pool, &media->conn->net_type, "IN");
 
-        // Add connection level details
-        media->conn = allocate_from_pool<pjmedia_sdp_conn>(mImplPriv->mDialog->pool);
-        pj_strdup2(mImplPriv->mDialog->pool, &media->conn->net_type, "IN");
+            if (params->ipv6 == true)
+            {
+                pj_strdup2(mImplPriv->mDialog->pool, &media->conn->addr_type, "IP6");
+            }
+            else
+            {
+                pj_strdup2(mImplPriv->mDialog->pool, &media->conn->addr_type, "IP4");
+            }
 
-        if (params->ipv6 == true)
-        {
-            pj_strdup2(mImplPriv->mDialog->pool, &media->conn->addr_type, "IP6");
+            pj_strdup2(mImplPriv->mDialog->pool, &media->conn->addr, source->getLocalAddress().c_str());
+
+            // If session level connection information has not yet been set then set it to us
+            if (!mImplPriv->mSDP->conn)
+            {
+                mImplPriv->mSDP->conn = media->conn;
+            }
+
+            media->desc.port = (pj_uint16_t) source->getLocalPort();
+            media->desc.port_count = 1;
+
+            RTCP::V1::RTCPSessionPrx rtcpSession;
+            if ((rtcpSession = RTCP::V1::RTCPSessionPrx::checkedCast(session, RTCP::V1::SessionFacet)))
+            {
+                pjmedia_sdp_attr *attr = allocate_from_pool<pjmedia_sdp_attr>(mImplPriv->mDialog->pool);
+                pj_strdup2(mImplPriv->mDialog->pool, &attr->name, "rtcp");
+                pj_strdup2(mImplPriv->mDialog->pool, &attr->value, boost::lexical_cast<std::string>(rtcpSession->getLocalPort()).c_str());
+                media->attr[media->attr_count++] = attr;
+            }
+
+            PayloadMap payloads;
+
+            // Add all of the formats to the SDP
+            addFormatstoSDP(stream->second->formats, media, payloads);
+
+            // Push the payload mapping to the RTP session so it'll correctly map things
+            session->associatePayloads(payloads);
         }
-        else
+        else if ((t38 = T38UdptlFormatPtr::dynamicCast(formats.front())))
         {
-            pj_strdup2(mImplPriv->mDialog->pool, &media->conn->addr_type, "IP4");
-        }
+            UDPTLServiceLocatorParamsPtr params;
 
-        pj_strdup2(mImplPriv->mDialog->pool, &media->conn->addr, source->getLocalAddress().c_str());
+            if (mImplPriv->mNatOptions.enableUDPTLICE)
+            {
+                AsteriskSCF::Media::UDPTL::V1::UDPTLOverICEServiceLocatorParamsPtr iceParams =
+                    new AsteriskSCF::Media::UDPTL::V1::UDPTLOverICEServiceLocatorParams;
+                params = iceParams;
+                iceParams->enableICE = true;
+                iceParams->enableTURN = mImplPriv->mNatOptions.enableUDPTLTURN;
+            }
+            else
+            {
+                params = new AsteriskSCF::Media::UDPTL::V1::UDPTLServiceLocatorParams;
+            }
 
-        // If session level connection information has not yet been set then set it to us
-        if (!mImplPriv->mSDP->conn)
-        {
-            mImplPriv->mSDP->conn = media->conn;
-        }
+            params->category = "udptl";
+            params->ipv6 = mImplPriv->mEndpoint->getConfig().sessionConfig.udptlOverIPv6;
 
-        media->desc.port = (pj_uint16_t) source->getLocalPort();
-        media->desc.port_count = 1;
+            UDPTLMediaServicePrx factory = UDPTLMediaServicePrx::uncheckedCast(mImplPriv->mServiceLocator->locate(params));
+            if (factory == 0)
+            {
+                continue;
+            }
 
-        RTCP::V1::RTCPSessionPrx rtcpSession;
-        if ((rtcpSession = RTCP::V1::RTCPSessionPrx::checkedCast(session, RTCP::V1::SessionFacet)))
-        {
-            pjmedia_sdp_attr *attr = allocate_from_pool<pjmedia_sdp_attr>(mImplPriv->mDialog->pool);
-            pj_strdup2(mImplPriv->mDialog->pool, &attr->name, "rtcp");
-            pj_strdup2(mImplPriv->mDialog->pool, &attr->value, boost::lexical_cast<std::string>(rtcpSession->getLocalPort()).c_str());
-            media->attr[media->attr_count++] = attr;
-        }
+            UDPTLSessionPrx session = factory->allocate(params);
+            if (session == 0)
+            {
+                continue;
+            }
 
-        PayloadMap payloads;
+            StreamSinkUDPTLPrx sink = StreamSinkUDPTLPrx::uncheckedCast(session->getSinks().front());
+            mImplPriv->mSinks.push_back(sink);
+            stream->second->sinks.push_back(sink);
+
+            StreamSourceUDPTLPrx source = StreamSourceUDPTLPrx::uncheckedCast(session->getSources().front());
+            mImplPriv->mSources.push_back(source);
+            stream->second->sources.push_back(source);
+
+            mImplPriv->mUDPTLSessions.push_back(session);
+
+            // Add the stream to the SDP
+            mImplPriv->mSDP->media_count = 0;
 
-        // Add all of the formats to the SDP
-        addFormatstoSDP(stream->second->formats, media, payloads);
+            // Since we may be replacing an existing stream go ahead and remove it
+            mImplPriv->mStreams.erase(boost::lexical_cast<std::string>(mImplPriv->mSDP->media_count));
+
+            pjmedia_sdp_media *media = allocate_from_pool<pjmedia_sdp_media>(mImplPriv->mDialog->pool);
+            // The media count is purposely not incremented here since it is done when the stream is added to the sequence
+            // of streams
+            mImplPriv->mSDP->media[mImplPriv->mSDP->media_count] = media;
+
+            pj_strdup2(mImplPriv->mDialog->pool, &media->desc.media, mImplPriv->mEndpoint->getDescriptor(
+                           stream->second->formats.front())->type.c_str());
+
+            pj_strdup2(mImplPriv->mDialog->pool, &media->desc.transport, "UDPTL");
+
+	    pj_strdup2(mImplPriv->mDialog->pool, &media->desc.fmt[media->desc.fmt_count++], "t38");
+
+            // Add connection level details
+            media->conn = allocate_from_pool<pjmedia_sdp_conn>(mImplPriv->mDialog->pool);
+            pj_strdup2(mImplPriv->mDialog->pool, &media->conn->net_type, "IN");
+
+            if (params->ipv6 == true)
+            {
+                pj_strdup2(mImplPriv->mDialog->pool, &media->conn->addr_type, "IP6");
+            }
+            else
+            {
+                pj_strdup2(mImplPriv->mDialog->pool, &media->conn->addr_type, "IP4");
+            }
+
+            AddressInformation info = source->getLocalDetails();
+
+            pj_strdup2(mImplPriv->mDialog->pool, &media->conn->addr, info.ipAddress.c_str());
+
+            // If session level connection information has not yet been set then set it to us
+            if (!mImplPriv->mSDP->conn)
+            {
+                mImplPriv->mSDP->conn = media->conn;
+            }
+
+            media->desc.port = (pj_uint16_t) info.port;
+            media->desc.port_count = 1;
 
-        // Push the payload mapping to the RTP session so it'll correctly map things
-        session->associatePayloads(payloads);
+            // Use the configured format to set the error correction
+            T38UdptlFormatPtr t38Configuration = T38UdptlFormatPtr::dynamicCast(mImplPriv->mEndpoint->getFormat(t38));
+
+            t38->errorCorrection = t38Configuration->errorCorrection;
+
+            SDPDescriptorPtr ourDescriptor = mImplPriv->mEndpoint->getInterpretedDescriptor(t38);
+            for (SDPFormatParameterSeq::const_iterator parameter = ourDescriptor->parameters.begin();
+                 parameter != ourDescriptor->parameters.end();
+                 ++parameter)
+            {
+                pjmedia_sdp_attr *attr = allocate_from_pool<pjmedia_sdp_attr>(mImplPriv->mDialog->pool);
+                pj_strdup2(mImplPriv->mDialog->pool, &attr->name, (*parameter).c_str());
+                media->attr[media->attr_count++] = attr;
+            }
+        }
+        else
+        {
+            // The media format type is just unknown to us, so we can not create a stream for this
+            continue;
+        }
 
         // Make the caller aware of this new stream
         newStreams.insert(make_pair(boost::lexical_cast<std::string>(mImplPriv->mSDP->media_count), stream->second));
@@ -2903,11 +3044,21 @@ pjmedia_sdp_session *SipSession::createSDPAnswer(const pjmedia_sdp_session* offe
         {
             SDPDescriptorPtr descriptor = new SDPDescriptor();
 
-        std::string payload = std::string(pj_strbuf(&offer->media[stream]->desc.fmt[format]),
-                pj_strlen(&offer->media[stream]->desc.fmt[format]));
-        descriptor->payload = boost::lexical_cast<int>(payload);
             descriptor->type = std::string(pj_strbuf(&offer->media[stream]->desc.media),
                                            pj_strlen(&offer->media[stream]->desc.media));
+	    std::string payload = std::string(pj_strbuf(&offer->media[stream]->desc.fmt[format]),
+                pj_strlen(&offer->media[stream]->desc.fmt[format]));
+
+            // If this is for T.38 it is actually special
+            if (descriptor->type == "image" && (payload == "T38" || payload == "t38"))
+            {
+                descriptor->payload = 96;
+                descriptor->subtype = "UDPTL";
+            }
+            else
+            {
+                descriptor->payload = boost::lexical_cast<int>(payload);
+            }
 
             // Some devices rely solely on the payload for known formats (such as PCMU) so the following format
             // parameters are completely optional
@@ -2992,8 +3143,29 @@ pjmedia_sdp_session *SipSession::createSDPAnswer(const pjmedia_sdp_session* offe
             continue;
         }
 
-    // Update the stream with the formats
-    ourStream->formats = formats;
+        // Update the stream with the formats
+        ourStream->formats = formats;
+
+        // Record the old state so we can relay the state change to the controller if needed
+        StreamState oldState = ourStream->state;
+
+        // Determine the state of the stream and update it
+        if (pjmedia_sdp_media_find_attr2(offer->media[stream], "sendonly", NULL))
+        {
+            ourStream->state = SendOnly;
+        }
+        else if (pjmedia_sdp_media_find_attr2(offer->media[stream], "recvonly", NULL))
+        {
+            ourStream->state = ReceiveOnly;
+        }
+        else if (pjmedia_sdp_media_find_attr2(offer->media[stream], "inactive", NULL))
+        {
+            ourStream->state = Inactive;
+        }
+        else if (pjmedia_sdp_media_find_attr2(offer->media[stream], "sendrecv", NULL))
+        {
+            ourStream->state = SendAndReceive;
+        }
 
         // Assume that no connection level details exist until proven otherwise
         std::string connection = destination;
@@ -3003,193 +3175,366 @@ pjmedia_sdp_session *SipSession::createSDPAnswer(const pjmedia_sdp_session* offe
                                      pj_strlen(&offer->media[stream]->conn->addr));
         }
 
-        RTPSessionPrx session;
+        AudioFormatPtr audio;
+        VideoFormatPtr video;
+        T38UdptlFormatPtr t38;
 
-    // If no sink and no source is present then this stream has no RTP session yet so find one
-    if (ourStream->sinks.empty() && ourStream->sources.empty())
-    {
-        RTPServiceLocatorParamsPtr params;
-        if (mImplPriv->mNatOptions.enableICE)
-        {
-        AsteriskSCF::Media::RTP::V1::RTPOverICEServiceLocatorParamsPtr iceParams =
-            new AsteriskSCF::Media::RTP::V1::RTPOverICEServiceLocatorParams;
-        params = iceParams;
-        iceParams->enableRTPOverICE = true;
-        iceParams->enableTURN = mImplPriv->mNatOptions.enableTURN;
-        }
-        else
+        if ((audio = AudioFormatPtr::dynamicCast(formats.front())) || (video = VideoFormatPtr::dynamicCast(formats.front())))
         {
-        params = new AsteriskSCF::Media::RTP::V1::RTPServiceLocatorParams;
-        }
-
-            params->category = "rtp";
-            params->formats = formats;
-
-            // See what address family the connection address is in so we can request the right RTP service
-            if (connection.find(":") != std::string::npos)
+            // If this is a modified stream make sure the transport is RTP, if not clear things out
+            if (!ourStream->sinks.empty())
             {
-                params->ipv6 = true;
+                StreamSinkRTPPrx rtpSink = StreamSinkRTPPrx::checkedCast(ourStream->sinks.front());
+                if (!rtpSink)
+                {
+                    ourStream->sinks.clear();
+                    newStreams.erase(boost::lexical_cast<std::string>(stream));
+                    newStreams.insert(make_pair(boost::lexical_cast<std::string>(stream), ourStream));
+                }
             }
-            else
+
+            if (!ourStream->sources.empty())
             {
-                params->ipv6 = false;
+                StreamSourceRTPPrx rtpSource = StreamSourceRTPPrx::checkedCast(ourStream->sources.front());
+                if (!rtpSource)
+                {
+                    ourStream->sources.clear();
+                    newStreams.erase(boost::lexical_cast<std::string>(stream));
+                    newStreams.insert(make_pair(boost::lexical_cast<std::string>(stream), ourStream));
+                }
             }
 
-            // Try to find a factory for RTP sessions matching what we need
-            RTPMediaServicePrx factory = RTPMediaServicePrx::uncheckedCast(mImplPriv->mServiceLocator->locate(params));
+            RTPSessionPrx session;
 
-            // If none exist we can't provide accept the stream
-            if (factory == 0)
+            // If no sink and no source is present then this stream has no RTP session yet so find one
+            if (ourStream->sinks.empty() && ourStream->sources.empty())
             {
-                // The only time this should ever occur is on the initial INVITE so removing the stream from everywhere
-                // is perfectly acceptable since nothing has seen it
-                mImplPriv->mStreams.erase(boost::lexical_cast<std::string>(stream));
-                newStreams.erase(boost::lexical_cast<std::string>(stream));
-                continue;
+                RTPServiceLocatorParamsPtr params;
+                if (mImplPriv->mNatOptions.enableICE)
+                {
+                    AsteriskSCF::Media::RTP::V1::RTPOverICEServiceLocatorParamsPtr iceParams =
+                        new AsteriskSCF::Media::RTP::V1::RTPOverICEServiceLocatorParams;
+                    params = iceParams;
+                    iceParams->enableRTPOverICE = true;
+                    iceParams->enableTURN = mImplPriv->mNatOptions.enableTURN;
+                }
+                else
+                {
+                    params = new AsteriskSCF::Media::RTP::V1::RTPServiceLocatorParams;
+                }
+
+                params->category = "rtp";
+                params->formats = formats;
+
+                // See what address family the connection address is in so we can request the right RTP service
+                if (connection.find(":") != std::string::npos)
+                {
+                    params->ipv6 = true;
+                }
+                else
+                {
+                    params->ipv6 = false;
... 7752 lines suppressed ...


-- 
asterisk-scf/integration/sip.git



More information about the asterisk-scf-commits mailing list