This is the central class for the application and contains the controlling logic and methods needed to complete the application's main flow.
AssistedCall objects are stored in the
SipApplicationSession. The application manages pairs of call-legs (where the application server is behaving as a B2BUA). Management of the call-leg pairs are encapsulated in implementations of the
ITPCC interface, for example,
AssistedCall class implements the
ITPCCEventListener interface, which allows it to receive callback notifications of the ongoing progress of call-leg pairs. If a caller or callee prematurely ends a call session, or for some reason a call cannot be connected, the
AssistedCall implementation will receive these notifications and end the other calls gracefully.
This utility class provides methods for managing the instances of
AssistedCall objects, network utility methods, and a SIP message header logging service. The
AssistantService object can also be used to create a timer so calls can receive timeout notifications. This is achieved using the servlet container's
AssistantTimerListener class is declared as the application timer listener in the sip.xml file.
This data access object wraps access to an SQL database for storing mappings from a person's public address (address of record) to their many device addresses (for example, their phone at home or at work). The
ContactStoreDAO returns a value object called
ContactStoreVO. A PointBase database is used with two tables called
Greetings table has two fields,
aor_uri, which is the public address for a user with a configured Personal Assistant, and
greeting, which is a blob containing the user's audio greeting. The
Contacts table has a key
aor_uri which it relates to its second field
Contacts table holds a URI for each of the user's devices.
Today, there are a number of different protocols all leveraging SIP for controlling media servers that have been published as IETF Internet Drafts. Popular examples, include the Media Sessions Markup Language (MSML), the Media Server Control Markup Language (MSCML), and the SIP Interface to VoiceXML Media Services (draft-burke-vxml). To make the implementation as general as possible, we have chosen to abstract the interface using the
IMediaListener classes, part of the
com.voxpilot.mediacontrol package. The
IMediaController interface provides methods for starting and terminating a VoiceXML session. The
IMediaListener interface is used to report events such as the VoiceXML session starting or terminating back to the SIP servlet application. Both of these interfaces should be considered "skeletons" that can be extended in the future to provide access to other functions on the media server, such as low-level commands to play announcements, collect input from the user, start conferences, and perform transcoding.
We have supplied a concrete implementation of
SipVxmlMediaController, which encapsulates the standard approach for triggering VoiceXML application sessions described in RFC 4240 and draft-burke-vxml. Briefly, the MRF is invoked by sending a SIP
INVITE to the MRF with a specially formatted SIP URI:
The user part is fixed at
dialog to indicate a VoiceXML dialog service. The host and port refer to the host and port of the MRF. The
voicexml parameter specifies the first VoiceXML page to execute and, in our case, will reference the application server. The
aai parameter is used for application-to-application information that can be retrieved within the VoiceXML application from the session variable
aai parameter is useful for passing in extra information to the VoiceXML application. For the Personal Assistant application, we will pass in the
SipApplicationSession ID and pass this ID back in each HTTP request for correlation purposes (more on this below).
The following code snippet shows how to create a media controller and create and connect a VoiceXML session:
// Create a media controller IMediaController mediaController = MediaControllerFactory.create( IMediaController.SIP_VXML_MEDIA_CONTROLLER, sipFactory, sipAppSession); // Register for events mediaController.setMediaListener(this); // Create a VoiceXML session VxmlParam  params = new VxmlParam; params = new VxmlParam(VxmlParam.VOICEXML, vxmlURL); params = new VxmlParam(VxmlParam.AAI, sipAppSession.getId()); mediaController.createVxmlSession(sipMrfUri, fromUri, toUri, sdpObject, sdpContentType, params); // Connect mediaController.connectVxmlSession(); /** The VoiceXML session can be started after the IMediaListener.vxmlSessionReady() event is received by calling the IMediaController.startVxmlSession() method. **/
IMediaController interface receives SIP messages (e.g. such as a 200 OK response from the MRF) via its
doSipServletMessage(). In the Personal Assistant application, the
AssistantSipServlet dispatches SIP messages to objects implementing the
ISipDialog interface. We employ an adapter pattern using a class called
SipMediaControllerAdapter which implements the
ISipDialog interface and aggregates a reference to an
IMediaController. This way, SIP messages are passed through to the
IMediaController via its adapter.
On the SIP side, application state is maintained via the
SipApplicationSession object, part of the standard SIP servlet package. A new
SipApplicationSession object is created each time a new
INVITE request is placed to the Personal Assistant application. The
SipApplicationSession object in turn contains a reference to one or more
SipSession objects - one for each SIP dialog. For the Personal Assistant application, we place the central
AssistedCall object into the
A key function required by a container supporting converged applications (such as one involving both the HTTP and SIP protocols) is the ability to provide some sort of correlation between a HTTP request and its corresponding SIP dialog. While the SIP servlet specification does mention that the
SipApplicationSession object can aggregate
HttpSession objects, the mechanism to create this relationship is not expanded upon. The upcoming WebLogic SIP Server 2.2 extends the SIP servlet API by introducing some useful methods for correlating HTTP and SIP sessions.
In the Personal Assistant application, we provide two static methods on the
AssistantService class called
findAssistedCall(). The former stores the
SipApplicationSession into the servlet context keyed by its ID (obtained from
SipApplicationSession.getId()). The latter retrieves the
SipApplicationSession object given the ID.
Each time the MRF is invoked, the
SipApplicationSession ID is passed into the VoiceXML application via the
aai parameter. Each HTTP request back to the application server from the MRF includes this ID, therefore allowing the HTTP servlet to retrieve the corresponding
SipApplicationSession and associated application state.
To decompose the application neatly, the Personal Assistant code encapsulates the call flow patterns between pairs of call legs in a specialized sub-class of
ITPCC. There are a total of four classes:
CallerToVMS: Connects the caller to the MRF to play a greeting message and record the caller's name.
CalleeToVMS: Places an outbound call to the callee and connects the callee to the MRF to inform the callee a caller wishes to speak to him or her.
CallerCalleeTransfer: Connects the caller to the callee.
CallerValedictionTransfer: Connects the caller to the MRF to play a valediction message if the callee refuses to speak to the caller.
( VMS stands for VoiceXML Media Server and is another name for MRF).
ITPCC interface is straightforward: The
startCall() method commences the call flow pattern, and the
endCall() method terminates the call-legs. The
disconnectB() methods can be used to tear down a particular call-leg.
Figure 6 illustrates the