JBoss.orgCommunity Documentation

Mobicents JAIN SLEE MGCP Demo Example User Guide

by Amit Bhayani and Oleg Kulikoff

Abstract

MGCP Demo is Media Gateway Controller Application demonstrating the usage of MGCP RA


This manual uses several conventions to highlight certain words and phrases and draw attention to specific pieces of information.

In PDF and paper editions, this manual uses typefaces drawn from the Liberation Fonts set. The Liberation Fonts set is also used in HTML editions if the set is installed on your system. If not, alternative but equivalent typefaces are displayed. Note: Red Hat Enterprise Linux 5 and later includes the Liberation Fonts set by default.

Four typographic conventions are used to call attention to specific words and phrases. These conventions, and the circumstances they apply to, are as follows.

Mono-spaced Bold

Used to highlight system input, including shell commands, file names and paths. Also used to highlight key caps and key-combinations. For example:

The above includes a file name, a shell command and a key cap, all presented in Mono-spaced Bold and all distinguishable thanks to context.

Key-combinations can be distinguished from key caps by the hyphen connecting each part of a key-combination. For example:

The first sentence highlights the particular key cap to press. The second highlights two sets of three key caps, each set pressed simultaneously.

If source code is discussed, class names, methods, functions, variable names and returned values mentioned within a paragraph will be presented as above, in Mono-spaced Bold. For example:

Proportional Bold

This denotes words or phrases encountered on a system, including application names; dialogue box text; labelled buttons; check-box and radio button labels; menu titles and sub-menu titles. For example:

The above text includes application names; system-wide menu names and items; application-specific menu names; and buttons and text found within a GUI interface, all presented in Proportional Bold and all distinguishable by context.

Note the > shorthand used to indicate traversal through a menu and its sub-menus. This is to avoid the difficult-to-follow 'Select Mouse from the Preferences sub-menu in the System menu of the main menu bar' approach.

Mono-spaced Bold Italic or Proportional Bold Italic

Whether Mono-spaced Bold or Proportional Bold, the addition of Italics indicates replaceable or variable text. Italics denotes text you do not input literally or displayed text that changes depending on circumstance. For example:

Note the words in bold italics above username, domain.name, file-system, package, version and release. Each word is a placeholder, either for text you enter when issuing a command or for text displayed by the system.

Aside from standard usage for presenting the title of a work, italics denotes the first use of a new and important term. For example:

If you find a typographical error in this manual, or if you have thought of a way to make this manual better, we would love to hear from you! Please submit a report in the the Issue Tracker, against the product Mobicents JAIN SLEE MGCP Demo Example, or contact the authors.

When submitting a bug report, be sure to mention the manual's identifier: JAIN_SLEE_MGCPDemo_EXAMPLE_User_Guide

If you have a suggestion for improving the documentation, try to be as specific as possible when describing it. If you have found an error, please include the section number and some of the surrounding text so we can find it easily.

This section provides instructions on how to obtain and build the MGCP Demo Example from source code.

  1. Downloading the source code

    Use SVN to checkout a specific release source, the base URL is http://mobicents.googlecode.com/svn/tags/servers/jain-slee/2.x.y/examples/mgcp-demo, then add the specific release version, lets consider 2.1.2.FINAL.

    						[usr]$ svn co
    						http://mobicents.googlecode.com/svn/tags/servers/jain-slee/2.x.y/examples/mgcp-demo/2.1.2.FINAL
    						slee-example-mgcp-demo-2.1.2.FINAL
    					
  2. Building the source code

    Important

    Maven 2.0.9 (or higher) is used to build the release. Instructions for using Maven2, including install, can be found at http://maven.apache.org

    Use Maven to build the deployable unit binary.

    						[usr]$ cd slee-example-mgcp-demo-2.1.2.FINAL
    						[usr]$ mvn install
    					

    Once the process finishes you should have the deployable-unit jar file in the target directory, if Mobicents JAIN SLEE is installed and environment variable JBOSS_HOME is pointing to its underlying JBoss Application Server directory, then the deployable unit jar will also be deployed in the container.

Similar process as for Section 2.2.1, “Release Source Code Building” , the only change is the SVN source code URL, which is http://mobicents.googlecode.com/svn/trunk/servers/jain-slee/examples/mgcp-demo.

The example is designed to demonstrate the usage of JAIN MGCP API including the MGCP RA. At the same time it also demonstrates various features/capabilities of Mobicents Media Server. MGCP messages are transmitted over UDP. Commands are sent to IP addresses defined in the domain for the endpoint. The responses are sent back to the source address (i.e., IP address and UDP port number) of the commands. The domain name specified for Endpoint can include port number as colon separated value. For example 122.64.4.108:2427

When no port is specified for the endpoint, the commands by default is sent:

by the Call Agents, to the default MGCP port for gateways, 2427.

by the Gateways, to the default MGCP port for Call Agents, 2727.

The MGCP RA bounds the MGCP Stack to IP address and Port specified for jain.mgcp.IP_ADDRESS, jain.mgcp.PORT properties in resource-adaptor-jar.xml for MGCP RA. For further details looks at MGCP RA Documentation.

The Example is composed of 3 Services.

CallSbb listens for incoming SIP call and depending on To field of INVITE it creates respective child; Child does further processing of SIP Message.

ConferenceSbb is responsible for maintaining Conference. User gets connected to Conference endpoint by dialing 2012 from SIP Phone. If this is the first User joining Conference, ConferenceSbb fires Custom Event that is consumed by ConfLegSbb. Multiple users can dial 2012 and get connected to same Conference endpoint and participate in conference call.

ConfLegSbb is acting as one of the automated leg of Conference. As soon as conference is initiated, this leg of conference will start a back ground music so even if there is only one participant in conference he/she can listen to music that verifies Conference has started.

As explained earlier, the main purpose of this demo is to make developers understand how to use the MGCP API and MGCP RA. Once there is clear understanding of MGCP API and RA, the business logic can be written as required. Let us go to Section 4, where MGCP usage from respective SBB is explained.

The bellow source code is from IVRSbb, it hides SIP related logic and highlights MGCP specific code. In case if you want to look at complete source, please get the source code as explained in Section 2.2.

package org.mobicents.mgcp.demo;

......

public abstract class IVRSbb implements Sbb {

	public final static String ENDPOINT_NAME = "/mobicents/media/IVR/$";

	public final static String JBOSS_BIND_ADDRESS = System.getProperty("jboss.bind.address", "127.0.0.1");

	public final static String WELCOME = "http://" + JBOSS_BIND_ADDRESS + ":8080/mgcpdemo/audio/RQNT-ULAW.wav";

	......

	private SbbContext sbbContext;

	......

	// MGCP
	private JainMgcpProvider mgcpProvider;
	private MgcpActivityContextInterfaceFactory mgcpAcif;

	public static final int MGCP_PEER_PORT = 2427;
	public static final int MGCP_PORT = 2727;

	private Tracer logger;

	/** Creates a new instance of CallSbb */
	public IVRSbb() {
	}

	public void onCallCreated(RequestEvent evt, ActivityContextInterface aci) {1
		.......
		//SIP Related handling
		.......

		// respond(evt, Response.RINGING);

		CallIdentifier callID = mgcpProvider.getUniqueCallIdentifier();2
		this.setCallIdentifier(callID.toString());
		EndpointIdentifier endpointID = new EndpointIdentifier(ENDPOINT_NAME, JBOSS_BIND_ADDRESS + ":" + MGCP_PEER_PORT);3

		CreateConnection createConnection = new CreateConnection(this, callID, endpointID, ConnectionMode.SendRecv);4

		try {
			String sdp = new String(evt.getRequest().getRawContent());
			createConnection.setRemoteConnectionDescriptor(new ConnectionDescriptor(sdp));5
		} catch (ConflictingParameterException e) {
			// should never happen
		}

		int txID = mgcpProvider.getUniqueTransactionHandler();6
		createConnection.setTransactionHandle(txID);

		MgcpConnectionActivity connectionActivity = null;
		try {
			connectionActivity = mgcpProvider.getConnectionActivity(txID, endpointID);7
			ActivityContextInterface epnAci = mgcpAcif.getActivityContextInterface(connectionActivity);
			epnAci.attach(sbbContext.getSbbLocalObject());
		} catch (FactoryException ex) {
			ex.printStackTrace();
		} catch (NullPointerException ex) {
			ex.printStackTrace();
		} catch (UnrecognizedActivityException ex) {
			ex.printStackTrace();
		}

		mgcpProvider.sendMgcpEvents(new JainMgcpEvent[] { createConnection });8
	}
	
	...
	....
	
	}	    
	    

1

IVRSbb is listening for INVITE SIP RA Event. The Slee Container calls corresponding onCallCreated event handler method.

2

New instance of CallIdentifier is created as this is new call. Through out the call, CallIdentifier will remain the same.

3

New instance of EndpointIdentifier is created. The Endpoint local name is "/mobicents/media/IVR/$". A term represented by a dollar sign ("$") is to be interpreted as, use any available free endpoint. Endpoint domain name is JBOSS_BIND_ADDRESS + ":" + MGCP_PEER_PORT. The MGCP Command will be delivered to MGCP Stack listening at JBOSS_BIND_ADDRESS IP Address and MGCP_PEER_PORT port. Make sure that the Mobicents Media Server is bound to same IP address as JBOSS_BIND_ADDRESS and port in mgcp-conf.xml (MGCP Configuration file in Mobicents Media Server) is same as MGCP_PEER_PORT.

4

New instance of CreateConnection object is created. This CreateConnection Request when received by Media Gateway, will cause Media Gateway to select any one free IVR Endpoint, create a connection on it and send back CreateConnectionResponse. If there is any error while creating connection the returned CreateConnectionResponse will carry the corresponding cause in ReturnCode

5

Setting the SDP of User Agent. This is not mandatory. If this is set the Connection created on Endpoint on media gateway will start sending the media (depending on ConnectionMode) to User Agent at IP:Port specified in SDP. If this is not set, the Connection can latter be modified by sending ModifyConnection (not shown in this example)

6

Set a new transaction for this MGCP Request.

7

Create a new MgcpConnectionActivity for this MGCP Request, attach the SbbLocalObject to this activity to receive CreateConnectionResponse event from MGCP RA.

8

Finally send this CreateConnection MGCP Command to Media Gateway.

Once the MGCP command reaches Media Gateway, it replies back and MGCP RA will fire corresponding event.

	public void onCreateConnectionResponse(CreateConnectionResponse event, ActivityContextInterface aci) {1
		logger.info("Receive CRCX response: " + event.getTransactionHandle());

		......
		....

		ReturnCode status = event.getReturnCode();2

		switch (status.getValue()) {
		case ReturnCode.TRANSACTION_EXECUTED_NORMALLY:

			this.setEndpointName(event.getSpecificEndpointIdentifier().getLocalEndpointName());3
			
			ConnectionIdentifier connectionIdentifier = event.getConnectionIdentifier();4

			this.setConnectionIdentifier(connectionIdentifier.toString());
			String sdp = event.getLocalConnectionDescriptor().toString();5

                        //Send OK to UA with SDP from media gateway
                        .....
			.......

			//Play Announcement
			sendRQNT(WELCOME, false);6
			.....
			......

			break;
		default:
			//CRCX failed at Media Gateway. Take necessary action7
			.....
		}
	}

1

MGCP RA will fire the CreateConnectionResponse event once CRCX Response received from Media Gateway.

2

ReturnCode specifies if Media Gateway has successfully created the connection on Endpoint or not.

Return codes are

100 and 199 indicate a provisional response

200 and 299 indicate a successful completion

400 and 499 indicate a transient error

500 and 599 indicate a permanent error

3

If connection created successfully, CreateConnectionResponse will carry the specific EndpointIdentifier indicating the concrete Endpoint selected by media gateway. Next all MGCP Request will be fired on same endpoint till DeleteConnection is requested which represents end of call.

4

If connection created successfully, CreateConnectionResponse will carry the specific ConnectionIdentifier identifying the connection created by media gateway on above Endpoint. The request to apply Signal or detect Event will be for this ConnectionIdentifier.

5

If connection created successfully, CreateConnectionResponse will carry the ConnectionDescriptor indicating the SDP of above created connection. This SDP can then be sent to UA as OK Response to INVITE received and RTP flow begins between UA and Media Gateway

6

Since the RTP connection is established between UA and Media Gateway, NotificationRequest can be send to Media Gateway to play an announcement.

7

If creation of connection failed for some reason indicated by ReturnCode, necessary action can be taken.

Let us see how NotificationRequest is used to request Media Gateway to play an Announcement

	private void sendRQNT(String mediaPath, boolean createActivity) {
		EndpointIdentifier endpointID = new EndpointIdentifier(this.getEndpointName(), JBOSS_BIND_ADDRESS + ":"
				+ MGCP_PEER_PORT);1

		NotificationRequest notificationRequest = new NotificationRequest(this, endpointID, mgcpProvider
				.getUniqueRequestIdentifier());2
		
		ConnectionIdentifier connectionIdentifier = new ConnectionIdentifier(this.getConnectionIdentifier());3
		
		EventName[] signalRequests = { new EventName(PackageName.Announcement, MgcpEvent.ann.withParm(mediaPath), connectionIdentifier) };
		notificationRequest.setSignalRequests(signalRequests);4

		RequestedAction[] actions = new RequestedAction[] { RequestedAction.NotifyImmediately };

		RequestedEvent[] requestedEvents = {5
				new RequestedEvent(new EventName(PackageName.Announcement, MgcpEvent.oc, connectionIdentifier), actions),
				new RequestedEvent(new EventName(PackageName.Announcement, MgcpEvent.of, connectionIdentifier), actions),
				new RequestedEvent(new EventName(PackageName.Dtmf, MgcpEvent.dtmf0, connectionIdentifier), actions),
				new RequestedEvent(new EventName(PackageName.Dtmf, MgcpEvent.dtmf1, connectionIdentifier), actions),
				new RequestedEvent(new EventName(PackageName.Dtmf, MgcpEvent.dtmf2, connectionIdentifier), actions),
				new RequestedEvent(new EventName(PackageName.Dtmf, MgcpEvent.dtmf3, connectionIdentifier), actions),
				new RequestedEvent(new EventName(PackageName.Dtmf, MgcpEvent.dtmf4, connectionIdentifier), actions),
				new RequestedEvent(new EventName(PackageName.Dtmf, MgcpEvent.dtmf5, connectionIdentifier), actions),
				new RequestedEvent(new EventName(PackageName.Dtmf, MgcpEvent.dtmf6, connectionIdentifier), actions),
				new RequestedEvent(new EventName(PackageName.Dtmf, MgcpEvent.dtmf7, connectionIdentifier), actions),
				new RequestedEvent(new EventName(PackageName.Dtmf, MgcpEvent.dtmf8, connectionIdentifier), actions),

				new RequestedEvent(new EventName(PackageName.Dtmf, MgcpEvent.dtmf9, connectionIdentifier), actions),
				new RequestedEvent(new EventName(PackageName.Dtmf, MgcpEvent.dtmfA, connectionIdentifier), actions),
				new RequestedEvent(new EventName(PackageName.Dtmf, MgcpEvent.dtmfB, connectionIdentifier), actions),
				new RequestedEvent(new EventName(PackageName.Dtmf, MgcpEvent.dtmfC, connectionIdentifier), actions),
				new RequestedEvent(new EventName(PackageName.Dtmf, MgcpEvent.dtmfD, connectionIdentifier), actions),
				new RequestedEvent(new EventName(PackageName.Dtmf, MgcpEvent.dtmfStar, connectionIdentifier), actions),
				new RequestedEvent(new EventName(PackageName.Dtmf, MgcpEvent.dtmfHash, connectionIdentifier), actions) };

		notificationRequest.setRequestedEvents(requestedEvents);
		notificationRequest.setTransactionHandle(mgcpProvider.getUniqueTransactionHandler());

		NotifiedEntity notifiedEntity = new NotifiedEntity(JBOSS_BIND_ADDRESS, JBOSS_BIND_ADDRESS, MGCP_PORT);
		notificationRequest.setNotifiedEntity(notifiedEntity);

		if (createActivity) {6
			MgcpEndpointActivity endpointActivity = null;
			try {
				endpointActivity = mgcpProvider.getEndpointActivity(endpointID);
				ActivityContextInterface epnAci = mgcpAcif.getActivityContextInterface(endpointActivity);
				epnAci.attach(sbbContext.getSbbLocalObject());
			} catch (FactoryException ex) {
				ex.printStackTrace();
			} catch (NullPointerException ex) {
				ex.printStackTrace();
			} catch (UnrecognizedActivityException ex) {
				ex.printStackTrace();
			}
		} // if (createActivity)

		mgcpProvider.sendMgcpEvents(new JainMgcpEvent[] { notificationRequest });7

		logger.info(" NotificationRequest sent");
	}       
       

1

The NotificationRequest should be fired on same Endpoint where connection is created

3

Create a new NotificationRequest Object passing EndpointIdentifier created above and use new RequestIdentifier

3

The NotificationRequest should be fired on same connection on Endpoint.

4

The NotificationRequest carries Signal to play an announcement on connection represented by connectionIdentifier

5

The NotificationRequest carries request to detect DTMF Events and also detect events if Announcement completed successfully or failed.

6

Since none of the Signals/Events are fired/detected on Endpoint, Endpoint Activity is not created. The above Events when detected would be fired on Connection Activity.

7

Finally send the request to Media Gateway.

Once Media Gateway receives the NotificationRequest, it will process the Signals / Events and send back NotificationRequestResponse which carries ReturnCode indicating if Signals can be applied or not and Events can be detected or not.

	public void onNotificationRequestResponse(NotificationRequestResponse event, ActivityContextInterface aci) {
		logger.info("onNotificationRequestResponse");

		ReturnCode status = event.getReturnCode();

		switch (status.getValue()) {
		case ReturnCode.TRANSACTION_EXECUTED_NORMALLY:
			logger.info("The Announcement should have been started");
			break;
		default:
			ReturnCode rc = event.getReturnCode();
			logger.severe("RQNT failed. Value = " + rc.getValue() + " Comment = " + rc.getComment());

			//Send DLCX to MMS. Send BYE to UA
			break;
		}

	}       
       

The Media Gateway will fire the Notify command to Application when ever it detects any of the above Events requested by NotificationRequest

	public void onNotifyRequest(Notify event, ActivityContextInterface aci) {
		logger.info("onNotifyRequest");

		 NotifyResponse response = new  NotifyResponse(event.getSource(),
				ReturnCode.Transaction_Executed_Normally);
		response.setTransactionHandle(event.getTransactionHandle());

		mgcpProvider.sendMgcpEvents(new JainMgcpEvent[] { response });1

		EventName[] observedEvents = event.getObservedEvents();2

		for (EventName observedEvent : observedEvents) {
			switch (observedEvent.getEventIdentifier().intValue()) {
			case MgcpEvent.REPORT_ON_COMPLETION:
				logger.info("Announcemnet Completed NTFY received");
				break;
			case MgcpEvent.REPORT_FAILURE:
				logger.info("Announcemnet Failed received");
				// TODO : Send DLCX and Send BYE to UA
				break;
			case MgcpEvent.DTMF_0:
				logger.info("You have pressed 0");
				sendRQNT(DTMF_0, false);
				break;
			case MgcpEvent.DTMF_1:
				logger.info("You have pressed 1");
				sendRQNT(DTMF_1, false);
				break;
			case MgcpEvent.DTMF_2:
				logger.info("You have pressed 2");
				sendRQNT(DTMF_2, false);
				break;
			case MgcpEvent.DTMF_3:
				logger.info("You have pressed 3");
				sendRQNT(DTMF_3, false);
				break;
			case MgcpEvent.DTMF_4:
				logger.info("You have pressed 4");
				sendRQNT(DTMF_4, false);
				break;
			case MgcpEvent.DTMF_5:
				logger.info("You have pressed 5");
				sendRQNT(DTMF_5, false);
				break;
			case MgcpEvent.DTMF_6:
				logger.info("You have pressed 6");
				sendRQNT(DTMF_6, false);
				break;
			case MgcpEvent.DTMF_7:
				logger.info("You have pressed 7");
				sendRQNT(DTMF_7, false);
				break;
			case MgcpEvent.DTMF_8:
				logger.info("You have pressed 8");
				sendRQNT(DTMF_8, false);
				break;
			case MgcpEvent.DTMF_9:
				logger.info("You have pressed 9");
				sendRQNT(DTMF_9, false);
				break;
			case MgcpEvent.DTMF_A:
				logger.info("You have pressed A");
				sendRQNT(A, false);
				break;
			case MgcpEvent.DTMF_B:
				logger.info("You have pressed B");
				sendRQNT(B, false);
				break;
			case MgcpEvent.DTMF_C:
				logger.info("You have pressed C");
				sendRQNT(C, false);
				break;
			case MgcpEvent.DTMF_D:
				logger.info("You have pressed D");
				sendRQNT(D, false);

				break;
			case MgcpEvent.DTMF_STAR:
				logger.info("You have pressed *");
				sendRQNT(STAR, false);

				break;
			case MgcpEvent.DTMF_HASH:
				logger.info("You have pressed C");
				sendRQNT(POUND, false);

				break;
			}
		}
	}              
              

1

Send the NotifyResponse immediately to avoid Media Gateway sending the Notify again on expiration of response Timer.

2

The Notify command carries list of Events depending on which all occurred at Media Gateway. Iterate through this list and act accordingly. In our example we are simply asking Media Gateway to play corresponding audio file for DTMF pressed by user.

Finally when user hangs-up, we need to delete the connection on Endpoint and free the resources

	public void onCallTerminated(RequestEvent evt, ActivityContextInterface aci) {1
		EndpointIdentifier endpointID = new EndpointIdentifier(this.getEndpointName(), JBOSS_BIND_ADDRESS + ":"
				+ MGCP_PEER_PORT);
		DeleteConnection deleteConnection = new DeleteConnection(this, endpointID);

		deleteConnection.setTransactionHandle(mgcpProvider.getUniqueTransactionHandler());
		mgcpProvider.sendMgcpEvents(new JainMgcpEvent[] { deleteConnection });2

		ServerTransaction tx = evt.getServerTransaction();
		Request request = evt.getRequest();

		try {
			Response response = messageFactory.createResponse(Response.OK, request);
			tx.sendResponse(response);
		} catch (Exception e) {
			logger.severe("Error while sending DLCX ", e);
		}
	}        
        

1

The SIP11 RA fires BYE event, slee container calls onCallTerminated method on SBB

2

New DeleteConnection Object is created passing the same Endpoint on which original connection was created. Once Media Gateway receives DeleteConnection command, it closes the connection and frees Endpoint from all resources allocated.

Revision History
Revision 1.0Tue Dec 30 2009Amit Bhayani
Creation of the Mobicents JAIN SLEE MGCP Demo Example User Guide.