[sip-comm-dev] SIP HOLD/UNHOLD Function


#1

Hi Everybody,

I'm trying to come up with a hold/unhold strategy for SIP
Communicator. So far I have Implemented the functionality according to
this RFC:

http://tools.ietf.org/html/draft-ietf-sip-service-examples-00

(Example HOLD)

Basically what I did was implement putOnHold in
OperationSetBasicTelephonySipImpl.java as follows:

public void putOnHold(CallParticipant cp) {
        CallParticipantSipImpl callParticipant = (CallParticipantSipImpl)cp;

        logger.error("\n\n\n\n\n\n\n---------------------HOLDING CALL
NEW NEW VERSION------------\n\n\n\n\n\n\n\n\n\n");

        Request request = callParticipant.getFirstTransaction().getRequest();
        Request hold = null;

        try {
            //callParticipant.getDialog().set
            hold = callParticipant.getDialog().createRequest(Request.INVITE);

            ContentTypeHeader contentTypeHeader =
                    protocolProvider.getHeaderFactory().createContentTypeHeader(
                    "application", "sdp");

            Address calleeAddress =
callParticipant.getDialog().getRemoteParty();
            javax.sip.address.URI calleeURI = calleeAddress.getURI();
            String host = ((SipURI)calleeURI).getHost();

            CallSession callSession =
((MediaServiceImpl)SipActivator.getMediaService())
            .createCallSession(callParticipant.getCall());

            logger.error("\n\n\n\n\n\n\n---------------------Creating
Sip Offer------------\n\n\n\n\n\n\n\n\n\n");

            //hold.setContent(request.getContent(), contentTypeHeader);
            logger.error(((CallSessionImpl)callSession).createSdpHoldOffer(InetAddress.getByName(host)));

            hold.setContent(((CallSessionImpl)callSession).createSdpHoldOffer(InetAddress.getByName(host)),
contentTypeHeader);

        } catch (Exception ex) {
            logger.error("Failed to create bye request!", ex);

        }
        ClientTransaction clientTransaction = null;
        try {
            clientTransaction = callParticipant.getJainSipProvider()
            .getNewClientTransaction(hold);
        } catch (TransactionUnavailableException ex) {
            logger.error(
                    "Failed to construct a client transaction from the
HOLD request"
                    , ex);

        }

        try {
            callParticipant.getDialog().sendRequest(clientTransaction);
            logger.debug("sent request:\n" + hold);
        } catch (SipException ex) {

        }
}

And then, the function putOffHold()

public void putOffHold(CallParticipant cp) {

        CallParticipantSipImpl callParticipant = (CallParticipantSipImpl)cp;

        logger.error("\n\n\n\n\n\n\n---------------------UNHOLDING
CALL NEW NEW VERSION------------\n\n\n\n\n\n\n\n\n\n");

        Request request = callParticipant.getFirstTransaction().getRequest();
        Request unhold = null;

        try {
            //callParticipant.getDialog().set
            unhold = callParticipant.getDialog().createRequest(Request.INVITE);

             ContentTypeHeader contentTypeHeader =
                    protocolProvider.getHeaderFactory().createContentTypeHeader(
                    "application", "sdp");

            logger.error("\n\n\n\n\n\n\n---------------------Creating
Sip Offer------------\n\n\n\n\n\n\n\n\n\n");

            unhold.setContent(request.getContent(), contentTypeHeader);

        } catch (Exception ex) {
            logger.error("Failed to create bye request!", ex);

        }
        ClientTransaction clientTransaction = null;
        try {
            clientTransaction = callParticipant.getJainSipProvider()
            .getNewClientTransaction(unhold);
        } catch (TransactionUnavailableException ex) {
            logger.error(
                    "Failed to construct a client transaction from the
HOLD request"
                    , ex);

        }

        try {
            callParticipant.getDialog().sendRequest(clientTransaction);
            logger.debug("sent request:\n" + unhold);
        } catch (SipException ex) {

        }

    }

And I created a special function in CallSessionImpl.java that allows
me to reset the SDP port to 0.0.0.0, for holds.

private SessionDescription createSessionHoldDescription(
                                            SessionDescription offer,
                                            InetAddress intendedDestination)
        throws MediaException
    {
        try
        {
            SessionDescription sessDescr
                = mediaServCallback.getSdpFactory().createSessionDescription();

            //"v=0"
            Version v = mediaServCallback.getSdpFactory().createVersion(0);

            sessDescr.setVersion(v);

            //we don't yet implement ice so just try to choose a local address
            //that corresponds to the address provided by the offer or as an
            //intended destination.
            NetworkAddressManagerService netAddressManager
                = MediaActivator.getNetworkAddressManagerService();

            if(offer != null)
            {
                Connection c = offer.getConnection();
                if(c != null)
                {
                    try
                    {
                        intendedDestination = InetAddress.getByName(c.
                            getAddress());
                    }
                    catch (SdpParseException ex)
                    {
                        logger.warn("error reading remote sdp. "
                                    + c.toString()
                                    + " is not a valid connection parameter.",
                                    ex);
                    }
                    catch (UnknownHostException ex)
                    {
                        logger.warn("error reading remote sdp. "
                                    + c.toString()
                                    + " does not contain a valid address.",
                                    ex);
                    }
                }
            }

            allocateMediaPorts(intendedDestination);

            InetAddress publicIpAddress = audioPublicAddress.getAddress();

            String addrType
                = publicIpAddress instanceof Inet6Address
                ? Connection.IP6
                : Connection.IP4;

            //spaces in the user name mess everything up.
            //bug report - Alessandro Melzi
            Origin o = mediaServCallback.getSdpFactory().createOrigin(
                call.getProtocolProvider().getAccountID().getUserID()
                , 0
                , 0
                , "IN"
                , addrType
                , publicIpAddress.getHostAddress());

            sessDescr.setOrigin(o);
            //c=
            Connection c = mediaServCallback.getSdpFactory().createConnection(
                "IN"
                , addrType
                , "0.0.0.0");

            sessDescr.setConnection(c);

            //"s=-"
            SessionName s
                = mediaServCallback.getSdpFactory().createSessionName("-");
            sessDescr.setSessionName(s);

            //"t=0 0"
            TimeDescription t
                = mediaServCallback.getSdpFactory().createTimeDescription();
            Vector timeDescs = new Vector();
            timeDescs.add(t);

            sessDescr.setTimeDescriptions(timeDescs);

            //media descriptions.
            Vector offeredMediaDescriptions = null;
            if(offer != null)
                offeredMediaDescriptions = offer.getMediaDescriptions(false);

            logger.debug("Will create media descs with: audio public address="
                         + audioPublicAddress
                         + " and video public address="
                         + videoPublicAddress);

            Vector mediaDescs
                = createMediaDescriptions(offeredMediaDescriptions
                                        , audioPublicAddress
                                        , videoPublicAddress);

            sessDescr.setMediaDescriptions(mediaDescs);

            if (logger.isTraceEnabled())
            {
                logger.trace("Generated SDP - " + sessDescr.toString());
            }

            return sessDescr;
        }
        catch (SdpException exc)
        {
            throw new MediaException(
                "An SDP exception occurred while generating local "
                + "sdp description"
                , MediaException.INTERNAL_ERROR
                , exc);
        }

    }

Here's what happens:

1) I place a call
2) Audio comes through fine
3) I place the call on hold, calling putCallOnHold(CallParticipant)
4) User hears on hold music.
5) After this point, even if I hang up the call, I can no longer hear
audio in new calls.
6) Needless to say, taking the user off hold STOPS the on hold music,
but does not restore audio.

Does anyone have any idea what I could be doing wrong? I mean, is
there some other step I am missing that would stop audio, even in new
calls?

Thanks,
JLS

···

---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@sip-communicator.dev.java.net
For additional commands, e-mail: dev-help@sip-communicator.dev.java.net


#2

Hello John,

I am glad to hear that someone is working on HOLD/UNHOLD
functionalities. This is something that we have been missing for quite a
while now. For the record, we'd be very interested to integrate it in
SIP Communicator if you decide to contribute it once you are done.

(more inline)

John Singleton wrote:

Hi Everybody,

I'm trying to come up with a hold/unhold strategy for SIP
Communicator. So far I have Implemented the functionality according to
this RFC:

http://tools.ietf.org/html/draft-ietf-sip-service-examples-00

This draft is quite outdated now. You are not supposed to be sending SDP
with a 0.0.0.0 address any more. You should have a look at RFC3264 which
defines rules for negotiating media with SIP and SDP.

http://tools.ietf.org/html/rfc3264

(The semantics of putting streams on hold are described in section 8.4 -
http://tools.ietf.org/html/rfc3264#section-8.4 )

You could also find complete call flow examples here:

http://www.tech-invite.com/Ti-sip-service-1.html

(Example HOLD)
...

Here's what happens:

1) I place a call
2) Audio comes through fine
3) I place the call on hold, calling putCallOnHold(CallParticipant)
4) User hears on hold music.
5) After this point, even if I hang up the call, I can no longer hear
audio in new calls.
6) Needless to say, taking the user off hold STOPS the on hold music,
but does not restore audio.

Does anyone have any idea what I could be doing wrong? I mean, is
there some other step I am missing that would stop audio, even in new
calls?

That's strange. I wonder what might be causing the problem. In your mail
I didn't see any code specificly handling reception of 0.0.0.0 addresses
in SDP. In case you fed these addresses directly to JMF then it might
have been freaking out with some unhandled exceptions.

I think it would be a good idea to to

1. Add methods to CallSessionImpl that handle re-INVITE descriptions and
that reinit your streams.

2. Specificly handle the HOLD and UNHOLD SDPs by stopping your streams
instead of feeding the 0.0.0.0 address or 0 port to JMF.

Hope this helps
Emil

···

Thanks,
JLS

---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@sip-communicator.dev.java.net
For additional commands, e-mail: dev-help@sip-communicator.dev.java.net

---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@sip-communicator.dev.java.net
For additional commands, e-mail: dev-help@sip-communicator.dev.java.net