An Introduction to the JAIN SIP API
Pages: 1, 2, 3

Sending a SIP Request

Let's now write a method to send a SIP message with the JAIN SIP API.

In the prerequisites I suggested that you must know SIP fairly well before you can start using the SIP API. You'll now see what I mean by that! The SIP API is quite a low-level abstraction and, in most cases, doesn't use default values or hide headers, request URIs, or contents of SIP messages. The advantage of this design is that you have complete control over what SIP messages contain.

The following method is a bit lengthy. It prepares and sends a SIP request. It can roughly be split into four subsections:

  • Create main elements
  • Create message
  • Complete message
  • Send message

The following main SIP elements are minimally needed to construct a message using the JAIN SIP API:

  • Request URI
  • Method
  • Call-ID header
  • CSeq header
  • From header
  • An array of Via headers
  • Max-forwards header

For information about these elements, please see An Introduction to SIP, Part 1 (Dev2Dev, 2006). The following code snippet creates all of these elements:

                         
public void sendMessage(String to, String message) throws
            ParseException, InvalidArgumentException, SipException {

        SipURI from = addressFactory.createSipURI(getUsername(),
                getHost() + ":" + getPort());
    Address fromNameAddress = addressFactory.createAddress(from);
        fromNameAddress.setDisplayName(getUsername());
        FromHeader fromHeader =
                headerFactory.createFromHeader(fromNameAddress,
                        "textclientv1.0");

        String username = to.substring(to.indexOf(":")+1, to.indexOf("@"));
        String address = to.substring(to.indexOf("@")+1);

        SipURI toAddress =
                addressFactory.createSipURI(username, address);
        Address toNameAddress = addressFactory.createAddress(toAddress);
        toNameAddress.setDisplayName(username);
        ToHeader toHeader =
                headerFactory.createToHeader(toNameAddress, null);

        SipURI requestURI =
                addressFactory.createSipURI(username, address);
        requestURI.setTransportParam("udp");

        ArrayList viaHeaders = new ArrayList();
        ViaHeader viaHeader =
                headerFactory.createViaHeader(
                        getHost(),
                        getPort(),
                        "udp",
                        null);
        viaHeaders.add(viaHeader);

        CallIdHeader callIdHeader = sipProvider.getNewCallId();

        CSeqHeader cSeqHeader =
                headerFactory.createCSeqHeader(1, Request.MESSAGE);

        MaxForwardsHeader maxForwards =
                headerFactory.createMaxForwardsHeader(70);
        ...
                      

I'm using factories that were created in the constructor, HeaderFactory and AddressFactory, to instantiate these elements.

Next let's instantiate the actual SIP message itself, passing in all the elements created earlier:

                         
      Request request =  messageFactory.createRequest(
        requestURI, Request.MESSAGE, callIdHeader, cSeqHeader,
        fromHeader, toHeader, viaHeaders,       maxForwards);
...
                      

Note the use of MessageFactory for this step.

Then let's add other elements to the message: a contact header and the contents of the message (payload). It's possible to add custom headers too at this point.

                         
    SipURI contactURI = addressFactory.createSipURI(getUsername(),
                getHost());
        contactURI.setPort(getPort());
        Address contactAddress = addressFactory.createAddress(contactURI);
        contactAddress.setDisplayName(getUsername());
        ContactHeader contactHeader =
                headerFactory.createContactHeader(contactAddress);
        request.addHeader(contactHeader);

        ContentTypeHeader contentTypeHeader =
                headerFactory.createContentTypeHeader("text", "plain");
        request.setContent(message, contentTypeHeader);
        ...
                      

For more information on how to further massage the request, there's a description of the Request interface in appendix.

Lastly, you send the message using the SipProvider instance:

                         
    sipProvider.sendRequest(request);
}
                      

Sending Messages Inside a Dialog

You're sending our message outside a dialog. That means messages are not related to each other. This works well for a simple instant-messaging application like the TextClient.

An alternative would be to create a dialog (sometimes called a session) using an INVITE message, and then send messages inside this dialog. The TextClient doesn't use this technique. However, I think it's something worth learning. So as a compromise, this subsection describes how it's done.

Sending a message inside a dialog requires the creation of Dialog and Transaction objects. On the initial message (that is, the message that creates the dialog), instead of using the provider to send out the message, you instantiate a Transaction and then get the Dialog from it. You keep the Dialog reference for later. You then use the Transaction to send the message:

                         
ClientTransaction trans = sipProvider.getNewClientTransaction(invite);
dialog = trans.getDialog();
trans.sendRequest();

                      

Later when you wish to send a new message inside the same dialog, you use the Dialog object from before to create a new request. You can then massage the request and, lastly, use the Transaction to send out the message.

                         
request = dialog.createRequest(Request.MESSAGE);

request.setHeader(contactHeader);
request.setContent(message, contentTypeHeader);

ClientTransaction trans = sipProvider.getNewClientTransaction(request);
trans.sendRequest();
                      

Essentially, you're skipping the "create main elements" step when sending a message inside an existing dialog. When you use an INVITE to create a dialog, don't forget to clean it up by sending an in-dialog BYE message at the end. This technique is also used to refresh registrations and subscriptions.

Previously, you've seen the SipListener interface, which contains the processDialogTerminated() and processTransactionTerminated() methods. These are called automatically at the end of a dialog and transaction, respectively. Typically, you implement these methods to clean things up (for example, discard the Dialog and Transaction instances). You'll leave these two methods empty as you don't need them in TextClient.

Pages: 1, 2, 3

Next Page ยป