Sunday, May 31, 2009

Time for Seam Telco Framework 2.1

The Mobicents application framework for SIP and Media on top of Seam is now officially named Seam Telco Framework (STF) and it just reached version 2.1!

There have been a number of changes and fixes since the last public version and the current 2.1 version must be stable enough to be consumed by all users.

The goal is still the same - to unify the programming model for Telco and JEE application. A somewhat new perspective for the framework is to minimize the new APIs and reuse as many standard or established APIs as possible (JSR-289, MSC or JSR-309) in order to keep a flat learning curve. You can think of it as something using the Seam infrastructure to expose these APIs to your application. For example the SIP messages and the media notification are delivered through Seam events in the context of a JSR-289 Sip Servlets Session. The Sip Servlets Session itself is backing the Seam SESSION scope context similarly to how the HTTP sessions work in Seam. Additionally, most of the framework objects are available and exposed through the Seam IoC and scoped at the right level. The STF simply plugs into Seam and reuses whatever makes sense in the SIP world. By the same logic, Seam uses that same infrastructure to expose the other APIs from the diagram (JEE, JBoss Frameworks and others) in certain roles - JSF for presentation, jBPM for flow and navigation, Drools for security and so forth.

We also want to highlight the point that most major IDEs already have support for Seam core syntax. You can use the same IDE tools to code SIP components without any extra plugins. Again, everything from STF is exposed through the Seam core infrastructure as events, components or scopes.

You should note the following changes:
  • The new documentation is here.
  • This source code of the latest stable release 2.1 is here (where the examples are stable).
  • The source code trunk has moved to here (including the dev examples).
  • The media framework is bundled.
  • The Connection and Link IVR helper classes are unified under a single IVRHelper class now. You can check the examples and the documentation for more information.
To have quick glance let's dive into the familiar conference IVR example:
@Scope(ScopeType.STATELESS)
public class MediaFrameworkDemo {
@Logger Log log;
@In MediaController mediaController;
@In SipSession sipSession;
@In MediaSessionStore mediaSessionStore;
@In IVRHelper ivrHelper;
@In MediaEventDispatcher mediaEventDispatcher;

@In(scope=ScopeType.APPLICATION, required=false)
@Out(scope=ScopeType.APPLICATION, required=false)

String conferenceEndpointName;

private final String announcement =
"http://mobicents.googlecode.com/svn/branches/servers/media/1.x.y/examples/mms-demo/web/src/main/webapp/audio/welcome.wav";

@Observer("INVITE")
public void doInvite(SipServletRequest request) throws Exception {
// Extract SDP from the SIp message
String sdp = new String((byte[]) request.getContent());

// Tell the other side to ring (status 180)
request.createResponse(SipServletResponse.SC_RINGING).send();

// Store the INVITE request in the sip session
sipSession.setAttribute("inviteRequest", request);

// If this is the first INVITE in the app, then we must start a new conference
if (conferenceEndpointName == null)
conferenceEndpointName = "media/trunk/Conference/$";

// Create a connection between the UA and the conference endpoint
mediaController.createConnection(conferenceEndpointName).modify("$",
sdp); // also updates the SDP in Media Server to match capabilities of UA
}

@Observer("connectionOpen")
public void doConnectionOpen(MsConnectionEvent event) throws IOException {
// Save this connection where the framework can read it
// mediaSessionStore.setMsConnection(event.getConnection());// This is done automatically in STF 2.0

// The conference endpoint is now assiged after we are connected, so save it too
conferenceEndpointName = event.getConnection().getEndpoint()
.getLocalName();

// Recall the INVITE request that we saved in doInvite
SipServletRequest request = (SipServletRequest) sipSession
.getAttribute("inviteRequest");

// Make OK (status 200) to tell the other side that the call is established
SipServletResponse response = request.createResponse(SipServletResponse.SC_OK);

// Put the SDP inside the OK message to tell what codecs and so on we agree with
response.setContent(event.getConnection().getLocalDescriptor(),
"application/sdp");

// Now actually send the message
response.send();

// And start listening for DTMF signals
ivrHelper.detectDtmf();
}

@Observer("DTMF")
public void dtmf(String button) {
// If the other side presses the button "0" stop the playback
if("0".equals(button)) {
ivrHelper.endAll();
} else {
// otherwise play announcement
ivrHelper.playAnnouncementWithDtmf(announcement);
}
// Also log the DTMF buttons pressed so far in this session
log.info("Current DTMF Stack for the SIP Session: "
+ mediaEventDispatcher.getDtmfArchive(sipSession));
}

@Observer( { "BYE" })
public void doBye(SipServletRequest request) throws Exception {
request.createResponse(200).send();

// And clean up the connections (not really required, because there is automatic cleanup in STF 2.1)
MsConnection connection = mediaSessionStore.getMsConnection();
connection.release();
}

@Observer("REGISTER")
public void doRegister(SipServletRequest request) throws Exception {
request.createResponse(200).send();
}

}
This is how you can do conferencing and IVR just by subscribing a few methods to a few events without implementing any callback interfaces or keeping track of how the media and SIP events are related. You will notice some differences and comments. There is significant effort by STF to automatically assign and cleanup media objects when it's clear what is expected or when they should not be used any more (for example they are cleaned up when the SIP session is destroyed). Overall we just try to keep the glue code out of your application or at worst keep the glue in the metadata.

What happened with version 2.0?

Version 2.0 is was released without announcment only to solve particular problems without being fully tested. The 2.1 version has some fixes on top of 2.0 and the API changes are explained in the documentation. If you are 2.0 user all APIs are back-compatible and you should be able to switch to 2.1 without any effort.

As usual, any suggestions and feedback are welcome!