Home > Software engineering >  How to leave a voicemail using Twilio AMD?
How to leave a voicemail using Twilio AMD?

Time:11-10

Given client code that makes an outgoing call like this:

var accountSid = configuration["accountSid"];
        var authToken = configuration["authToken"];

        TwilioClient.Init(accountSid, authToken);

        var call = CallResource.Create(
            machineDetection: "DetectMessageEnd",
            asyncAmd: "true",
            asyncAmdStatusCallback: new Uri("[URL]/callback/index"),
            asyncAmdStatusCallbackMethod: HttpMethod.Post,
            twiml: new Twilio.Types.Twiml("<Response><Say>Ahoy there!</Say></Response>"),
            from: new Twilio.Types.PhoneNumber(configuration["fromPhoneNumber"]),
            to: new Twilio.Types.PhoneNumber(configuration["toPhoneNumber"])
        );

aka, asyncAmd is enabled and callback URL is specified, with my webhook controller action that looks like this:

[ApiController]
[Route("callback")]
public class CallbackController : TwilioController
{
    [HttpPost]
    [Route("index")]
    public IActionResult Index()
    {
        var response = new VoiceResponse();

        if (Request.Form.TryGetValue("AnsweredBy", out var answeredBy))
        {
            if (answeredBy != "human")
            {
                response.Say("this is the voice message");
            }
        }

        return Content(response.ToString(), "text/xml");
    }
}

why is it there is no voicemail being left?

Note: I am including the Twiml I want to say in CallResource.Create b/c I don't want a callback to get the message contents in case of a human answering.

I only need the callback performed for the results of AMD detection, and then to leave a voice message.

Do I do that with response.Say?

Thanks!

CodePudding user response:

Twilio developer evangelist here.

Twilio answering machine detection can happen in synchronous or asynchronous mode. From this blog post:

With Async AMD on Twilio, AMD is done asynchronously (hence the name). When the call is answered, a call url is executed immediately, so if a person answers the call rather than voicemail, they can begin interacting with your application without any silence. Then “asynchronously”, or “in parallel”, AMD processes the call audio and determines what answered the call. When AMD processing is complete, the result (the AnsweredBy parameter) is sent to a second URL, the asyncAmdStatusCallback.

One key difference between standard AMD and async AMD is how you modify the call once receiving the AMD result. With standard AMD, you have one URL and the result is sent to this URL just like any other outbound-api call. When your URL receives the result, you can check the AnsweredBy parameter and update the call accordingly with TwiML. With Async AMD, your call is already executing TwiML and you instead need to update the call via API.

In your case you are using async AMD, but you are not updating the call via the API.

You have two options. You can choose to use synchronous AMD and you can then respond to the result using TwiML like you are doing so far.

Alternatively, you can continue to use async AMD, but instead of responding to the webhook with TwiML, use the REST API to update the call with the new TwiML or with a new webhook URL.

One thing I would look out for too. Your initial TwiML is very short, your example code shows that it sends <Response><Say>Ahoy there!</Say></Response>. It is entirely possible that this TwiML will be completed before an answering machine is detected and since it is the only TwiML for the call, the call would then hang up. You may want to consider using a longer message or pausing so that you can get the result of the AMD.

CodePudding user response:

Figured I'd follow up here. Thanks @philnash for the help. You were indeed right

  • I was returning Twiml from the asyncAMD webhook instead of updating the call.
  • my very short Twiml in the initiating call was not long enough

I got through the first part and things were still failing even with Twiml that was longer:

<Response><Say>Hello there. This is a longer message that will be about as long as the real message asking you to confirm or cancel your appointment. Hopefully it's long enough!</Say></Response>

BUT, that still was not long enough! By the time the asyncAMD callback was invoked, and I tried to use CallResource.Update, the call was already ended.

I ended up dumping about 2,000 characters of lorem ipsum into the outgoing call Twiml and the asyncAMD callback using CallResource.Update worked perfectly.

  • Related