[asterisk-scf-commits] asterisk-scf/integration/sip.git branch "master" updated.
Commits to the Asterisk SCF project code repositories
asterisk-scf-commits at lists.digium.com
Tue Sep 7 20:14:45 CDT 2010
branch "master" has been updated
via 7e83ed56e0096655fd0bf2adc6beef74ca48ceb0 (commit)
from ea0755c80ad39b685e49fda6f5dd852eee27283b (commit)
Summary of changes:
local-slice/SipIf.ice | 4 +-
slice | 2 +-
src/CMakeLists.txt | 6 +-
src/PJSipManager.cpp | 4 +-
src/PJSipManager.h | 4 +-
src/PJSipSessionModule.cpp | 98 +++++---
src/PJSipSessionModule.h | 4 +-
src/SipChannelServiceApp.cpp | 33 ++--
src/SipChannelServiceDataModel.h | 14 +-
src/SipChannelServiceEndpointLocator.cpp | 11 +-
src/SipChannelServiceEndpointLocator.h | 8 +-
src/SipChannelServiceEventPublisher.cpp | 8 +-
src/SipChannelServiceEventPublisher.h | 6 +-
src/SipEndpoint.cpp | 376 +---------------------------
src/SipEndpoint.h | 131 +---------
src/SipEndpointFactory.cpp | 7 +-
src/SipEndpointFactory.h | 5 +-
src/SipSession.cpp | 406 ++++++++++++++++++++++++++++++
src/SipSession.h | 177 +++++++++++++
19 files changed, 719 insertions(+), 585 deletions(-)
create mode 100644 src/SipSession.cpp
create mode 100644 src/SipSession.h
- Log -----------------------------------------------------------------
commit 7e83ed56e0096655fd0bf2adc6beef74ca48ceb0
Author: Joshua Colp <jcolp at digium.com>
Date: Tue Sep 7 22:20:51 2010 -0300
Bring the SIP channel service up to date, well... closer, to the recent design changes surrounding sessions.
diff --git a/local-slice/SipIf.ice b/local-slice/SipIf.ice
index 39e7c1e..a10b71f 100644
--- a/local-slice/SipIf.ice
+++ b/local-slice/SipIf.ice
@@ -1,6 +1,6 @@
#pragma once
-module Hydra
+module AsteriskSCF
{
module SIP
{
@@ -41,4 +41,4 @@ module V1
}; // module V1
}; //module SIP
-}; //module Hydra
+}; //module AsteriskSCF
diff --git a/slice b/slice
index dcb271b..9774fbe 160000
--- a/slice
+++ b/slice
@@ -1 +1 @@
-Subproject commit dcb271baaca90fa89ed6b7d4846ea458fb303943
+Subproject commit 9774fbe91da9a6e5c8f1d5cb1f1d372c72973037
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index cd0e729..5c759b6 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -6,10 +6,10 @@ hydra_component_add_slice(SipChannelService RoutingIf)
hydra_component_add_slice(SipChannelService ServiceLocatorIf)
hydra_component_add_slice(SipChannelService EndpointIf)
hydra_component_add_slice(SipChannelService ComponentServiceIf)
-hydra_component_add_slice(SipChannelService SessionIf)
-hydra_component_add_slice(SipChannelService BridgeServiceIf)
+hydra_component_add_slice(SipChannelService BridgingIf)
hydra_component_add_slice(SipChannelService MediaIf)
hydra_component_add_slice(SipChannelService MediaRTPIf)
+hydra_component_add_slice(SipChannelService SessionCommunicationsIf)
# Add our component's own slice types.
hydra_component_add_slice(SipChannelService SipIf)
@@ -24,6 +24,8 @@ hydra_component_add_file(SipChannelService SipEndpointFactory.cpp)
hydra_component_add_file(SipChannelService SipEndpointFactory.h)
hydra_component_add_file(SipChannelService SipEndpoint.cpp)
hydra_component_add_file(SipChannelService SipEndpoint.h)
+hydra_component_add_file(SipChannelService SipSession.cpp)
+hydra_component_add_file(SipChannelService SipSession.h)
hydra_component_add_file(SipChannelService PJSipManager.cpp)
hydra_component_add_file(SipChannelService PJSipManager.h)
hydra_component_add_file(SipChannelService PJSipSessionModule.cpp)
diff --git a/src/PJSipManager.cpp b/src/PJSipManager.cpp
index 6da99c2..e64af83 100644
--- a/src/PJSipManager.cpp
+++ b/src/PJSipManager.cpp
@@ -9,7 +9,7 @@
#include "PJSipManager.h"
-namespace Hydra
+namespace AsteriskSCF
{
namespace SipChannelService
@@ -110,4 +110,4 @@ bool PJSipManager::setTransports(pjsip_endpoint *endpoint)
}; //End namespace SipChannelService
-}; //End namespace Hydra
+}; //End namespace AsteriskSCF
diff --git a/src/PJSipManager.h b/src/PJSipManager.h
index 4394c9d..35a8146 100644
--- a/src/PJSipManager.h
+++ b/src/PJSipManager.h
@@ -16,7 +16,7 @@
#include <boost/shared_ptr.hpp>
#include "PJSipSessionModule.h"
-namespace Hydra
+namespace AsteriskSCF
{
namespace SipChannelService
@@ -63,4 +63,4 @@ private:
}; //End namespace SipChannelService
-}; //End namespace Hydra
+}; //End namespace AsteriskSCF
diff --git a/src/PJSipSessionModule.cpp b/src/PJSipSessionModule.cpp
index 0319642..1c1a397 100644
--- a/src/PJSipSessionModule.cpp
+++ b/src/PJSipSessionModule.cpp
@@ -8,27 +8,28 @@
#include <Core/Endpoint/EndpointIf.h>
#include <Core/Routing/RoutingIf.h>
-#include <Core/Bridging/BridgeServiceIf.h>
-#include <Session/SessionIf.h>
+#include <SessionCommunications/Bridging/BridgingIf.h>
+#include <SessionCommunications/SessionCommunicationsIf.h>
#include <Media/MediaIf.h>
#include "PJSipSessionModule.h"
#include "SipChannelServiceDataModel.h"
#include "SipEndpoint.h"
#include "SipEndpointFactory.h"
+#include "SipSession.h"
#include "PJSipManager.h"
-namespace Hydra
+namespace AsteriskSCF
{
namespace SipChannelService
{
-using namespace Hydra::Core::Routing::V1;
-using namespace Hydra::Core::Bridging::V1;
-using namespace Hydra::Core::Endpoint::V1;
-using namespace Hydra::Session::V1;
-using namespace Hydra::Media::V1;
+using namespace AsteriskSCF::Core::Routing::V1;
+using namespace AsteriskSCF::SessionCommunications::Bridging::V1;
+using namespace AsteriskSCF::Core::Endpoint::V1;
+using namespace AsteriskSCF::SessionCommunications::V1;
+using namespace AsteriskSCF::Media::V1;
static pj_status_t sessionLoad(pjsip_endpoint *endpt)
{
@@ -125,22 +126,25 @@ static void handle_new_invite(pjsip_rx_data *rdata)
pjsip_sip_uri *sipFrom = (pjsip_sip_uri *)from;
callerName = std::string(pj_strbuf(&sipFrom->user), pj_strlen(&sipFrom->user));
}
- SipEndpointPtr* caller = new SipEndpointPtr(factory->findByName(callerName));
+ SipEndpointPtr caller = factory->findByName(callerName);
if (caller == 0)
{
pjsip_inv_answer(inv_session, 404, NULL, NULL, &tdata);
pjsip_inv_send_msg(inv_session, tdata);
return;
}
- SipEndpointConfig &config = *(caller)->getConfig();
+ SipEndpointConfig &config = caller->getConfig();
if (config.sessionConfig.callDirection != BOTH && config.sessionConfig.callDirection != INBOUND)
{
pjsip_inv_answer(inv_session, 403, NULL, NULL, &tdata);
pjsip_inv_send_msg(inv_session, tdata);
return;
}
- (*caller)->setInviteSession(inv_session);
- (*caller)->setDialog(dlg);
+
+ // TODO: Create a session here on the endpoint
+ SipSessionPtr* session = 0;
+ (*session)->setInviteSession(inv_session);
+ (*session)->setDialog(dlg);
//We've created our calling endpoint. Now we need to look up the destination.
pjsip_uri *ruri = rdata->msg_info.msg->line.req.uri;
@@ -168,11 +172,7 @@ static void handle_new_invite(pjsip_rx_data *rdata)
}
//Adding the SipEndpoint to the dialog's mod_data makes it easy to
//retrieve during signal callbacks.
- dlg->mod_data[module->id] = (void *)caller;
- BridgeFactoryPrx bridgeFactory = dataModel.getBridgeFactory();
- BridgePrx bridge = bridgeFactory->createBridge((*caller)->getSessionEndpoint(), endpoints, 0);
- Hydra::Session::V1::SignalCallbackPrx callback = Hydra::Session::V1::SignalCallbackPrx::checkedCast(bridge, "SignalCallback");
- (*caller)->setSignalCallback(callback);
+ dlg->mod_data[module->id] = (void *)session;
}
static pj_bool_t sessionOnReceiveRequest(pjsip_rx_data *rdata)
@@ -248,7 +248,7 @@ static pj_bool_t sessionOnReceiveRequest(pjsip_rx_data *rdata)
static void handle_invite_response(pjsip_inv_session *inv, pjsip_rx_data *rdata, pjsip_dialog *dlg)
{
int respCode = rdata->msg_info.msg->line.status.code;
- SipEndpointPtr *endpoint = (SipEndpointPtr*)dlg->mod_data[pjsip_ua_instance()->id];
+ SipSessionPtr *session = (SipSessionPtr*)dlg->mod_data[pjsip_ua_instance()->id];
//Commented because they are currently unused. They
//will be once the individual cases are mapped out.
//pjsip_dialog *dlg = pjsip_rdata_get_dlg(rdata);
@@ -270,21 +270,36 @@ static void handle_invite_response(pjsip_inv_session *inv, pjsip_rx_data *rdata,
else if (respCode == 180)
{
std::cout << "[DEBUG] Got 180 response" << std::endl;
- (*endpoint)->getSignalCallback()->ring((*endpoint)->getSessionEndpoint()->id);
+ std::vector<AsteriskSCF::SessionCommunications::V1::SessionListenerPrx>& listeners = (*session)->getListeners();
+ std::vector<AsteriskSCF::SessionCommunications::V1::SessionListenerPrx>::const_iterator listener;
+ for (listener = listeners.begin(); listener != listeners.end(); ++listener)
+ {
+ (*listener)->ringing((*session)->getSessionProxy());
+ }
}
else if (respCode == 183)
{
std::cout << "[DEBUG] Got 183 response" << std::endl;
- Hydra::Session::V1::ResponseCodePtr response = new Hydra::Session::V1::ResponseCode();
+ AsteriskSCF::SessionCommunications::V1::ResponseCodePtr response = new AsteriskSCF::SessionCommunications::V1::ResponseCode();
response->isdnCode = 42;
- (*endpoint)->getSignalCallback()->progress((*endpoint)->getSessionEndpoint()->id, response);
+ std::vector<AsteriskSCF::SessionCommunications::V1::SessionListenerPrx>& listeners = (*session)->getListeners();
+ std::vector<AsteriskSCF::SessionCommunications::V1::SessionListenerPrx>::const_iterator listener;
+ for (listener = listeners.begin(); listener != listeners.end(); ++listener)
+ {
+ (*listener)->progressing((*session)->getSessionProxy(), response);
+ }
}
else if (respCode == 200)
{
std::cout << "[DEBUG] Got 200 response" << std::endl;
if (inv->state != PJSIP_INV_STATE_DISCONNECTED)
{
- (*endpoint)->getSignalCallback()->connected((*endpoint)->getSessionEndpoint()->id);
+ std::vector<AsteriskSCF::SessionCommunications::V1::SessionListenerPrx>& listeners = (*session)->getListeners();
+ std::vector<AsteriskSCF::SessionCommunications::V1::SessionListenerPrx>::const_iterator listener;
+ for (listener = listeners.begin(); listener != listeners.end(); ++listener)
+ {
+ (*listener)->connected((*session)->getSessionProxy());
+ }
}
}
}
@@ -350,20 +365,29 @@ static void invOnStateChanged(pjsip_inv_session *inv, pjsip_event *event)
{
if (inv->state == PJSIP_INV_STATE_DISCONNECTED)
{
- SipEndpointPtr *endpoint = (SipEndpointPtr*)inv->dlg->mod_data[pjsip_ua_instance()->id];
- if ((*endpoint)->getSignalCallback() != 0)
+ SipSessionPtr *session = (SipSessionPtr*)inv->dlg->mod_data[pjsip_ua_instance()->id];
+ AsteriskSCF::SessionCommunications::V1::ResponseCodePtr response = new AsteriskSCF::SessionCommunications::V1::ResponseCode();
+ if (inv->cause == 486)
{
- /* Translate the reason for our disconnection into suitable granular calls */
- if (inv->cause == 486)
- {
- (*endpoint)->getSignalCallback()->busy((*endpoint)->getSessionEndpoint()->id);
- }
- Hydra::Session::V1::ResponseCodePtr response = new Hydra::Session::V1::ResponseCode();
- response->isdnCode = 42;
- (*endpoint)->getSignalCallback()->terminated((*endpoint)->getSessionEndpoint()->id, response);
+ response->isdnCode = 17;
+ }
+ else if (PJSIP_IS_STATUS_IN_CLASS(inv->cause, 500))
+ {
+ response->isdnCode = 34;
+ }
+ else
+ {
+ // TODO: See what cause is on a normal call completion
+ response->isdnCode = 0;
+ }
+ std::vector<AsteriskSCF::SessionCommunications::V1::SessionListenerPrx>& listeners = (*session)->getListeners();
+ std::vector<AsteriskSCF::SessionCommunications::V1::SessionListenerPrx>::const_iterator listener;
+ for (listener = listeners.begin(); listener != listeners.end(); ++listener)
+ {
+ (*listener)->stopped((*session)->getSessionProxy(), response);
}
- (*endpoint)->destroy();
- delete endpoint;
+ (*session)->destroy();
+ delete session;
}
//stub
}
@@ -409,8 +433,8 @@ static void invOnMediaUpdate(pjsip_inv_session *inv, pj_status_t status)
const pjmedia_sdp_conn *remote_conn = remote_sdp->media[0]->conn ? remote_sdp->media[0]->conn : remote_sdp->conn;
- SipEndpointPtr *endpoint = (SipEndpointPtr*)inv->dlg->mod_data[pjsip_ua_instance()->id];
- (*endpoint)->setRemoteDetails(pj_strbuf(&remote_conn->addr), remote_sdp->media[0]->desc.port);
+ SipSessionPtr *session = (SipSessionPtr*)inv->dlg->mod_data[pjsip_ua_instance()->id];
+ (*session)->setRemoteDetails(pj_strbuf(&remote_conn->addr), remote_sdp->media[0]->desc.port);
// Each stream has its own set of formats, so go to that granularity
for (unsigned int stream = 0; stream < remote_sdp->media_count; stream++)
@@ -553,4 +577,4 @@ pjsip_module *PJSipSessionModule::getModule()
}
}; //end namespace SipChannelService
-}; //end namespace Hydra
+}; //end namespace AsteriskSCF
diff --git a/src/PJSipSessionModule.h b/src/PJSipSessionModule.h
index fd70169..22f0b8c 100644
--- a/src/PJSipSessionModule.h
+++ b/src/PJSipSessionModule.h
@@ -12,7 +12,7 @@
#include <pjsip_ua.h>
#include <pjlib.h>
-namespace Hydra
+namespace AsteriskSCF
{
namespace SipChannelService
@@ -31,4 +31,4 @@ private:
};
}; //end namespace SipChannelService
-}; //end namespace Hydra
+}; //end namespace AsteriskSCF
diff --git a/src/SipChannelServiceApp.cpp b/src/SipChannelServiceApp.cpp
index 3badf65..f493452 100644
--- a/src/SipChannelServiceApp.cpp
+++ b/src/SipChannelServiceApp.cpp
@@ -17,22 +17,25 @@
#include "RoutingIf.h"
#include "ServiceLocatorIf.h"
#include "ComponentServiceIf.h"
-#include "BridgeServiceIf.h"
+#include "BridgingIf.h"
+#include "SessionCommunicationsIf.h"
#include "SipChannelServiceDataModel.h"
#include "SipChannelServiceEventPublisher.h"
#include "SipChannelServiceEndpointLocator.h"
#include "SipEndpointFactory.h"
#include "PJSipSessionModule.h"
+#include "SipSession.h"
using namespace std;
-using namespace Hydra::SipChannelService;
-using namespace Hydra::Core;
-using namespace Hydra::Core::Routing::V1;
-using namespace Hydra::Core::Discovery::V1;
-using namespace Hydra::System::Component::V1;
-
-namespace Hydra
+using namespace AsteriskSCF::SipChannelService;
+using namespace AsteriskSCF::Core;
+using namespace AsteriskSCF::Core::Routing::V1;
+using namespace AsteriskSCF::Core::Discovery::V1;
+using namespace AsteriskSCF::System::Component::V1;
+using namespace AsteriskSCF::SessionCommunications;
+
+namespace AsteriskSCF
{
namespace SipChannelService
{
@@ -66,9 +69,9 @@ public: // Overrides of the SipChannelServiceDataModel singleton's public inter
return mRoutingServiceLocatorRegistry;
}
- virtual Bridging::V1::BridgeFactoryPrx getBridgeFactory() const
+ virtual Bridging::V1::BridgeManagerPrx getBridgeManager() const
{
- return mBridgeFactory;
+ return mBridgeManager;
}
virtual boost::shared_ptr<SipEndpointFactory> getEndpointFactory() const
@@ -101,7 +104,7 @@ public: // Implementation details are visible to this file's classes.
boost::shared_ptr<SipChannelServiceEventPublisher> mEventPublisher;
Routing::V1::EndpointLocatorPtr mEndpointLocator;
Routing::V1::LocatorRegistryPrx mRoutingServiceLocatorRegistry;
- Bridging::V1::BridgeFactoryPrx mBridgeFactory;
+ Bridging::V1::BridgeManagerPrx mBridgeManager;
boost::shared_ptr<SipEndpointFactory> mEndpointFactory;
ServiceLocatorPrx mServiceLocator;
PJSipManager *mPJSipManager;
@@ -289,7 +292,7 @@ void SipChannelServiceApp::registerWithServiceLocator()
string componentServiceGuid("SipChannelService");
mComponentServiceManagement = ServiceManagementPrx::uncheckedCast(mServiceLocatorManagement->addService(componentServicePrx, componentServiceGuid));
- setCategory(mComponentServiceManagement, Hydra::SIP::V1::ComponentServiceDiscoveryCategory);
+ setCategory(mComponentServiceManagement, AsteriskSCF::SIP::V1::ComponentServiceDiscoveryCategory);
// TBD... We may have other interfaces to publish to the Service Locator.
}
@@ -354,10 +357,10 @@ void SipChannelServiceApp::locateBridgeService()
}
ServiceLocatorParamsPtr genericparams = new ServiceLocatorParams();
- genericparams->category = Hydra::Core::Bridging::V1::BridgeServiceDiscoveryCategory;
+ // genericparams->category = Bridging::V1::BridgeServiceDiscoveryCategory;
Ice::ObjectPrx objectPrx = mDataModelInstance.mServiceLocator->locate(genericparams);
- mDataModelInstance.mBridgeFactory = Hydra::Core::Bridging::V1::BridgeFactoryPrx::checkedCast(objectPrx);
+ mDataModelInstance.mBridgeManager = Bridging::V1::BridgeManagerPrx::checkedCast(objectPrx);
}
/**
@@ -492,7 +495,7 @@ int SipChannelServiceApp::run(int argc, char* argv[])
}
}; // end SipChannelService
-}; // end Hydra
+}; // end AsteriskSCF
static SipChannelServiceApp app;
// Application entry point.
diff --git a/src/SipChannelServiceDataModel.h b/src/SipChannelServiceDataModel.h
index e148ca9..d3508fa 100644
--- a/src/SipChannelServiceDataModel.h
+++ b/src/SipChannelServiceDataModel.h
@@ -11,11 +11,11 @@
#include <Ice/Ice.h>
#include <boost/shared_ptr.hpp>
#include "RoutingIf.h"
-#include "BridgeServiceIf.h"
+#include "BridgingIf.h"
#include "ServiceLocatorIf.h"
#include "PJSipManager.h"
-namespace Hydra
+namespace AsteriskSCF
{
namespace SipChannelService
{
@@ -35,11 +35,11 @@ public:
virtual const Ice::CommunicatorPtr getCommunicator() const = 0;
virtual const SipChannelServiceEventPublisher& getEventPublisher() const = 0;
- virtual Hydra::Core::Routing::V1::EndpointLocatorPtr getEndpointLocator() const = 0;
- virtual Hydra::Core::Routing::V1::LocatorRegistryPrx getRoutingService() const = 0;
- virtual Hydra::Core::Bridging::V1::BridgeFactoryPrx getBridgeFactory() const = 0;
+ virtual AsteriskSCF::Core::Routing::V1::EndpointLocatorPtr getEndpointLocator() const = 0;
+ virtual AsteriskSCF::Core::Routing::V1::LocatorRegistryPrx getRoutingService() const = 0;
+ virtual AsteriskSCF::SessionCommunications::Bridging::V1::BridgeManagerPrx getBridgeManager() const = 0;
virtual boost::shared_ptr<SipEndpointFactory> getEndpointFactory() const = 0;
- virtual Hydra::Core::Discovery::V1::ServiceLocatorPrx getServiceLocator() const = 0;
+ virtual AsteriskSCF::Core::Discovery::V1::ServiceLocatorPrx getServiceLocator() const = 0;
virtual PJSipManager *getPJSipManager() const = 0;
virtual bool IsPaused() const = 0;
@@ -49,5 +49,5 @@ protected:
};
}; // SipChannelService
-}; // Hydra
+}; // AsteriskSCF
diff --git a/src/SipChannelServiceEndpointLocator.cpp b/src/SipChannelServiceEndpointLocator.cpp
index 80507d0..c4dd3ff 100644
--- a/src/SipChannelServiceEndpointLocator.cpp
+++ b/src/SipChannelServiceEndpointLocator.cpp
@@ -13,19 +13,20 @@
#include "SipChannelServiceEndpointLocator.h"
#include "SipEndpoint.h"
-namespace Hydra
+namespace AsteriskSCF
{
namespace SipChannelService
{
-Hydra::Core::Endpoint::V1::EndpointSeq SipChannelServiceEndpointLocator::lookup(const ::std::string& destination, const Ice::Current&)
+AsteriskSCF::Core::Endpoint::V1::EndpointSeq SipChannelServiceEndpointLocator::lookup(const ::std::string& destination, const Ice::Current&)
{
- Hydra::Core::Endpoint::V1::EndpointSeq endpoints;
+ AsteriskSCF::Core::Endpoint::V1::EndpointSeq endpoints;
SipEndpointPtr endpoint = mEndpointFactory->findByName(destination);
- endpoints.push_back(endpoint->getSessionEndpoint());
+ // TODO: Pass back an endpoint whatever
+// endpoints.push_back(endpoint->getSessionEndpoint());
return endpoints;
}
}; // end SipChannelService
-}; // end Hydra
+}; // end AsteriskSCF
diff --git a/src/SipChannelServiceEndpointLocator.h b/src/SipChannelServiceEndpointLocator.h
index 9c3b8f7..380e7fe 100644
--- a/src/SipChannelServiceEndpointLocator.h
+++ b/src/SipChannelServiceEndpointLocator.h
@@ -10,7 +10,7 @@
#include "RoutingIf.h"
-namespace Hydra
+namespace AsteriskSCF
{
namespace SipChannelService
{
@@ -21,7 +21,7 @@ namespace SipChannelService
* Channel Service component, so that the rest of the Asterisk SCF system
* can bridge our endpoints.
*/
-class SipChannelServiceEndpointLocator : public Hydra::Core::Routing::V1::EndpointLocator
+class SipChannelServiceEndpointLocator : public AsteriskSCF::Core::Routing::V1::EndpointLocator
{
public:
SipChannelServiceEndpointLocator(boost::shared_ptr<SipEndpointFactory> factory) : mEndpointFactory(factory) { };
@@ -32,7 +32,7 @@ public: // Overrides of EndpointLocator
* The Routing Service will call this method when it needs to lookup an endpoint that
* we have indicated that we are managing.
*/
- virtual ::Hydra::Core::Endpoint::V1::EndpointSeq lookup(const ::std::string& destination, const ::Ice::Current& = ::Ice::Current());
+ virtual ::AsteriskSCF::Core::Endpoint::V1::EndpointSeq lookup(const ::std::string& destination, const ::Ice::Current& = ::Ice::Current());
private:
/**
@@ -42,4 +42,4 @@ private:
};
}; // end SipChannelService
-}; // end Hydra
+}; // end AsteriskSCF
diff --git a/src/SipChannelServiceEventPublisher.cpp b/src/SipChannelServiceEventPublisher.cpp
index 7616650..7bbbff1 100644
--- a/src/SipChannelServiceEventPublisher.cpp
+++ b/src/SipChannelServiceEventPublisher.cpp
@@ -13,9 +13,9 @@
#include "SipChannelServiceEventPublisher.h"
using namespace ::std;
-using namespace ::Hydra::SIP::V1;
+using namespace ::AsteriskSCF::SIP::V1;
-namespace Hydra
+namespace AsteriskSCF
{
namespace SipChannelService
{
@@ -111,7 +111,7 @@ SipChannelServiceEventPublisher::SipChannelServiceEventPublisher()
* Send a message to the service's event topic to report a lookup event.
*/
void SipChannelServiceEventPublisher::sendLookupEvent(const ::std::string& destination,
- ::Hydra::SIP::V1::Event::OperationResult result) const
+ ::AsteriskSCF::SIP::V1::Event::OperationResult result) const
{
if (!mImpl->isInitialized())
{
@@ -122,5 +122,5 @@ void SipChannelServiceEventPublisher::sendLookupEvent(const ::std::string& desti
}
}; // end SipChannelService
-}; // end Hydra
+}; // end AsteriskSCF
diff --git a/src/SipChannelServiceEventPublisher.h b/src/SipChannelServiceEventPublisher.h
index be2a651..b8e9869 100644
--- a/src/SipChannelServiceEventPublisher.h
+++ b/src/SipChannelServiceEventPublisher.h
@@ -12,7 +12,7 @@
#include "SipIf.h"
-namespace Hydra
+namespace AsteriskSCF
{
namespace SipChannelService
{
@@ -32,7 +32,7 @@ public:
* @param result Informs event listeners of the operations success or failure.
*/
void sendLookupEvent(const ::std::string& destination,
- ::Hydra::SIP::V1::Event::OperationResult result) const;
+ ::AsteriskSCF::SIP::V1::Event::OperationResult result) const;
private:
@@ -40,5 +40,5 @@ private:
};
}; // end SipChannelService
-}; // end Hydra
+}; // end AsteriskSCF
diff --git a/src/SipEndpoint.cpp b/src/SipEndpoint.cpp
index b0ce755..e4048c3 100644
--- a/src/SipEndpoint.cpp
+++ b/src/SipEndpoint.cpp
@@ -13,390 +13,20 @@
#include "PJSipManager.h"
#include "SipEndpointFactory.h"
-namespace Hydra
+namespace AsteriskSCF
{
namespace SipChannelService
{
-class SipSignalCommands : public Hydra::Session::V1::SignalCommands
-{
-public:
- SipSignalCommands(SipEndpointPtr endpoint) : mEndpoint(endpoint) { };
-
- bool call(const Core::Endpoint::V1::EndpointIdPtr& caller, const Core::Endpoint::V1::EndpointIdPtr& destination, const Hydra::Session::V1::SignalCallbackPrx& callback, const Ice::Current&)
- {
- pj_str_t local_uri, remote_uri;
- pjsip_dialog *dialog;
- SipEndpointConfig &config = mEndpoint->getConfig();
-
- if (config.sessionConfig.callDirection != BOTH && config.sessionConfig.callDirection != OUTBOUND)
- {
- std::cerr << "[ERROR] Policy disallows placing outgoing calls to endpoint " << mEndpoint->getName() << std::endl;
- return false;
- }
-
- char local[64];
- pj_ansi_sprintf(local, "sip:%s", config.sessionConfig.sourceAddress.c_str());
- local_uri = pj_str(local);
-
- char remote[64];
- bool userDefined = config.transportConfig.user.size() != 0;
- pj_ansi_sprintf(remote, "sip:%s%s%s",
- userDefined ? config.transportConfig.user.c_str() : "",
- userDefined ? "@" : "",
- config.transportConfig.address.c_str());
- remote_uri = pj_str(remote);
-
- // Create a UAC dialog for the outgoing call
- if ((pjsip_dlg_create_uac(pjsip_ua_instance(), &local_uri, &local_uri, &remote_uri, &remote_uri, &dialog)) != PJ_SUCCESS)
- {
- return false;
- }
-
- // Record our endpoint within the dialog so code handling pjsip events can do STUFF
- pjsip_module *module = pjsip_ua_instance();
- if (module == NULL)
- {
- std::cerr << "[WARNING] Um, couldn't get the module from the PJSipManger??" << std::endl;
- }
- SipEndpointPtr* endpoint = new SipEndpointPtr(mEndpoint);
- dialog->mod_data[module->id] = (void*)endpoint;
-
- // Since the SDP generation requires a pool we use the dialog one, so it has to be set here
- mEndpoint->setDialog(dialog);
-
- pjmedia_sdp_session *sdp = mEndpoint->createSDPOffer();
-
- // Create an INVITE session
- pjsip_inv_session *inviteSession;
- if ((pjsip_inv_create_uac(dialog, sdp, 0, &inviteSession)) != PJ_SUCCESS)
- {
- pjsip_dlg_terminate(dialog);
- return false;
- }
-
- // Create the actual INVITE packet
- pjsip_tx_data *packet;
- if ((pjsip_inv_invite(inviteSession, &packet)) != PJ_SUCCESS)
- {
- pjsip_inv_terminate(inviteSession, 500, 0);
- pjsip_dlg_terminate(dialog);
- return false;
- }
-
- // Before we send the message we probably should populate the endpoint data... just in case
- mEndpoint->setInviteSession(inviteSession);
- mEndpoint->setSignalCallback(callback);
-
- // Boom! Houston, we have transmission.
- pjsip_inv_send_msg(inviteSession, packet);
-
- return true;
- }
- void terminate(const Core::Endpoint::V1::EndpointIdPtr&, const Ice::Current&)
- {
- if (mEndpoint->getSignalCallback() == 0)
- {
- return;
- }
-
- pjsip_tx_data *packet;
-
- mEndpoint->setSignalCallback(0);
-
- if ((pjsip_inv_end_session(mEndpoint->getInviteSession(), 503, NULL, &packet)) == PJ_SUCCESS)
- {
- pjsip_inv_send_msg(mEndpoint->getInviteSession(), packet);
- }
- }
-
-private:
- /**
- * A pointer to the endpoint that created us.
- */
- SipEndpointPtr mEndpoint;
-};
-
-class SipSignalCallback : public Hydra::Session::V1::SignalCallback
-{
-public:
- SipSignalCallback(SipEndpointPtr endpoint) : mEndpoint(endpoint) { };
-
- void ring(const Core::Endpoint::V1::EndpointIdPtr& ep, const Ice::Current&)
- {
- pjsip_tx_data *packet;
-
- if ((pjsip_inv_answer(mEndpoint->getInviteSession(), 180, NULL, NULL, &packet)) == PJ_SUCCESS)
- {
- pjsip_inv_send_msg(mEndpoint->getInviteSession(), packet);
- }
- }
- void connected(const Core::Endpoint::V1::EndpointIdPtr& ep, const Ice::Current&)
- {
- pjmedia_sdp_session *sdp = mEndpoint->createSDPOffer();
- pjsip_tx_data *packet;
- if ((pjsip_inv_answer(mEndpoint->getInviteSession(), 200, NULL, sdp, &packet)) == PJ_SUCCESS)
- {
- pjsip_inv_send_msg(mEndpoint->getInviteSession(), packet);
- }
- }
- void terminated(const Core::Endpoint::V1::EndpointIdPtr& ep, const Hydra::Session::V1::ResponseCodePtr& response, const Ice::Current&)
- {
- // This is a notification that the remote side hung up but is NOT a command telling us to terminate the call
- }
- void busy(const Core::Endpoint::V1::EndpointIdPtr& ep, const Ice::Current&)
- {
- pjsip_tx_data *packet;
-
- if ((pjsip_inv_end_session(mEndpoint->getInviteSession(), 486, NULL, &packet)) == PJ_SUCCESS)
- {
- pjsip_inv_send_msg(mEndpoint->getInviteSession(), packet);
- }
-
- mEndpoint->setSignalCallback(0);
- }
- void congestion(const Core::Endpoint::V1::EndpointIdPtr& ep, const Hydra::Session::V1::ResponseCodePtr& response, const Ice::Current&)
- {
- pjsip_tx_data *packet;
-
- // This should map the response code to its respective SIP response code instead of always using 500
- if ((pjsip_inv_end_session(mEndpoint->getInviteSession(), 500, NULL, &packet)) == PJ_SUCCESS)
- {
- pjsip_inv_send_msg(mEndpoint->getInviteSession(), packet);
- }
-
- mEndpoint->setSignalCallback(0);
- }
- void hold(const Core::Endpoint::V1::EndpointIdPtr& ep, const Ice::Current&)
- {
- // TODO: Update SDP with sendonly attribute and no IP
-
- // TODO: This is actually passing the hold through, we will need to support local generation
-
- pjsip_tx_data *packet;
- if ((pjsip_inv_reinvite(mEndpoint->getInviteSession(), NULL, NULL, &packet)) == PJ_SUCCESS)
- {
- pjsip_inv_send_msg(mEndpoint->getInviteSession(), packet);
- }
- }
- void unhold(const Core::Endpoint::V1::EndpointIdPtr& ep, const Ice::Current&)
- {
- // TODO: Update SDP with sendrecv and IP
-
- // TODO: This is actually passing the unhold through, we will need to support local generation
-
- pjsip_tx_data *packet;
- if ((pjsip_inv_reinvite(mEndpoint->getInviteSession(), NULL, NULL, &packet)) == PJ_SUCCESS)
- {
- pjsip_inv_send_msg(mEndpoint->getInviteSession(), packet);
- }
- }
- void flash(const Core::Endpoint::V1::EndpointIdPtr& ep, const Ice::Current&)
- {
- // This is usually transported using INFO or RFC2833, so for now just pretend it does not exist
- }
- void progress(const Core::Endpoint::V1::EndpointIdPtr& ep, const Hydra::Session::V1::ResponseCodePtr& response, const Ice::Current&)
- {
- pjmedia_sdp_session *sdp = mEndpoint->createSDPOffer();
- pjsip_tx_data *packet;
- if ((pjsip_inv_answer(mEndpoint->getInviteSession(), 183, NULL, sdp, &packet)) == PJ_SUCCESS)
- {
- pjsip_inv_send_msg(mEndpoint->getInviteSession(), packet);
- }
- }
-
-private:
- /**
- * A pointer to the endpoint that created us.
- */
- SipEndpointPtr mEndpoint;
-};
-
-class SipMediaSession : public Media::V1::Session
-{
-public:
-SipMediaSession(SipEndpointPtr endpoint) : mId(IceUtil::generateUUID()), mEndpoint(endpoint) { };
-
- Hydra::Media::V1::StreamSourceSeq getSources(const Ice::Current&)
- {
- return mEndpoint->getSources();
- }
-
- Hydra::Media::V1::StreamSinkSeq getSinks(const Ice::Current&)
- {
- return mEndpoint->getSinks();
- }
-
- virtual std::string getId(const Ice::Current&)
- {
- return mId;
- }
-
-private:
- /**
- * Unique identifier for the media session.
- */
- std::string mId;
-
- /**
- * A pointer to the endpoint that created us.
- */
- SipEndpointPtr mEndpoint;
-};
-
/**
* Default constructor.
*/
SipEndpoint::SipEndpoint(Ice::ObjectAdapterPtr adapter, boost::shared_ptr<SipEndpointFactory> factory, std::string name, Ice::PropertyDict props)
-: mName(name), mAdapter(adapter), mEndpointFactory(factory)
+: mName(name)
{
std::cout << "Constructing SIP endpoint " << name << std::endl;
- mSessionEndpoint = new Hydra::Session::V1::SessionEndpoint();
- mSessionEndpoint->id = new Hydra::Core::Endpoint::V1::EndpointId();
- mSessionEndpoint->id->endpointManagerId = "pjsip";
- mSessionEndpoint->id->destinationId = IceUtil::generateUUID();
setConfiguration(props);
-
- mSignalCommands = new SipSignalCommands(this);
- mSessionEndpoint->command = Hydra::Session::V1::SignalCommandsPrx::uncheckedCast(adapter->addWithUUID(mSignalCommands));
- mSignalCallbacks = new SipSignalCallback(this);
- mSessionEndpoint->callback = Hydra::Session::V1::SignalCallbackPrx::uncheckedCast(adapter->addWithUUID(mSignalCallbacks));
- mMediaSession = new SipMediaSession(this);
- mSessionEndpoint->mediaSession = Hydra::Media::V1::SessionPrx::uncheckedCast(adapter->addWithUUID(mMediaSession));
-
- // Get an RTP session capable of handling the formats we are going to offer
- Hydra::Media::V1::FormatSeq formats;
- requestRTPSessions(formats);
-}
-
-/**
- * Internal function called to destroy an endpoint. This is controlled by signaling.
- */
-void SipEndpoint::destroy()
-{
- // Remove all of the different interfaces we have exposed to the world.
- mAdapter->remove(mSessionEndpoint->command->ice_getIdentity());
- mSignalCommands = 0;
- mAdapter->remove(mSessionEndpoint->callback->ice_getIdentity());
- mSignalCallbacks = 0;
- mAdapter->remove(mSessionEndpoint->mediaSession->ice_getIdentity());
- mMediaSession = 0;
-
- // Release all the RTP sessions we are using
- for (std::vector<Hydra::Media::RTP::V1::RTPSessionPrx>::const_iterator i = mRTPSessions.begin(); i != mRTPSessions.end(); ++i)
- {
- (*i)->release();
- }
-
- /* Now... remove ourselves from the factory, once this is done all of our references will be
- * gone and we will cease to exist.
- */
- mEndpointFactory->remove(this);
-}
-
-/**
- * Internal function called to produce an SDP session structure.
- */
-pjmedia_sdp_session *SipEndpoint::createSDPOffer()
-{
- pjmedia_sdp_session *sdp = static_cast<pjmedia_sdp_session*>(pj_pool_zalloc(mDialog->pool, sizeof(pjmedia_sdp_session)));
-
- pj_strdup2(mDialog->pool, &sdp->origin.user, "AsteriskSCF");
- pj_time_val tv;
- pj_gettimeofday(&tv);
- sdp->origin.version = sdp->origin.id = tv.sec + 2208988800UL;
- pj_strdup2(mDialog->pool, &sdp->origin.net_type, "IN");
- pj_strdup2(mDialog->pool, &sdp->origin.addr_type, "IP4");
- sdp->origin.addr = *pj_gethostname();
- pj_strdup2(mDialog->pool, &sdp->name, "sip");
- sdp->time.start = 0;
- sdp->time.stop = 0;
- sdp->attr_count = 0;
-
- // Right now we only support a single stream so go and get it
- Hydra::Media::RTP::V1::StreamSourceRTPPrx stream = Hydra::Media::RTP::V1::StreamSourceRTPPrx::uncheckedCast(mSources.front());
-
- // Add connection details at the session level since we currently only support one media stream.
- sdp->conn = static_cast<pjmedia_sdp_conn*>(pj_pool_zalloc(mDialog->pool, sizeof(pjmedia_sdp_conn)));
- sdp->conn->net_type = sdp->origin.net_type;
- sdp->conn->addr_type = sdp->origin.addr_type;
- pj_strdup2(mDialog->pool, &sdp->conn->addr, stream->getLocalAddress().c_str());
-
- // Add a single media stream
- sdp->media_count = 1;
- pjmedia_sdp_media* media = static_cast<pjmedia_sdp_media*>(pj_pool_zalloc(mDialog->pool, sizeof(pjmedia_sdp_media)));
- sdp->media[0] = media;
- pj_strdup2(mDialog->pool, &media->desc.media, "audio");
- media->desc.port = stream->getLocalPort();
- media->desc.port_count = 1;
- pj_strdup2(mDialog->pool, &media->desc.transport, "RTP/AVP");
-
- // Populate the stream with codec details
- sdp->media[0]->desc.fmt_count = 1;
- sdp->media[0]->attr_count = 0;
-
- // TODO: We should iterate over the formats to produce this instead of hardcoding
- pjmedia_sdp_rtpmap rtpmap;
- pjmedia_sdp_attr *attr;
-
- // This is hardcoded value for ULAW for now
- pj_strdup2(mDialog->pool, &media->desc.fmt[0], "0");
- rtpmap.pt = media->desc.fmt[0];
- rtpmap.clock_rate = 8000;
- pj_strdup2(mDialog->pool, &rtpmap.enc_name, "PCMU");
- rtpmap.param.slen = 0;
- pjmedia_sdp_rtpmap_to_attr(mDialog->pool, &rtpmap, &attr);
- sdp->media[0]->attr[sdp->media[0]->attr_count++] = attr;
-
- // Might as well add sendrecv
- attr = static_cast<pjmedia_sdp_attr*>(pj_pool_zalloc(mDialog->pool, sizeof(pjmedia_sdp_attr)));
- pj_strdup2(mDialog->pool, &attr->name, "sendrecv");
- sdp->media[0]->attr[sdp->media[0]->attr_count++] = attr;
-
- return sdp;
-}
-
-/**
- * Internal function called to request needed RTP sessions.
- */
-void SipEndpoint::requestRTPSessions(Hydra::Media::V1::FormatSeq& formats)
-{
- // TODO: This needs to be improved for multiple streams
- Hydra::Media::RTP::V1::RTPServiceLocatorParamsPtr params = new Hydra::Media::RTP::V1::RTPServiceLocatorParams();
- params->category = "rtp";
-
- SipChannelServiceDataModel& mDataModelInstance(SipChannelServiceDataModel::getInstance());
- Hydra::Media::RTP::V1::RTPMediaServicePrx factory = Hydra::Media::RTP::V1::RTPMediaServicePrx::uncheckedCast(mDataModelInstance.getServiceLocator()->locate(params));
- Hydra::Media::RTP::V1::RTPSessionPrx session = factory->allocate(formats);
- mRTPSessions.push_back(session);
-
- // Create a local copy of the sources, this won't get changed by the RTP session so it's all good
- mSources = session->getSources();
-
- // Create a local copy of the sinks, this won't get changed by the RTP session so it's all good
- mSinks = session->getSinks();
-
- // For testing push a static payload mapping for ULAW into the RTP session
- Hydra::Media::RTP::V1::PayloadMap payloads;
- Hydra::Media::V1::AudioFormatPtr format = new Hydra::Media::V1::AudioFormat();
- format->name = "ulaw";
- format->sampleRate = 8000;
- format->frameSize = 20;
- format->maximumFrameSize = 20;
- format->minimumFrameSize = 20;
- payloads.insert(std::make_pair(0, format));
-
- session->associatePayloads(payloads);
-}
-
-/**
- * Internal function called to set the remote details for RTP.
- */
-void SipEndpoint::setRemoteDetails(std::string destination, int port)
-{
- Hydra::Media::RTP::V1::StreamSinkRTPPrx sink = Hydra::Media::RTP::V1::StreamSinkRTPPrx::uncheckedCast(mSinks.front());
- sink->setRemoteDetails(destination, port);
}
void SipEndpoint::setConfiguration(Ice::PropertyDict props)
@@ -495,4 +125,4 @@ Direction SipEndpointConfig::stringToDirection(std::string directionString)
}
}; // end SipChannelService
-}; // end Hydra
+}; // end AsteriskSCF
diff --git a/src/SipEndpoint.h b/src/SipEndpoint.h
index 84fdcc8..af5bf18 100644
--- a/src/SipEndpoint.h
+++ b/src/SipEndpoint.h
@@ -14,7 +14,7 @@
#include <boost/shared_ptr.hpp>
#include <Core/Endpoint/EndpointIf.h>
-#include <Session/SessionIf.h>
+#include <SessionCommunications/SessionCommunicationsIf.h>
#include <Media/MediaIf.h>
#include <Media/RTP/MediaRTPIf.h>
@@ -25,14 +25,12 @@
#include <pjlib-util.h>
#include <pjlib.h>
-namespace Hydra
+namespace AsteriskSCF
{
namespace SipChannelService
{
-class SipSignalCommands;
-class SipSignalCallback;
class SipEndpointFactory;
/**
@@ -194,76 +192,29 @@ class SipEndpoint : public IceUtil::Shared
public:
SipEndpoint(Ice::ObjectAdapterPtr, boost::shared_ptr<SipEndpointFactory>, std::string name, Ice::PropertyDict props);
- bool operator==(const SipEndpoint &other) const {
- return (this->mInviteSession == other.mInviteSession);
- }
-
bool operator==(const std::string &name) const
{
return (mName == name);
}
- void destroy();
-
- pjmedia_sdp_session *createSDPOffer();
-
- void setRemoteDetails(std::string destination, int port);
-
- /**
- * Internal function which sets the PJsip dialog.
- */
- void setDialog(pjsip_dialog *dialog) { mDialog = dialog; };
-
- /**
- * Internal function which gets the PJsip dialog.
- */
- pjsip_dialog *getDialog() { return mDialog; };
-
- /**
- * Internal function which sets the PJsip INVITE session.
- */
- void setInviteSession(pjsip_inv_session *session) { mInviteSession = session; };
-
- /**
- * Internal function which gets the PJsip INVITE session.
- */
- pjsip_inv_session *getInviteSession() { return mInviteSession; };
-
- /**
- * Internal function which sets the signal callback proxy.
- */
- void setSignalCallback(const Hydra::Session::V1::SignalCallbackPrx& callback) { mSignalCallback = callback; };
+ SipEndpointConfig &getConfig() { return mConfig; };
- /**
- * Internal function which gets the signal callback proxy.
- */
- Hydra::Session::V1::SignalCallbackPrx getSignalCallback() { return mSignalCallback; };
+ std::string getName() { return mName; };
+private:
/**
- * Internal function which gets the media sources on the endpoint.
+ * The Ice object adapter that our proxies were added to.
*/
- Hydra::Media::V1::StreamSourceSeq getSources() { return mSources; };
+ Ice::ObjectAdapterPtr mAdapter;
/**
- * Internal function which gets the media sinks on the endpoint.
+ * The endpoint factory that created us.
*/
- Hydra::Media::V1::StreamSinkSeq getSinks() { return mSinks; };
+ boost::shared_ptr<SipEndpointFactory> mEndpointFactory;
/**
- * Internal function which returns a SessionEndpoint class.
+ * Set up configuration for the endpoint
*/
- Hydra::Session::V1::SessionEndpointPtr getSessionEndpoint() { return mSessionEndpoint; };
-
- SipEndpointConfig &getConfig() { return mConfig; };
-
- std::string getName() { return mName; };
-
-private:
- void requestRTPSessions(Hydra::Media::V1::FormatSeq& formats);
-
- /**
- * Set up configuration for the endpoint
- */
void setConfiguration(Ice::PropertyDict props);
void setTransportConfiguration(Ice::PropertyDict props);
@@ -279,66 +230,6 @@ private:
*/
std::string mName;
- /**
- * An instance of signal commands.
- */
- Hydra::Session::V1::SignalCommandsPtr mSignalCommands;
-
- /**
- * An instance of signal callbacks.
- */
- Hydra::Session::V1::SignalCallbackPtr mSignalCallbacks;
-
- /**
- * An instance of a media session.
- */
- Hydra::Media::V1::SessionPtr mMediaSession;
-
- /**
- * The Ice object adapter that our proxies were added to.
- */
- Ice::ObjectAdapterPtr mAdapter;
-
- /**
- * The endpoint factory that created us.
- */
- boost::shared_ptr<SipEndpointFactory> mEndpointFactory;
-
- /**
- * PJsip dialog for this endpoint.
- */
- pjsip_dialog *mDialog;
-
- /**
- * PJsip INVITE session for this endpoint.
- */
- pjsip_inv_session *mInviteSession;
-
- /**
- * A proxy to the signal callback interface we should invoke signal operations on.
- */
- Hydra::Session::V1::SignalCallbackPrx mSignalCallback;
-
- /**
- * A vector of RTP media sessions belonging to this endpoint.
- */
- std::vector<Hydra::Media::RTP::V1::RTPSessionPrx> mRTPSessions;
-
- /**
- * A vector of media sources associated with this endpoint.
- */
- Hydra::Media::V1::StreamSourceSeq mSources;
-
- /**
- * A vector of media sinks associated with this endpoint.
- */
- Hydra::Media::V1::StreamSinkSeq mSinks;
-
- /**
- * An instance of SessionEndpoint containing session details.
- */
- Hydra::Session::V1::SessionEndpointPtr mSessionEndpoint;
-
SipEndpointConfig mConfig;
};
@@ -349,4 +240,4 @@ typedef IceUtil::Handle<SipEndpoint> SipEndpointPtr;
}; //End namespace SipChannelService
-}; //End namespace Hydra
+}; //End namespace AsteriskSCF
diff --git a/src/SipEndpointFactory.cpp b/src/SipEndpointFactory.cpp
index 39e9852..cfa0648 100644
--- a/src/SipEndpointFactory.cpp
+++ b/src/SipEndpointFactory.cpp
@@ -9,7 +9,7 @@
#include "SipEndpoint.h"
#include "SipEndpointFactory.h"
-namespace Hydra
+namespace AsteriskSCF
{
namespace SipChannelService
{
@@ -26,7 +26,8 @@ SipEndpointPtr SipEndpointFactory::createEndpoint(std::string destination, Ice::
void SipEndpointFactory::remove(SipEndpointPtr endpoint)
{
- mEndpoints.erase(std::remove(mEndpoints.begin(), mEndpoints.end(), endpoint), mEndpoints.end());
+ // TODO: Do we even need to remove sip endpoints yet?
+// mEndpoints.erase(std::remove(mEndpoints.begin(), mEndpoints.end(), endpoint), mEndpoints.end());
}
SipEndpointPtr SipEndpointFactory::findByName(std::string endpointName)
@@ -43,4 +44,4 @@ SipEndpointPtr SipEndpointFactory::findByName(std::string endpointName)
}
}; // end SipChannelService
-}; // end Hydra
+}; // end AsteriskSCF
diff --git a/src/SipEndpointFactory.h b/src/SipEndpointFactory.h
index c6c6247..f1b6d19 100644
--- a/src/SipEndpointFactory.h
+++ b/src/SipEndpointFactory.h
@@ -12,11 +12,10 @@
#include <boost/enable_shared_from_this.hpp>
#include <Core/Endpoint/EndpointIf.h>
-#include <Session/SessionIf.h>
#include "SipEndpoint.h"
-namespace Hydra
+namespace AsteriskSCF
{
namespace SipChannelService
{
@@ -49,4 +48,4 @@ private:
};
}; // end SipChannelService
-}; // end Hydra
+}; // end AsteriskSCF
diff --git a/src/SipSession.cpp b/src/SipSession.cpp
new file mode 100644
index 0000000..56f9e18
--- /dev/null
+++ b/src/SipSession.cpp
@@ -0,0 +1,406 @@
+/*
+ * Asterisk Scalable Communications Framework
+ *
+ * Copyright (C) 2010 -- Digium, Inc.
+ *
+ * All rights reserved.
+ */
+
+#include <Ice/Ice.h>
+#include <IceUtil/UUID.h>
+
+#include "SipChannelServiceDataModel.h"
+#include "PJSipManager.h"
+#include "SipEndpointFactory.h"
+#include "SipEndpoint.h"
+#include "SipSession.h"
+
+namespace AsteriskSCF
+{
+namespace SipChannelService
+{
+
+class SipMediaSession : public Media::V1::Session
+{
+public:
+SipMediaSession(SipSessionPtr session) : mId(IceUtil::generateUUID()), mSession(session) { };
+
+ AsteriskSCF::Media::V1::StreamSourceSeq getSources(const Ice::Current&)
+ {
+ return mSession->getSources();
+ }
+
+ AsteriskSCF::Media::V1::StreamSinkSeq getSinks(const Ice::Current&)
+ {
+ return mSession->getSinks();
+ }
+
+ virtual std::string getId(const Ice::Current&)
+ {
+ return mId;
+ }
+
+private:
+ /**
+ * Unique identifier for the media session.
+ */
+ std::string mId;
+
+ /**
+ * A pointer to the communications session that created us.
+ */
+ SipSessionPtr mSession;
+};
+
+/**
+ * Default constructor.
+ */
+SipSession::SipSession(Ice::ObjectAdapterPtr adapter, SipEndpointPtr endpoint)
+: mAdapter(adapter), mEndpoint(endpoint)
+{
+ mSessionProxy = AsteriskSCF::SessionCommunications::V1::SessionPrx::uncheckedCast(adapter->addWithUUID(this));
+
+ mMediaSession = new SipMediaSession(this);
+ mMediaSessionProxy = AsteriskSCF::Media::V1::SessionPrx::uncheckedCast(adapter->addWithUUID(mMediaSession));
+
+ // Get an RTP session capable of handling the formats we are going to offer
+ AsteriskSCF::Media::V1::FormatSeq formats;
+ requestRTPSessions(formats);
+}
+
+AsteriskSCF::SessionCommunications::V1::SessionInfoPtr SipSession::addListener(const AsteriskSCF::SessionCommunications::V1::SessionListenerPrx& listener, const Ice::Current& current)
+{
+ mListeners.push_back(listener);
+ return getInfo(current);
+}
+
+/**
+ * An implementation of the connect method as defined in SessionCommunications.ice which sends
+ * a 200 OK with SDP to the SIP endpoint.
+ */
+void SipSession::connect(const Ice::Current&)
+{
+ pjmedia_sdp_session *sdp = createSDPOffer();
+ pjsip_tx_data *packet;
+ if ((pjsip_inv_answer(mInviteSession, 200, NULL, sdp, &packet)) == PJ_SUCCESS)
+ {
+ pjsip_inv_send_msg(mInviteSession, packet);
+ }
+}
+
+/**
+ * An implementation of the flash method as defined in SessionCommunications.ice which sends
+ * nothing, presently, to the SIP endpoint.
+ */
+void SipSession::flash(const Ice::Current&)
+{
+ // This is usually transported using INFO or RFC2833, so for now just pretend it does not exist
+}
+
+/**
+ * An implementation of the getEndpoint method as defined in SessionCommunications.ice
+ */
+AsteriskSCF::SessionCommunications::V1::SessionEndpointPrx SipSession::getEndpoint(const Ice::Current&)
+{
+ AsteriskSCF::SessionCommunications::V1::SessionEndpointPrx endpoint;
+ return endpoint;
+}
+
+/**
+ * An implementation of the getInfo method as defined in SessionCommunications.ice
+ */
+AsteriskSCF::SessionCommunications::V1::SessionInfoPtr SipSession::getInfo(const Ice::Current&)
+{
+ AsteriskSCF::SessionCommunications::V1::SessionInfoPtr sessioninfo;
+ return sessioninfo;
+}
+
+/**
+ * An implementation of the connect method as defined in SessionCommunications.ice
+ */
+AsteriskSCF::Media::V1::SessionPrx SipSession::getMediaSession(const Ice::Current&)
+{
+ return mMediaSessionProxy;
+}
+
+/**
+ * An implementation of the hold method as defined in SessionCommunications.ice which sends
+ * a reinvite with sendonly attribute and no connection info to the SIP endpoint.
+ */
+void SipSession::hold(const Ice::Current&)
+{
+ // TODO: Update SDP with sendonly attribute and no IP
+
+ // TODO: This is actually passing the hold through, we will need to support local generation
+
+ pjsip_tx_data *packet;
+ if ((pjsip_inv_reinvite(mInviteSession, NULL, NULL, &packet)) == PJ_SUCCESS)
+ {
+ pjsip_inv_send_msg(mInviteSession, packet);
+ }
+}
+
+/**
+ * An implementation of the progress method as defined in SessionCommunications.ice which sends
+ * a 183 Session Progress with SDP to the SIP endpoint.
+ */
+void SipSession::progress(const AsteriskSCF::SessionCommunications::V1::ResponseCodePtr&, const Ice::Current&)
+{
+ pjmedia_sdp_session *sdp = createSDPOffer();
+ pjsip_tx_data *packet;
+ if ((pjsip_inv_answer(mInviteSession, 183, NULL, sdp, &packet)) == PJ_SUCCESS)
+ {
+ pjsip_inv_send_msg(mInviteSession, packet);
+ }
+}
+
+/**
+ * An implementation of the removeListener method as defined in SessionCommunications.ice
+ */
+void SipSession::removeListener(const AsteriskSCF::SessionCommunications::V1::SessionListenerPrx& listener, const Ice::Current&)
+{
+ mListeners.erase(std::remove(mListeners.begin(), mListeners.end(), listener), mListeners.end());
+}
+
+/**
+ * An implementation of the ring method as defined in SessionCommunications.ice which sends
+ * a 180 Ringing without SDP to the SIP endpoint.
+ */
+void SipSession::ring(const Ice::Current&)
+{
+ pjsip_tx_data *packet;
+
+ if ((pjsip_inv_answer(mInviteSession, 180, NULL, NULL, &packet)) == PJ_SUCCESS)
+ {
+ pjsip_inv_send_msg(mInviteSession, packet);
+ }
+}
+
+/**
+ * An implementation of the start method as defined in SessionCommunications.ice which sends
+ * an INVITE with SDP to the SIP endpoint.
+ */
+void SipSession::start(const Ice::Current&)
+{
+ pj_str_t local_uri, remote_uri;
+ pjsip_dialog *dialog;
+ SipEndpointConfig &config = mEndpoint->getConfig();
+
+ char local[64];
+ pj_ansi_sprintf(local, "sip:%s", config.sessionConfig.sourceAddress.c_str());
+ local_uri = pj_str(local);
+
+ char remote[64];
+ bool userDefined = config.transportConfig.user.size() != 0;
+ pj_ansi_sprintf(remote, "sip:%s%s%s",
+ userDefined ? config.transportConfig.user.c_str() : "",
+ userDefined ? "@" : "",
+ config.transportConfig.address.c_str());
+ remote_uri = pj_str(remote);
+
+ // Create a UAC dialog for the outgoing call
+ if ((pjsip_dlg_create_uac(pjsip_ua_instance(), &local_uri, &local_uri, &remote_uri, &remote_uri, &dialog)) != PJ_SUCCESS)
+ {
+ // What should we do here? Throw an exception?
+ return;
+ }
+
+ // Record our session within the dialog so code handling pjsip events can do STUFF
+ SipSessionPtr* session = new SipSessionPtr(this);
+ dialog->mod_data[pjsip_ua_instance()->id] = (void*)session;
+
+ // Since the SDP generation requires a pool we use the dialog one, so it has to be set here
+ mDialog = dialog;
+
+ pjmedia_sdp_session *sdp = createSDPOffer();
+
+ // Create an INVITE session
+ pjsip_inv_session *inviteSession;
+ if ((pjsip_inv_create_uac(dialog, sdp, 0, &inviteSession)) != PJ_SUCCESS)
+ {
+ pjsip_dlg_terminate(dialog);
+ // What should we do here? Throw an exception?
+ return;
+ }
+
+ // Create the actual INVITE packet
+ pjsip_tx_data *packet;
+ if ((pjsip_inv_invite(inviteSession, &packet)) != PJ_SUCCESS)
+ {
+ pjsip_inv_terminate(inviteSession, 500, 0);
+ pjsip_dlg_terminate(dialog);
+ // What should we do here? Throw an exception?
+ return;
+ }
+
+ // Before we send the message we probably should populate the endpoint data... just in case
+ mInviteSession = inviteSession;
+
+ // Boom! Houston, we have transmission.
+ pjsip_inv_send_msg(inviteSession, packet);
+}
+
+/**
+ * An implementation of the stop method as defined in SessionCommunications.ice which sends
+ * a BYE or applicable response code to the SIP endpoint depending upon the state of the dialog.
+ */
+void SipSession::stop(const AsteriskSCF::SessionCommunications::V1::ResponseCodePtr& response, const Ice::Current&)
+{
+ pjsip_tx_data *packet;
+ // Assume a 503 until proven otherwise
+ unsigned int code = 503;
+
+ // TODO: Convert ALL response codes to equivalent SIP ones, and allow configuration to change it
+ if (response->isdnCode == 17)
+ {
+ code = 486;
+ }
+
+ if ((pjsip_inv_end_session(mInviteSession, 503, NULL, &packet)) == PJ_SUCCESS)
+ {
+ pjsip_inv_send_msg(mInviteSession, packet);
+ }
+}
+
+/**
+ * An implementation of the unhold method as defined in SessionCommunications.ice which sends
+ * a reinvite with sendrecv attribute and connection information to the SIP endpoint.
+ */
+void SipSession::unhold(const Ice::Current&)
+{
+ // TODO: Update SDP with sendrecv and IP
+
+ // TODO: This is actually passing the unhold through, we will need to support local generation
+
+ pjsip_tx_data *packet;
+ if ((pjsip_inv_reinvite(mInviteSession, NULL, NULL, &packet)) == PJ_SUCCESS)
+ {
+ pjsip_inv_send_msg(mInviteSession, packet);
+ }
+}
+
+/**
+ * Internal function called to destroy an endpoint. This is controlled by signaling.
+ */
+void SipSession::destroy()
+{
+ // Remove all of the different interfaces we have exposed to the world.
+ mAdapter->remove(mSessionProxy->ice_getIdentity());
+ mAdapter->remove(mMediaSessionProxy->ice_getIdentity());
+ mMediaSession = 0;
+
+ // Release all the RTP sessions we are using
+ for (std::vector<AsteriskSCF::Media::RTP::V1::RTPSessionPrx>::const_iterator i = mRTPSessions.begin(); i != mRTPSessions.end(); ++i)
+ {
+ (*i)->release();
+ }
+
+ // TODO: Remove ourselves from the endpoint
+}
+
+/**
+ * Internal function called to produce an SDP session structure.
+ */
+pjmedia_sdp_session *SipSession::createSDPOffer()
+{
+ pjmedia_sdp_session *sdp = static_cast<pjmedia_sdp_session*>(pj_pool_zalloc(mDialog->pool, sizeof(pjmedia_sdp_session)));
+
+ pj_strdup2(mDialog->pool, &sdp->origin.user, "AsteriskSCF");
+ pj_time_val tv;
+ pj_gettimeofday(&tv);
+ sdp->origin.version = sdp->origin.id = tv.sec + 2208988800UL;
+ pj_strdup2(mDialog->pool, &sdp->origin.net_type, "IN");
+ pj_strdup2(mDialog->pool, &sdp->origin.addr_type, "IP4");
+ sdp->origin.addr = *pj_gethostname();
+ pj_strdup2(mDialog->pool, &sdp->name, "sip");
+ sdp->time.start = 0;
+ sdp->time.stop = 0;
+ sdp->attr_count = 0;
+
+ // Right now we only support a single stream so go and get it
+ AsteriskSCF::Media::RTP::V1::StreamSourceRTPPrx stream = AsteriskSCF::Media::RTP::V1::StreamSourceRTPPrx::uncheckedCast(mSources.front());
+
+ // Add connection details at the session level since we currently only support one media stream.
+ sdp->conn = static_cast<pjmedia_sdp_conn*>(pj_pool_zalloc(mDialog->pool, sizeof(pjmedia_sdp_conn)));
+ sdp->conn->net_type = sdp->origin.net_type;
+ sdp->conn->addr_type = sdp->origin.addr_type;
+ pj_strdup2(mDialog->pool, &sdp->conn->addr, stream->getLocalAddress().c_str());
+
+ // Add a single media stream
+ sdp->media_count = 1;
+ pjmedia_sdp_media* media = static_cast<pjmedia_sdp_media*>(pj_pool_zalloc(mDialog->pool, sizeof(pjmedia_sdp_media)));
+ sdp->media[0] = media;
+ pj_strdup2(mDialog->pool, &media->desc.media, "audio");
+ media->desc.port = stream->getLocalPort();
+ media->desc.port_count = 1;
+ pj_strdup2(mDialog->pool, &media->desc.transport, "RTP/AVP");
+
+ // Populate the stream with codec details
+ sdp->media[0]->desc.fmt_count = 1;
+ sdp->media[0]->attr_count = 0;
+
+ // TODO: We should iterate over the formats to produce this instead of hardcoding
+ pjmedia_sdp_rtpmap rtpmap;
+ pjmedia_sdp_attr *attr;
+
+ // This is hardcoded value for ULAW for now
+ pj_strdup2(mDialog->pool, &media->desc.fmt[0], "0");
+ rtpmap.pt = media->desc.fmt[0];
+ rtpmap.clock_rate = 8000;
+ pj_strdup2(mDialog->pool, &rtpmap.enc_name, "PCMU");
+ rtpmap.param.slen = 0;
+ pjmedia_sdp_rtpmap_to_attr(mDialog->pool, &rtpmap, &attr);
+ sdp->media[0]->attr[sdp->media[0]->attr_count++] = attr;
+
+ // Might as well add sendrecv
+ attr = static_cast<pjmedia_sdp_attr*>(pj_pool_zalloc(mDialog->pool, sizeof(pjmedia_sdp_attr)));
+ pj_strdup2(mDialog->pool, &attr->name, "sendrecv");
+ sdp->media[0]->attr[sdp->media[0]->attr_count++] = attr;
+
+ return sdp;
+}
+
+/**
+ * Internal function called to request needed RTP sessions.
+ */
+void SipSession::requestRTPSessions(AsteriskSCF::Media::V1::FormatSeq& formats)
+{
+ // TODO: This needs to be improved for multiple streams
+ AsteriskSCF::Media::RTP::V1::RTPServiceLocatorParamsPtr params = new AsteriskSCF::Media::RTP::V1::RTPServiceLocatorParams();
+ params->category = "rtp";
+
+ SipChannelServiceDataModel& mDataModelInstance(SipChannelServiceDataModel::getInstance());
+ AsteriskSCF::Media::RTP::V1::RTPMediaServicePrx factory = AsteriskSCF::Media::RTP::V1::RTPMediaServicePrx::uncheckedCast(mDataModelInstance.getServiceLocator()->locate(params));
+ AsteriskSCF::Media::RTP::V1::RTPSessionPrx session = factory->allocate(formats);
+ mRTPSessions.push_back(session);
+
+ // Create a local copy of the sources, this won't get changed by the RTP session so it's all good
+ mSources = session->getSources();
+
+ // Create a local copy of the sinks, this won't get changed by the RTP session so it's all good
+ mSinks = session->getSinks();
+
+ // For testing push a static payload mapping for ULAW into the RTP session
+ AsteriskSCF::Media::RTP::V1::PayloadMap payloads;
+ AsteriskSCF::Media::V1::AudioFormatPtr format = new AsteriskSCF::Media::V1::AudioFormat();
+ format->name = "ulaw";
+ format->sampleRate = 8000;
+ format->frameSize = 20;
+ format->maximumFrameSize = 20;
+ format->minimumFrameSize = 20;
+ payloads.insert(std::make_pair(0, format));
+
+ session->associatePayloads(payloads);
+}
+
+/**
+ * Internal function called to set the remote details for RTP.
+ */
+void SipSession::setRemoteDetails(std::string destination, int port)
+{
+ AsteriskSCF::Media::RTP::V1::StreamSinkRTPPrx sink = AsteriskSCF::Media::RTP::V1::StreamSinkRTPPrx::uncheckedCast(mSinks.front());
+ sink->setRemoteDetails(destination, port);
+}
+
+}; // end SipChannelService
+}; // end AsteriskSCF
diff --git a/src/SipSession.h b/src/SipSession.h
new file mode 100644
index 0000000..4a8b3b3
--- /dev/null
+++ b/src/SipSession.h
@@ -0,0 +1,177 @@
+/*
+ * Asterisk Scalable Communications Framework
+ *
+ * Copyright (C) 2010 -- Digium, Inc.
+ *
+ * All rights reserved.
+ */
+
+#pragma once
+
+#include <Ice/Ice.h>
+
+#include <boost/thread.hpp>
+#include <boost/shared_ptr.hpp>
+
+#include <Core/Endpoint/EndpointIf.h>
+#include <SessionCommunications/SessionCommunicationsIf.h>
+#include <Media/MediaIf.h>
+#include <Media/RTP/MediaRTPIf.h>
+
+#include <pjsip.h>
+#include <pjmedia.h>
+#include <pjsip_ua.h>
+#include <pjsip_simple.h>
+#include <pjlib-util.h>
+#include <pjlib.h>
+
+namespace AsteriskSCF
+{
+
+namespace SipChannelService
+{
+
+/*
+ * Implementation of the Session interface as defined in SessionCommunicationsIf.ice
+ */
+class SipSession : public AsteriskSCF::SessionCommunications::V1::Session
+{
+public:
+ SipSession(Ice::ObjectAdapterPtr, SipEndpointPtr);
+
+ bool operator==(const SipSession &other) const {
+ return (this->mInviteSession == other.mInviteSession);
+ }
+
+ /**
+ * Interface specific functions.
+ */
+ AsteriskSCF::SessionCommunications::V1::SessionInfoPtr addListener(const AsteriskSCF::SessionCommunications::V1::SessionListenerPrx&, const Ice::Current&);
+ void connect(const Ice::Current&);
+ void flash(const Ice::Current&);
+ AsteriskSCF::SessionCommunications::V1::SessionEndpointPrx getEndpoint(const Ice::Current&);
+ AsteriskSCF::SessionCommunications::V1::SessionInfoPtr getInfo(const Ice::Current&);
+ AsteriskSCF::Media::V1::SessionPrx getMediaSession(const Ice::Current&);
+ void hold(const Ice::Current&);
+ void progress(const AsteriskSCF::SessionCommunications::V1::ResponseCodePtr&, const Ice::Current&);
+ void removeListener(const AsteriskSCF::SessionCommunications::V1::SessionListenerPrx&, const Ice::Current&);
+ void ring(const Ice::Current&);
+ void start(const Ice::Current&);
+ void stop(const AsteriskSCF::SessionCommunications::V1::ResponseCodePtr&, const Ice::Current&);
+ void unhold(const Ice::Current&);
+
+ /**
+ * Implementation specific functions.
+ */
+ void destroy();
+
+ pjmedia_sdp_session *createSDPOffer();
+
+ void setRemoteDetails(std::string destination, int port);
+
+ /**
+ * Internal function which sets the PJsip dialog.
+ */
+ void setDialog(pjsip_dialog *dialog) { mDialog = dialog; };
+
+ /**
+ * Internal function which gets the PJsip dialog.
+ */
+ pjsip_dialog *getDialog() { return mDialog; };
+
+ /**
+ * Internal function which sets the PJsip INVITE session.
+ */
+ void setInviteSession(pjsip_inv_session *session) { mInviteSession = session; };
+
+ /**
+ * Internal function which gets the PJsip INVITE session.
+ */
+ pjsip_inv_session *getInviteSession() { return mInviteSession; };
+
+ /**
+ * Internal function which gets the media sources on the endpoint.
+ */
+ AsteriskSCF::Media::V1::StreamSourceSeq& getSources() { return mSources; };
+
+ /**
+ * Internal function which gets the media sinks on the endpoint.
+ */
+ AsteriskSCF::Media::V1::StreamSinkSeq& getSinks() { return mSinks; };
+
+ /**
+ * Internal function which gets the listeners on this session.
+ */
+ std::vector<AsteriskSCF::SessionCommunications::V1::SessionListenerPrx>& getListeners() { return mListeners; };
+
+ /**
+ * Internal function which gets the proxy to the session.
+ */
+ AsteriskSCF::SessionCommunications::V1::SessionPrx& getSessionProxy() { return mSessionProxy; };
+private:
+ void requestRTPSessions(AsteriskSCF::Media::V1::FormatSeq& formats);
+
+ /**
+ * An instance of a media session.
+ */
+ AsteriskSCF::Media::V1::SessionPtr mMediaSession;
+
+ /**
+ * A proxy to the above media session.
+ */
+ AsteriskSCF::Media::V1::SessionPrx mMediaSessionProxy;
+
+ /**
+ * A proxy to this communications session.
+ */
+ AsteriskSCF::SessionCommunications::V1::SessionPrx mSessionProxy;
+
+ /**
+ * The Ice object adapter that our proxies were added to.
+ */
+ Ice::ObjectAdapterPtr mAdapter;
+
+ /**
+ * PJsip dialog for this endpoint.
+ */
+ pjsip_dialog *mDialog;
+
+ /**
+ * PJsip INVITE session for this endpoint.
+ */
+ pjsip_inv_session *mInviteSession;
+
+ /**
+ * A vector of RTP media sessions belonging to this endpoint.
+ */
+ std::vector<AsteriskSCF::Media::RTP::V1::RTPSessionPrx> mRTPSessions;
+
+ /**
+ * A vector of media sources associated with this endpoint.
+ */
+ AsteriskSCF::Media::V1::StreamSourceSeq mSources;
+
+ /**
+ * A vector of media sinks associated with this endpoint.
+ */
+ AsteriskSCF::Media::V1::StreamSinkSeq mSinks;
+
+ /**
+ * The endpoint that we belong to.
+ */
+ SipEndpointPtr mEndpoint;
+
+ /**
+ * A vector of listeners that want to be notified of responses from the SIP endpoint.
+ */
+ std::vector<AsteriskSCF::SessionCommunications::V1::SessionListenerPrx> mListeners;
+};
+
+/**
+ * A typedef which creates a smart pointer type for SipSession.
+ */
+typedef IceUtil::Handle<SipSession> SipSessionPtr;
+
+}; //End namespace SipChannelService
+
+}; //End namespace AsteriskSCF
-----------------------------------------------------------------------
--
asterisk-scf/integration/sip.git
More information about the asterisk-scf-commits
mailing list