putting an outgoing call from a twilio client to a phone on hold(Get phone side call Sid) - twilio

I am trying to implement 'hold call' functionality into my system. I have looked at this question and some twilio docs, and recommended way to do this is to dequeue the call, which will automatically play the hold music, and then retrieve from queue when hold is complete(un-hold).
This works perfectly fine, when I have an incoming call from a mobile, to my twilio client, and I can dequeue the call, and all works fine.
However when I do it with the outgoing call from the twilio client to the mobile, if I update the call to issue dequeue instruction, I get to hear the hold music on the client side itself, and the phone gets disconnected. I suppose this is because I have set the client leg of the call on hold. So the question is how do I get the call sid for the mobile leg of the call.
I have tried querying CallResource by ParentCallId, but that does not return anything in the case of outgoing calls. Any ideas?
Call is initiated on the client with:
var params = {
To: num
};
console.log('Calling ' + num + '...');
Twilio.Device.connect(params);
The connect API callback uses a simple Dial verb.
Client code for saving callid on connect:
Twilio.Device.connect(function (conn) {
if (conn._direction === 'OUTGOING') {
$scope.outgoing_call_sid = conn.parameters.CallSid;
$scope.number = conn.message.To;
} else {
$scope.incoming_call_sid = conn.parameters.CallSid;
$scope.number = conn.parameters.From;
}
$scope.message = 'In call with ' + $scope.number;
$scope.status = 'InCall';
});
Client code on hold button click:
$scope.hold = function () {
$scope.status = 'Hold';
$scope.message = 'Putting on hold...';
if ($scope.outgoing_call_sid) {
return $http.get(serviceBase + 'api/twilio/hold?callid=' + $scope.outgoing_call_sid);
}
};
Server side Hold API call:
public IHttpActionResult Hold(string callid) { /
//callid = GetLegCallId(callid); //Try to replace with child call
CallResource.Update(new UpdateCallOptions(callid) { Url = ConfigurationManager.AppSettings["ngrokUrl"] + "/api/twilio/enqueue", Method = HttpMethod.Get });
return Ok();
}
Code for getting any child calls:
public string GetLegCallId(string callId)
{
var calls = CallResource.Read(new ReadCallOptions() { ParentCallSid = callId });
if (calls.GetEnumerator().Current != null)
return calls.GetEnumerator().Current.Sid;
}

My bad. Twilio wasnt the issue. Issue was with usage of calls.GetEnumerator().Current != null.
Should do MoveNext on the Enumerator, before Current will have a value. Resolved by doing that. Stupid:(

Related

How do I get a Twilio function to continue a call and return gather information

I have a studio flow that I am attempting to handle multiple different languages. I have a widget that starts the call and then passes it over to my function. However, after making the call and moving to the function, the call instantly ends. Am I doing something incorrect? From what I understand, I can send the call to a function to continue it. Is something wrong with my function? See my function code below.
exports.handler = function(context, event, callback) {
let twiml = new Twilio.twiml.VoiceResponse();
const gatherOptions = { Numdigit:"1", Timeout:"5"};
let sayOptions = { Voice:"Alice", Language: event.Language };
if(!event.Retries){
event.Retries = 0;
}
console.log(event.Language);
console.log(event.Body);
if (event.Digits) {
if(event.Digits === '9' && event.Retries < 3) {
event.Retries += 1;
twiml.gather(gatherOptions).say(sayOptions, event.Body);
} else if(event.Digits === '3' || event.Digits === '5'){
return callback(null, twiml);
}else {
twiml.say("sorry, I didnt get that.");
event.Digits = '9';
}
} else {
twiml.gather(gatherOptions).say(sayOptions, event.Body);
}
callback(null, twiml);
};
Outside of your Twilio Function code, anytime you jump out of Studio and return TwiML and then want to return to the Studio flow, you must use the TwiML Redirect Widget (which you can use to call the Twilio Function).
Your gatherOptions keys should be camelCase (i.e. numDigits, timeout).
This may be useful to carry state across Functions.
How to Share Information Between Your Applications

Twilio-Client always returns connection status as open on outbound call even if the recipient has not accepted the call yet

I am trying to get the status of outbound call made through Twilio Client(js) v 1.10.1. But the .status() method returns the value as "open" even if the call is in ringing state. I tried adding enableRingingState: true as a parameter while initializing the Twilio.Device and also set the answerOnBridge="true" while creating the TwiMl Dial verb at server side.
As per the official documentation, js sdk should be returning these status "pending", "connecting", "ringing", "open", "closed".
This is required to showing "calling..." until the call is picked and start the timer(mm:ss) in my dialer in browser as soon the call is picked.
Note: Tried the same with Twilio's Quickstart guide code as well.
/**** Pseudo Code is like below ***/
// FRONT END CODE
let device = require('twilio-client').Device;
let outboundCall = '';
const twilioInit = () => {
// axios call to get capability {token} from service
device = device.setup(token,
{
allowIncomingWhileBusy: true,
enableRingingState: true
});
device.ready(function () {
console.log("Twilio ready");
device.identity = "Ratan";
console.log("Twilio Device ", device);
});
device.error(function (error) {
console.log("error in twilio ", error);
if (error.message == "JWT Token Expired") {
alert("token expired");
}
// If token has expired, dispatch an action to get new token.
});
}
// on phone icon click i am calling the below method
const makeOutboundCall = () => {
outboundCall = device.connect({
To: '+911234567890' // This is not the real phone number, I use number from list of Twilio verified numbers
});
outboundCall.on('ringing', function (hasEarlyMedia) {
console.log("ringing");
});
// Then tracking the status of this outboundCall object in setInterval function with a interval of one second by outboundCall.status() and clearing the..
// ..setInterval once the call disconnects
}
// BACK END CODE - SERVER SIDE (WEBHOOK)
#RequestMapping(value="/callCustomers", produces= "text/xml")
public String callByBrowserToMobile(#RequestParam String ApplicationSid, #RequestParam String ApiVersion,
#RequestParam String Called, #RequestParam String Caller,
#RequestParam String CallStatus, #RequestParam String To,
#RequestParam String From, #RequestParam String CallSid,
#RequestParam String Direction, #RequestParam String AccountSid) {
Number number = new Number.Builder(To).build();
Dial dial = new Dial.Builder().answerOnBridge(true).number(number).callerId(myTwilioNumber).build();
VoiceResponse response = new VoiceResponse.Builder().dial(dial).build();
logger.info(response.toXml());
return response.toXml();
}
The call is placed correctly but the issue is only with tracking outbound call status with twilio js library so that i can start call timer in UI once the call is picked by recipient.
Twilio developer evangelist here.
Edit: Found out what the issue was
When using <Dial answerOnBridge="true"> to make the ringing events available, the <Dial> needs to be the first TwiML that Twilio sees when it starts the call. When you are using a free trial account Twilio plays a message at the start of the call which acts as the first TwiML that is seen, so the answerOnBridge attribute doesn't take effect and you don't get the ringing events as you'd expect.
To fix this particular issue you will need to upgrade your account so that Twilio no longer reads out the trial account message at the start of the call.
Original answer:
I wouldn't use setInterval to poll the status of the call. Instead, I would listen to the events on the connection object. So your makeOutboundCall function should look a bit like this:
const makeOutboundCall = () => {
outboundCall = device.connect({
To: TO_NUMBER
});
outboundCall.on("ringing", (hasEarlyMedia) => {
console.log("The call has started and the other phone is ringing.");
});
outboundCall.on("accept", (connection) => {
console.log("The other person answered the phone!");
});
outboundCall.on("disconnect", () => {
console.log("The other person hung up.");
});
}
Let me know if that helps at all.

How do I set custom parameters for Twilio TVOCallInvite on iOS?

I'm trying to pass custom parameters in call invite structure but don't receive them on the recipient side.
let connectOptions: TVOConnectOptions = TVOConnectOptions(accessToken: token) { (builder) in
builder.params = ["To": "Recipeint Id",
"From": "Caller name"]
builder.uuid = uuid
}
self.call = TwilioVoice.connect(with: connectOptions, delegate: self)
Any ideas?
You need to add logic in backend or you can say server code for the same.
Link for server code in node
https://github.com/twilio/voice-quickstart-server-node
need to modify below function
function makeCall(request, response) {
// The recipient of the call, a phone number or a client
var to = null;
if (request.method == 'POST') {
to = request.body.to;
callerId = request.body.from; //--> new added line for caller name
} else {
to = request.query.to;
callerId = request.body.from; //--> new added line for caller name
}
const voiceResponse = new VoiceResponse();
if (!to) {
voiceResponse.say("Congratulations! You have made your first call! Good bye.");
} else if (isNumber(to)) {
const dial = voiceResponse.dial({callerId : callerNumber});
dial.number(to);
} else {
const dial = voiceResponse.dial({callerId : callerId});
dial.client(to);
}
console.log('Response:' + voiceResponse.toString());
return response.send(voiceResponse.toString());
}
also need make var instead of const for callerId variable , and If you are passing caller name then node code format should save value in this format
'client:callername'
i.e. client: and after that value which is being passed from iOS app
Gave up actually with this idea... Followed this instruction so that the app reports a call to CallKit and then updates the caller name after that.

Unable to join chat channel

When trying to join a channel in the twilio code I've been working with, it comes up with the error saying that it "Cannot read property 'getChannelByUniqueName' of null". The chat works but when I try to open it up on a different browser, like firefox instead of chrome, it says the error "Channel with provided unique name already exist". Can anyone help with this problem?
// Initialize the Chat client
chatClient = new Twilio.Chat.Client(data.token);
joinChannels(chatClient);
});
function joinChannels(chatClient) {
chatClient.getSubscribedChannels();
joinChannel('generalss','Generals Chat Channel');
}
function joinChannel(channelName, channelFriendlyName) {
console.log(channelName);
console.log(chatClient);
print('Attempting to join "' + channelName + '" chat channel...');
var promise = chatClient.getChannelByUniqueName(channelName);
promise.then(function(channel) {
console.log('Found ' + channelName + ' channel:');
channels[channelName] = channel;
console.log(channels);
setupChannel();
}).catch(function() {
// If it doesn't exist, let's create it
chatClient.createChannel({
uniqueName: channelName,
friendlyName: channelFriendlyName
}).then(function(channel) {
channels[channelName] = channel;
setupChannel(channelName);
});
});
}
Twilio developer evangelist here.
It looks to me like you aren't passing the chatClient to your joinChannel method (and secondly that the client might not be fully initialised yet).
I would initialise the client with the following, which uses the create method that returns a promise that resolves when the Client is ready.
// Initialize the Chat client
new Twilio.Chat.Client.create(data.token).then(function(chatClient) {
joinChannels(chatClient);
});
});
Then, make sure you pass the client through to the joinChannel method:
function joinChannels(chatClient) {
chatClient.getSubscribedChannels();
joinChannel(chatClient, 'generalss','Generals Chat Channel');
}
function joinChannel(chatClient, channelName, channelFriendlyName) {
// the rest...
}
Let me know if that helps at all.

Laravel PubSubHubbub i have subscribed but couldn't receive updates

I am trying to get real time feed updates using the Pubsubhubbup and Laravel, i have created 2 functions one for subscribe and the other one is a callback function.
when the subscribe function called it worked and the callback function receives a confirmation from the hub and respond with the hub_challenge code, all this works OK but the callback function doesn't receive any feed updates after that although it should receive it from the hub when there are updates but this is not happen !!
can you help to find what is the problem ??
thanks for your time.
the functions
public function subscribe(Feed $feed)
{
$hub_url = "http://pubsubhubbub.appspot.com";
$callback_url = url('feed/getFeedUpdates');
$subscriber = new Subscriber($hub_url, $callback_url);
$subscriber->subscribe($feed->feed_url);
Flash::success('Feed has been saved.');
return redirect('feed');
}
public function getFeedUpdates(Request $request)
{
// Subscribe Confirmation
if ($request->has('hub_mode') && $request->hub_mode == 'subscribe') {
$response = new Response($request->hub_challenge, 200);
$response->header('Content-Type', 'text/plain');
return $response;
} else { // Receive Updates
$updates = file_get_contents("php://input");
// put the updates to the database
}
}

Resources