0

I'm using the Twilio JavaScript Voice SDK and TwiML App handled by PHP to make an outbound voice call.

My first implementation was to dial the number directly..

Client side...

    device.connect({
        params: {
            callee_name: name,
            callee_number: phoneNumber,
        }   
    }).then((call) => {
        call.on('accept', (acceptedCall) => {
            console.log('in accept');
            let callSid = acceptedCall.parameters.CallSid;
        });
    });

Server side...

    $voiceResponse = new VoiceResponse;
    $dial = $voiceResponse->dial('', ['callerId' => $callerId]);
    $dial->number($calleeNumber,[
         'statusCallbackEvent' => 'initiated ringing answered completed',
         'statusCallback' => $statusCallbackUrl
    ]);
    $xml = $voiceResponse->asXml();
    $response = new Response($xml, Response::HTTP_OK, ['context-type' => 'text/xml']);
    return $response;

This works fine. With this approach, however, capabilities such as call forwarding, coaching and many others are simply not possible. To get access to these capabilities I have to put the call into a conference. So one approach is put the call into conference when I need those functions. However, as noted in this answer https://stackoverflow.com/a/22919470/7422838 it is best to put the outbound call in conference from the start. So, for example, if your are recording the call, the recording will not be in two pieces when you put the call in conference.

So how to do this? My current approach is this:

Client side...

    device.connect({
        params: {
            callee_name: name,
            callee_number: phoneNumber,
        }   
    }).then((call) => {
        call.on('accept', (acceptedCall) => {
            let callSid = acceptedCall.parameters.CallSid;
            $.ajax({
                url: dialFromConferenceUrl,
                data: {
                    call_sid: callSid,
                    callee_name: name,
                    callee_number: phoneNumber,
                }
            });
        });
    });

Server side, in the voice.XML callback

    $voiceResponse = new VoiceResponse;
    $dial = $voiceResponse->dial('', ['callerId' => $callerId]);
    $dial->conference($conferenceSid,[
         'statusCallbackEvent' => 'start end join leave mute hold',
         'statusCallback' => $statusCallbackUrl
    ]);
    $xml = $voiceResponse->asXml();
    $response = new Response($xml, Response::HTTP_OK, ['context-type' => 'text/xml']);
    return $response;

Server side, in the call from conference handler...

$client->conferences($conferenceSid)
     ->participants
     ->create($mainPhone,$calleePhone
     [
          'label' => $calleeType,
          'statusCallback' => $conferenceStatusUrl,
          'statusCallbackEvent' => ['initiated', 'ringing', 'answered', 'completed']
      ]);

So all this works, but it seems very inelegant and klugey. I'm making 2 server round trips to do, from the client's perspective, a single operation: make an outbound call through a conference room. Sure there are multiple components to this operation: (1) create conference room; (2) connect client to conference room; (3) dial 2nd party and add as participant to conference room. But why can't all of these component operations be done server-side, with a single query from the client?

I suspect they can be, which is why I am asking this question.

AQuirky
  • 4,691
  • 2
  • 32
  • 51

1 Answers1

1

There are two approaches I can suggest.

The first one is you can dial the callee on the 'twiml XML fetch request' itself, which may lead to dail the callee before the caller joins the conference.

The second one is you can pass an extra argument with the statusCallback URL. In that way, you can identify the join event of the caller channel. And when the caller channel joins the conference you can dial the callee.

Both will avoid an extra request from the client, I think that's your main concern. And second approach will ensure the caller is in the conference before dialing the callee.

Anees Sadeek
  • 168
  • 1
  • 10
  • Not following. Dial the callee on the twilml XML fetch request? Do you mean add another Dial verb to the XML document? This cannot work. Do you mean use the API to dial the caller. If so this would mean dialing the caller in the context of the GET request. Ug. Need less klugey rather than more. Your second idea is better (at least it is in a POST request) and indeed I do a bunch of stuff in status callbacks...so much so that it starts looking like good code. I've come to the conclusion that there is no Twilio implementation that is not a bag of hammers approach. – AQuirky May 10 '23 at 22:21
  • Sry I missed your comment. Yes, you are right, you can't pass the dial agent and conference through the XML document. I mentioned the call-create API only. The only difference between the two approaches is the triggering point of the call-create API. I'm using the second approach only to ensure the Caller is there before dialing Callee, but in my understanding, both requests are POST only. I've removed all the Twilio GET routes from my app, am I missing something here? – Anees Sadeek Jun 13 '23 at 06:56