Tropo Blind Transfers

Updated 22 Jan 2001 due to sipsorcery call manager service again being made available on an HTTP URL since there’s a problem with Tropo recognizing the sipsorcery SSL certificate. Note the service is still available on HTTPS as well as HTTP. Also it’s no longer necessary to use the workaround to get SIP headers in a Tropo dialplan. Calls can be forwarded directly to sip.tropo.com.

Updated 12 Apr 2010 due to sipsorcery call manager service migration to HTTPS.

Tropo is a hosted voice application platform that I and a number of other sipsorcery users have messed around with at various stages. At this point I would say Tropo is definitely the pick of the bunch from the voice application platforms I have tested out and some of the stuff that can be done in a couple of lines of script, such as speech recognition or text-to-speech, is pretty amazing.

One glaring ommission for me and again other sipsorcery users has been the lack of an elegant way to transfer calls away off the Tropo servers. Here’s a few posts from the Tropo Forums about transfers:

  • Call and Transfer (from jack9901)
  • transfer API
  • And I posted the same query regarding blind transfers at some point as well but it must have been cleaned out

The usage pattern a lot of people are after is to dial into the Tropo platform, do some processing, such as ask the user to enter a number, and then transfer the call back to a different system to do some different processing, such as forward the call to a 3rd party SIP provider. Tropo does support attended transfers but that has two big shortcomings:

  • 1. Because Tropo will ultimately be charging by the minute having their servers bridge the whole call after any application processing is done is an unneccessary expense,
  • 2. Adding an extra media server into the call path always introduces call quality concerns. Even if Tropo’s systems and network connections are the best in the World it’s extra latency on the call that’s not needed.

After the recent work I did to support transfers on the sipsorcery servers I started thinking about the Tropo problem again and realised there was a nice elegant solution. Instead of initiating the SIP transfer from Tropo I could get Tropo to send a HTTPS request to sipsorcery and have it do the transfer instead. So that’s what I’ve spent the last few days doing and the good news is it works perfectly (at least for me).

The steps are:

  • Create a new dialplan on your sipsorcery account called transfer, this is the dialplan the call will end up in when it comes back from Tropo,
  • In your sipsorcery diaplan set the From header user to something that can be used to uniquely identify the call:
        when /^232$/ then sys.Dial("999142xxx@sip.tropo.com")
    

    An old example of a sipsorcery dialplan is shown below. The difference between the two is that when sip.tropo.com is used instead of sip-noproxy.voxeo.net there is no way to access the SIP headers within a Tropo dialplan and a “hack” of setting the From header user is needed.

        when /^232$/ then sys.Dial("999142xxx@sip.tropo.com[fu=uniqueidxxx]")
    

    The From header user can be accessed in the Tropo system with $currentCall.callerID $currentCall.getHeader(“x-sbc-call-id”),

  • In your Tropo application the blind transfer needs to be initiated using a HTTPS request a Ruby example I’ve used is:
    require 'java'
    
    answer()
    say "hello world"
    log "Call-ID=" + $currentCall.getHeader("x-sbc-call-id")
    svcURL = "http://www.sipsorcery.com/callmanager.svc/blindtransfer?user=username&callid=#{$currentCall.getHeader("x-sbc-call-id")}&destination=hold";
    url= java.net.URL.new svcURL
    conn = url.openConnection
    log "javaURL created"
    stm = conn.getInputStream
    transferResult = org.apache.commons.io.IOUtils.toString(stm)
    log transferResult
    say "http://202.6.74.107:8060/triplej.mp3" # Play some audio while transfer is being carried out.
    

    An old Tropo example, which will NOT work due to the call manager service no longer being provided on an HTTP URL, is shown below.

    require 'net/http'
    
    answer()
    say "hello world"
    transferResult = Net::HTTP.get_response(URI.parse("http://sipsorcery.com/callmanager.svc/blindtransfer?user=username&callid=#{$currentCall.callerID}&destination=1234")).body
    log transferResult
    say "http://202.6.74.107:8060/triplej.mp3" # Play some audio while transfer is being carried out.
    

    The new blindtransfer web service method takes three parameters:

    • user must be your sipsorcery username,
    • callid is used to identify the call leg that’s being transferred out of the call. Tropo doesn’t seem to provide much access to the incoming call headers so I’ve tailored the sipsorcery end to be able to look up the call leg based on the From header URI user. That’s why it needs to be set to something reasonably unique in your sipsorcery dialplan,
    • destination this is the value that will end up in the sipsorcery transfer dialplan as req.URI.User.

For once the whole thing is easier than it sounds and I think for those people already familiar with sipsorcery and Tropo it will be an easy job to use the new mechanism. The great thing about it is that there is now an elegant way to solve the challenge of allowing a user to dial in and enter or say their number and then dial that number out through a different provider.

  1. Luxxx’s avatar

    The new blindtransfer web service looks also like an interessting way to transfer calls from the desktop. But what i havn’t understand up to now, is how to specify the new destination in the URL.

    The other thing is how (un)secure this solution is. People could steel your calls, or connect you to their premium charged services…

    Possibly it would help, if the “uniqueidxxx” would be generated for each call, to make it really unique.

    Reply

    1. sipsorcery’s avatar

      Yes the security would need to be tightened up. The best way would be to sign the query string with a password or key. It wouldn’t be difficult to implement if the feature got enough use to warrant it (yes it’s a chicken and egg). It’s also the reason the transfer goes through a dedicated “transfer” dialplan and not a normal one. Only users that explicitly set up a transfer dial plan and are therefore aware of the blind transfer service will be affected. And while the security is lacking it would be a very good idea to leave the ability to forward to premium numbers out of the transfer dialplan!

      The unique ID can be generated on each call with in the Ruby dailplan that generates it. I think there is a Ruby random library that can be used failing that I’m sure there’s some pseudo-random way to do it.

      Reply

    2. Luxxx’s avatar

      Oh, Google Reader cutted the code. So i was not seeing the hole URL. Now i unserstand how to transmit the destination. 😉

      Reply

    3. Luxxx’s avatar

      I tried out now to transfer calls from the desktop. (scenario: somebody calls me, i take the call and want to transfer it.) The good thing: it works! The bad: With setting the FU parameter, i’m no longer able to see who is really calling me. So for this way of use, it would be nice, to have an alternative way instead of overwriting the caller ID.

      Reply

      1. sipsorcery’s avatar

        You don’t need to use the fu parameter, you can also use the SIP Call-ID header. If you are sending the call to your desktop then you’ll be able to get full access to the SIP headers. I included the fu mechanism for systems like tropo and cloudvox where the only information passed up about the incoming call is the caller ID.

        Reply

      2. dennis’s avatar

        Hi,

        http://sipsorcery.com/callmanager.svc does not work. It always redirect to sipsorcery website. I tried https://www.sipsorcery.com/callmanager.svc… , but ruby library on tropo missing ssl support and run into exceptions. Any idea?

        Reply

        1. sipsorcery’s avatar

          Since the sipsorcery web site has moved to Windows Azure the only URL option is now https://www.sipsorcery.com.callmanager.svc, I’ll update the article. In regards to the SSL support issue on Tropo it’s actually more of a Ruby issue but I’ve already been through that and you can see how to solve it at https://www.tropo.com/account/tickets/tickets.jsp?bb-cid=95&bb-tid=1096752&bb-name=tropo_support.

          Reply

        2. sipsorcery’s avatar

          Also worth a mention is that I found a better way to get access to the SIP headers in Tropo which alleviates the need to use the fu dial string option, see https://www.tropo.com/account/tickets/tickets.jsp?bb-cid=100&bb-tid=1108552&bb-name=tropo_support. I need to update the blog post for that as well.

          Reply

        3. dennis’s avatar

          Thanks Aaron,
          I will give the first method a try. At the same time Iam thinking the other work around. In Tropo script, instead of issue a https request, I can use call() to connect to one of my sipsorcery account, put my destination number as callerID. In my sipsorcery dial plan, upon receive this call I can reject this call and issue https for blind transfer. This would require ruby in sipsorcery to support https.
          In your second reply, if im right, you are looking for a way to send extra information between tropo and sipsorcery, that would be nice. for now since my dialplan know the uniqeID, i may not need it to be send back from tropo.
          Will this idea works?

          Dennis

          Reply

          1. sipsorcery’s avatar

            If I understand correctly the call() from Tropo approach won’t work. That’s essentially Tropo doing an attended transfer for you and means the media will stay on the Tropo servers, which is what I am trying to avoid with the blind transfer approach.

            That aside by placing a new call from Tropo to your sipsorcery dialplan you won’t be able to make any changes to your original sipsorcery call. Once a call gets answered the sipsorcery dialplan execution completes and from there becomes a SIP dialogue (providing it was answered with a 2xx response). After that the only way you can manipulate the established call using sipsorcery is with the callmanager.svc URL.

            Reply

          2. Mike Telis’s avatar

            I’m considering writing of a “call announcement” script, similar to Google Voice call announcement feature but it shouldn’t answer incoming call until I tell it so. Here is a scenario I’m looking for:

            Upon receipt of incoming call, my ATA starts ringing. I pick up the phone and I hear a message saying caller’s number. If I wish to talk, I press 1 and incoming call is connected. If I press any other key, the call is rejected.

            Note that on caller’s side, the call isn’t answered until I press 1 on my phone, so they don’t get charged while I’m thinking whether to accept the call or ditch it.

            Any idea of how this scenario could be implemented?

            Reply

            1. sipsorcery’s avatar

              Yes you need to use early media, it’s the SIP equivalent of the PSTN “the number you have called is not connectect” recorded message you receive when dialling an out of service number. It’s not actually answering the call but is instead replacing the ring tone that is normally played to the phone with the recorded messgae.

              The same question came up on the forums this morning, http://forum.sipsorcery.com/viewtopic.php?f=3&t=2435&start=10#p14959. In short I don’t know of any provider offering much in the way of early media services. I’ve used Asterisk to do early media in the past do it’s an option if you want to install your own server. Actually maybe Gizmo used to have a feature where you could customise the ringtone that was played to specific callers, that would be early media, I never used the feautre and I don’t know if they still have it.

              Reply

              1. Mike Telis’s avatar

                I don’t see how early media could help because it’s played on the caller’s end while I need to communicate with the callee.

                Anyway, I got the answer here:

                https://www.tropo.com/forums/?xt=1275245987638&&bb-cid=95&bb-statusBitToShow=0&bb-tid=1150164#bb

                but wasn’t quite satisfied with it. The problem is that the whole conversation is going to stay with Tropo and all the beauty of Sipsorcery’s blind transfer mechanism is gone 🙁 — I’ll get billed for the full length of the conversation.

                I’m thinking of this solution:

                1. Incoming call arrives to SS and forwarded to Tropo.
                2. Tropo initiates a new outbound call thru Sipsorcery, communicates with the callee.
                3. Tropo issues HTTP service request to Sipsorcery and SS binds two calls together, just like it does processing sys.GoogleVoiceCall request.

                Is it possible to implement?

                Reply

              2. sipsorcery’s avatar

                I’ve implemented a new method on the callmanager service. It’s called using:

                https://www.sipsorcery.com/callmanager.svc/dualtransfer?user=your-username&callid1=Tropo-CallID1&callid2=Tropo-CallID2

                The two tropo Call-ID’s need to match the Call-ID headers that the sipsorcery server gets. The dual transfer method will then bridge together the other end of both those calls and then hang up the two tropo calls.

                Reply

                1. Mike Telis’s avatar

                  Thanks for your prompt response! Have you tried this new mechanism? I’m wondering if I need to open a new Tropo session for outbound call or the whole procedure can be managed within the same session, like this:

                  call “sip:#{number}.mydialSIP@sipsorcery.com”, {
                  :callerID=>callerID,
                  :onAnswer=>lambda{|event|
                  newCall = event.value
                  }
                  }

                  # communicate with the callee

                  answer

                  # perform dual-transfer on $currentCall and newCall

                  Yet another thing: do I actually need to “answer” incoming call in Tropo script or dual-transfer will work without it?

                  Reply

                2. sipsorcery’s avatar

                  I haven’t tried it with tropo calls but I have with two ordinary sipsorcery calls and it works well. I don’t know how you get the Call-ID from a call that’s originated from tropo as I’ve never had a need to do that.

                  Theoretically a call control method could leave the initial call unanswered and then bridge it with the second answered call, which as you mention above would be the same as a GoogleVoice callback. You’d still need to be able to get the Call-ID of the call you are originating from tropo so if you can get the dualtransfer method working to your satisfaction let me know and I’ll see about coming up with a tranfer method for an unanswered call leg (which I guess isn’t really a transfer but I don’t know what else to call it).

                  Reply

                  1. Mike Telis’s avatar

                    > You’d still need to be able to get the Call-ID of the call you are originating from tropo …

                    So far, I’m having problems with that. It seems like the call() method in Tropo only responds to :callerID parameter, I couldn’t even change the name. I’ve opened a ticket, let’s see what Tropo support says.

                    Reply

                  2. Jose de Castro’s avatar

                    Hello,

                    Thanks for the kind words regarding Tropo. We’re hard at work on features including a RESTful Provisioning API, Reporting and some API additional that will make coding for Tropo even better than it is now.

                    As for our blind transfer capabilities, I’m happy to announce that we’re adding first class support for SIP Refer as early as next week. Please subscribe to our RSS feed for more info, announcements such as this and random updates on Tropo and other Voxeo Labs initiatives.

                    RSS: http://blog.tropo.com/feed

                    Thanks for the support,

                    Jose de Castro
                    Chief Architect
                    Voxeo Labs
                    @loopingrage

                    Reply

                    1. sipsorcery’s avatar

                      Hi Jose,

                      That’s fanatastic news. I’m already subscribed to the Tropo RSS feed so I’ll be waiting with eager anticipation.

                      Aaron

                      Reply

Reply

Your email address will not be published. Required fields are marked *