Posted on by No comments yet

LinkedInGoogle+TwitterFacebook

Using Tropo’s Scripting API and Ruby, I wrote a clever little script that allows you to automatically return missed calls from people as soon as you hang up a phone call.

Here is the use case:

  • User A calls user B
  • While users A and B talking, user C calls user B
  • Tropo script records the missed user C call and returns their call after B hangs up. The Tropo script automatically calls users B and C and bridges them in a conference call.

Here is a video to help demonstrate the concept:

Here is the Ruby script using Iris Couch as a JSON datastore directly from the Tropo cloud!

require 'rubygems'
require 'net/http'
require 'json'

# Setup couchdb JSON datastore calls
module Couch

class Server
def initialize(host, port, options = nil)
@host = host
@port = port
@options = options
end

def delete(uri)
request(Net::HTTP::Delete.new(uri))
end

def get(uri)
request(Net::HTTP::Get.new(uri))
end

def put(uri, json)
req = Net::HTTP::Put.new(uri)
req["content-type"] = "application/json"
req.body = json
request(req)
end

def post(uri, json)
req = Net::HTTP::Post.new(uri)
req["content-type"] = "application/json"
req.body = json
request(req)
end

def request(req)
res = Net::HTTP.start(@host, @port) { |http|http.request(req) }
unless res.kind_of?(Net::HTTPSuccess)
handle_error(req, res)
end
res
end

private

def handle_error(req, res)
e = RuntimeError.new("#{res.code}:#{res.message}nMETHOD:#{req.method}nURI:#{req.path}n#{res.body}")
raise e
end
end
end

# define couchdb server name
server = Couch::Server.new("tropo.couchone.com", "80")

# get callerid
callerid = $currentCall.callerID
if callerid.length == 10
callerid = "1" + callerid
end

say "welcome to tropo's call back demo"

ask "Please enter the country code and phone number of the person you are trying to reach followed by the pound sign.", {
:choices => "[8-15 DIGITS]",
:terminator => '#',
:timeout => 15.0,
:mode => "dtmf",
:interdigitTimeout => 5 ,
:onChoice => lambda { |event|

target = event.value

# check to see if record exists indicating that the called party is on another call
res = server.get("/callerback/" + target) rescue nil
jsonresp = res.body rescue nil

# phone number record will exist if called party is on the phone
if jsonresp

# if on the phone, write number to return call when available
postcallback = server.put("/callerback/" + target + "q", '{"phone":' + callerid + '}') rescue nil
say target + " is on the phone now but will return your call shortly."
hangup

else

# transfer call
say "Please wait while we transfer your call. Press star to cancel the transfer."

# write record to show that the dialed party is unavailable
postoncall = server.put("/callerback/" + target, "{}") rescue nil

# transfer call
transfer target, {
:playvalue => "http://www.phono.com/audio/holdmusic.mp3",
:terminator => "*",
:onTimeout => lambda { |event|
# no answer
say "Sorry, but nobody answered at " + target.to_s + " please try again later."
hangup
}
}

# Transfer blocks. The code below will not be executed until the transferred call completed.

# find and delete current called party record
getcurrentrec = server.get("/callerback/" + target) rescue nil
jsongetcurrentrec = getcurrentrec.body rescue nil
currentdata = JSON.parse(jsongetcurrentrec)
deletecurrent = server.delete("/callerback/" + target + "?rev=" + currentdata["_rev"].to_s )

# check to see if a number exists to callback and delete it
getcallback = server.get("/callerback/" + target + "q") rescue nil
jsoncallback = getcallback.body rescue nil

# If someone called while we were on the phone, let's call them back!
if jsoncallback

# find and delete their callback number
callbackdata = JSON.parse(jsoncallback)
callerid = callbackdata["phone"]
deletecallback = server.delete("/callerback/" + target + "q?rev=" + callbackdata["_rev"].to_s )

# Call the 2 numbers and bridge the new call using conference

# create unique conference room based on timestamp
timeVar = Time.new
conferenceID = timeVar.strftime("%Y%H%M%S")

# set conference options
conferenceOptions={
:mute=>false,
:playTones=>true,
:leaveprompt=>"beep"
}

threads = []

# Call First Leg (User)
call 'tel:+' + target, {
:callerID => callerid.to_s,
:onAnswer => lambda{|event|
log "@"*5 + "User has answered"

#Create second thread for second leg (Operator)
threads << Thread.new do
log "@"*5 + "Start second thread"
call 'tel:+' + callerid.to_s, {
:callerID=>target.to_s,
:onAnswer=>lambda{|confevent|
log "@"*5+"Operator answered join conference"
newCall2 = confevent.value
#announce caller
newCall2.say("You have a call from " + target.to_s)
#join operator to conference
newCall2.conference(conferenceID,conferenceOptions)
}
}
end #thread

newCall = event.value
newCall.say("Please hold while we connect you to " + callerid.to_s)
newCall.conference(conferenceID,conferenceOptions)

}
}

threads.each { |t| t.join }

end #jsoncallback

end #jsonresp

},
:onBadChoice => lambda { |event|
say "We did not recognize that phone number"
}
}

Leave a Reply

  • (will not be published)