I have implemented Twilio Voice JS SDK to make/receive outgoing/incoming calls from within browser.
Using the status callbacks, I get to know when the call was initiated, ringing, in progress and completed.
However, I am not able to find and record which user made/answered a call (All users have different log id and different client identity id).
When the Incoming call is received, incoming event is triggered on voice client (browser), however, there is no call information availale (call SID etc) to record it.
Similarly, when an outgoing call is made, Call SID information is not available.
Code for incoming calls and to record callsid
device.on("incoming", handleIncomingCall);
function handleIncomingCall(call) {
try{
console.log(call.properties.CallSid);
}
catch (err)
{
console.log("An error occurred while retrieving callsid properties from call object.");
}
//show incoming call div
incomingCallDiv.classList.remove("d-none");
//add event listeners for Accept, Reject, and Hangup buttons
incomingCallAcceptButton.onclick = () => {
acceptIncomingCall(call);
};
incomingCallRejectButton.onclick = () => {
rejectIncomingCall(call);
};
incomingCallHangupButton.onclick = () => {
hangupIncomingCall(call);
};
}
Message that I am getting in the console
An error occurred while retrieving callsid properties from call object.
When you make an outgoing call or recive an incoming call event with the Twilio Voice SDK, the Call object has a parameters property that contains the call parameters you would also receive via the webhook.
So, if you are placing an outgoing call, you can get the call Sid like this:
const device = new Device(token);
const call = await device.connect(options);
console.log(call.parameters.CallSid);
Or if you are receiving a call:
const device = new Device(token);
device.on("incoming", call => {
console.log(call.parameters.CallSid);
})
Note that the CallSid you receive here will not match the outbound CallSid to a another phone when placing an outbound call, and will not match the inbound CallSid when receiving the call. Twilio calls between two people (or phone numbers or clients) have a leg for each connection between Twilio and that person, with a different Call Sid for each leg. You can connect the calls together by understanding the call parent. If you are receiving an incoming call, the parent call is the inbound leg. If you are placing an outgoing call, the parent call is that outbound leg. You can list calls and filter by the parent call Sid using the API.
Related
I'm trying to create an interactive dashboard that shows Twilio calls with the ability to listen to any ongoing calls. Is it possible? And what is the best approach I should take?
I saw two methods on the documentation which are Twiml Voice: and Twiml Voice: . Conference doesn't suit with my scenario because incoming calls are not ringing. And I couldn't find a way to listen to voice Streams on the documentation.
Note: Currently inbound calls are handled by Twilio function and WebSocket and outbound calls are handled by Twilio JavaScript SDK.
Thanks in advance.
If you want to listen to a live Voicecall you could try the Stream as IObert suggests. Or, you must use the Conference feature and add yourself as a "Coach." Don't be put off by the name Conference. Think of it as a Voicecall with many more helpful features. You can create a conference from an outbound call like this:
string accountSid = "ACxxxxxx";
string authToken = "xxxxx";
TwilioClient.Init(accountSid, authToken);
var voiceresponse = new VoiceResponse();
var say = new Say("Setting up your conference.");
var dialConference = new Dial();
dialConference.Conference(
name: "Your Conference"
startConferenceOnEnter: true,
endConferenceOnExit: true
);
voiceresponse.Append(say);
voiceresponse.Append(dialConference);
var twiml = voiceresponse.ToString();
var call = CallResource.Create(
twiml: new Twilio.Types.Twiml(twiml),
to: new Twilio.Types.PhoneNumber("E164 Number to Dial"),
from: new Twilio.Types.PhoneNumber("E164 Your Twilio Number")
);
Then once you have a conference started, you can add the second call from either an inbound or outbound call. With an inbound call, use Twiml to send the call to the conference. With an outbound call, use the REST API to add a Conference Participant.
From the client side, using the Twilio Javascript Client, you would then connect your device to the Conference with the correct Conference Twiml parameters which is explained here:
https://www.twilio.com/docs/voice/sdks/javascript/twiliodevice#deviceconnectconnectoptions
const device = new Device(token);
let call = await device.connect({
params: {
To: 'Your Conference'
}
});
I use a slightly different method...I use a button on the client that when you click it makes an outbound call to the "coach" using the Conference Participant REST API. The coach answers and is added with mute = true. The "coach" uses the Twilio Client for WebRTC but the same process will work with a "regular" phone line with a phone number. Using the Twilio Client in this way allows the coach to listen on their computer speakers which is convenient.
The harder part is you will need to keep track of which calls are active on the client side. Otherwise, you won't have an accurate list of which calls or conferences are active. Repeatedly polling the Twilio REST API for active calls is not recommended by Twilio and is super slow compared to using the webhooks to notify of call status changes.
I am trying to create a voice call from twilio to a number using programmable voice.
I also intend to gather recipient's speech transcribed. However, the documentation contains examples and tutorials only for inbound voice calls.
This is what I have tried-
Initiating voice call:
client.calls
.create({
twiml: `<Response><Gather input="speech" action="https://ngrok-url-for-my-local-server/voice" method="POST" speechTimeout="5"><Say>Hey there, How are you?</Say><Pause length="4" /></Gather></Response>`,
to: toPhoneNumber,
from: myPhoneNumber,
})
.then((call) => {
console.log(call.sid)
console.log(call)
})
.catch((e) => {
console.log(e)
})
Code in handler for gathering speech-
const VoiceResponse = twiml.VoiceResponse
const res = new VoiceResponse()
res.gather()
console.log(res.toString())
However I am not getting anything useful in the console.
Can anybody point me to a useful tutorial or example or tell me what I should do ?
You need to first make the call and then modify the call to gather.
When you make the call using the new VoiceResponse() call you will be returned a SID for the call. Next, use that SID to modify a call that is in progress by redirecting to the Twiml to gather the digits.
You will have three legs:
Make the outbound call (you provided this code in your questions).
Modify the active outbound call by using the call's SID to redirect to a Gather twiml.
After the gather has finished tell the call what do to using the action parameter of the gather. Here is an example.
If you are trying to go for a conference bridge type feature where you press * to move into an admin type menu, you will need a more complex solution involving a conference call.
I'm using an incoming call flow that starts call recording, asks a bunch of questions, gathers responses, at the end of the call: stops recording and sends a sms to caller using send/wait for reply widget. A response is expected and based on what's in the body of the incoming call, it calls a function.
All this works, except, I am not receiving a response back from the caller.
My concurrent call setting =off
incoming trigger = incoming call
the flow is tied to a phone number (voice)
I'm not sure how to get a reply back into the same flow. Do I need to attach something to the message section of the phone number?
Any guidance would be appreciated
A Studio flow execution represents one call, one SMS, or the incoming call trigger from the REST Trigger. As the call initiates your flow, it will terminate when the call ends.
But you can work around this by using a function that gets invoked when the recording is done. This function can then use the Twilio APIs to fetch contextual information from the call and trigger the REST API interface of the same flow (but with a different trigger).
I created a small example that does something similar:
The flow is triggered by a call, starts a recording, and gathers data
There is a recording callback URL that points to my function
// This is your new function. To start, set the name and path on the left.
exports.handler = function (context, event, callback) {
console.log(`Recording ${event.RecordingSid} state changed to ${event.RecordingStatus}.`)
if (event.RecordingStatus === "completed") {
const client = context.getTwilioClient();
return client.calls(event.CallSid).fetch()
.then(call => {
client.studio.v2.flows(<Flow ID>)
.executions
.create({
to: call.from,
from: <YOUR NUMBER>,
parameters: {
RecordingUrl: event.RecordingUrl,
}
})
.then(execution => {
console.log(`Triggered execution ${execution.sid}`)
return callback(null, "OK");
});
})
.catch(callback)
}
return callback(null, "OK");
};
You can find the ID of your flow in the console (or when you click on the root element and check the Flow Configuration):
The REST API triggers a second flow execution that reads the parameter and uses them to send a text message:
I have successfully implemented Voice calls functionality in my php application using JS SDK.
Now, I need to implement Call Monitoring and barge in features, that I believe are only available using Twilio Conference.
My current code looks like
$response = new VoiceResponse();
$dial = $response->dial('');
//If Incoming call, redirect the call to my browser client
if($phonenumber == $mytwiliophonenumber)
{
$dial->client($browserclientname);
}
//If outgoing, make the call to the phone number
else
{
$dial->number($phonenumber);
}
Now, what is the easiest way to change this to conference?
I have read that I need to dial the conference, but it is not working.
$dial->conference('anyconferencename');
Any guidance?
A conference has a fundamental difference to connecting two callers together in a regular dial. A conference acts as a room that participants join individually, rather than when you use client or number which places an outbound call leg to the client or number you are dialling.
If you have your user dial into a conference using $dial->conference you will need to create another leg to call the other person into the conference too. You can do this using the conference participants API.
So, instead of your current code, you could update to something like this:
$response = new VoiceResponse();
$dial = $response->dial('');
//If Incoming call, redirect the call to my browser client
if($phonenumber == $mytwiliophonenumber)
{
$participant = "client:" . $browserclientname;
}
//If outgoing, make the call to the phone number
else
{
$participant = $phonenumber;
}
$conferenceName = 'conferencename';
$twilio->conferences($conferenceName)
->participants
->create($mytwiliophonenumber, // from
$participant, // to
);
$dial->conference($conferenceName);
In this option, regardless of whether the call is inbound or outbound, the caller is placed in a conference call. And another call is generated to add the other participant to the conference call too.
The code below intercepts a call in progress and transfer the call to a new number (This piece works as expected).
The question is:
Should I mark the original call as "completed"
How do I do this?
$call_sid = $_SESSION['CallSid'];
$sid = 'xxxxxxxxxxxxxxxxxxxxxxx';
$token = 'xxxxxxxxxxxxxxxxxxxxxxx';
$twilio = new \Twilio\Rest\Client($sid, $token);
$call = $twilio->calls($call_sid)->update(['twiml' => '<Response><Say>Redirecting to Buba</Say><Dial callerId="+18888880592">+14888068886</Dial></Response>']);
//TODO cancel this CALL SID. Status=completed??
print($call->to);
The Twilio call legs are kept up via Twilio Markup Language (TwiML). If you modify one call leg which appears to be what you are doing, if there is another call leg (no conference involved) that is part of that call, that leg will begin processing any TwiML after the <Dial> that originally connected the two parties. If there is no TwiML after the <Dial>, Twilio will hangup that call leg, so no action required on your side.
You should be able to see this behavior in your call logs.