4

The new Twilio 5x libraries have introduced a bit of an odd approach to gathering DTMF digits on phonecalls.

The old 4x code for a gather would have looked something like:

twiml.BeginGathertwiml.BeginGather(new { numDigits = "1", action = "/TwilioCallbacks/InputResponse" });
if(x == 10){
    twiml.Say("I am saying a thing because x = 10");
}
else{
    twiml.Say("I am saying the other thing");
}
twiml.EndGather();

Now, if you wanted to let the user punch digits on the keypad while your bot was talking to them, that'd work just fine.

However in Twilio 5x, it looks like this:

twiml.Say("I am saying a really long thing where the user must wait until the twiml script reaches the gather phrase");
twiml.Say("press 1 if stack overflow is awesome, press 2 to quit programming forever");
twiml.Gather(
            numDigits: 1,
            input: new List<InputEnum>() { InputEnum.Dtmf },
            timeout: 10,
            method: "POST",
            action: new System.Uri(Startup.hostAddress + "/TwilioCallbacks/InputResponse")
        );

Right after Gather(...) you have a short window to collect the response, if you set a timeout on the response, the twiml won't proceed to the next say until the timeout expires.

How can I Gather digits in such a way that the user can interact with the keypad at any point during the message? The new approach seems to be a step backward.

edit: Clarified the 4xx use case, such that folks can understand why chaining .Say won't work here.

edit: Some people below are suggesting chaining the .Say() verb right after .Gather().

This actually doesn't behave as expected either. This is the C# code.

    twiml.Gather(
        numDigits: 1,
        input: new List<InputEnum>() { InputEnum.Dtmf },
        timeout: 10,
        method: "POST",
        action: new System.Uri(Startup.hostAddress + "/TwilioCallBot/InputResponse")
    ).Say("this is a test");

This is the resulting twiml:

<Gather input="dtmf" action="https://callbot21.ngrok.io/RCHHRATool//TwilioCallBot/InputResponse" method="POST" timeout="10" numDigits="1">
</Gather>
<Say>this is a test</Say>

The say verb needs to be inside the gather tag to get the behavior we're looking for.

Scuba Steve
  • 1,541
  • 1
  • 19
  • 47
  • 1
    Looking at the API example for using 5.x it looks a bit different than the way you've structured things in your question. Look here, maybe it'll help you figure it out. https://www.twilio.com/docs/libraries/csharp-dotnet/usage-guide#code – fourwhey Sep 22 '18 at 00:59
  • It's a little different but to the same effect. Calling twml.Append(gather) has the exact same effect as calling twiml.Gather(...) Including the new behavior in the dtmf digit gathering. – Scuba Steve Sep 24 '18 at 00:12
  • 1
    If you look at the [example](https://www.twilio.com/docs/libraries/csharp-dotnet/usage-guide?code-sample=code-gather-with-speech&code-language=C%23&code-sdk-version=5.x) you'll notice that, for nesting verbs, you don't call `Say()` on the `twml/ response` object, rather you call `Say()` on the newly created `Gather` object... – IronGeek Oct 10 '18 at 03:42
  • 1
    @ScubaSteve In order to provide actual code to satisfy your requirements you need to provide the current *actual* code in a [mcve]. Not pseudo code, like you did above, so that a proper migration example can be presented. – Nkosi Oct 10 '18 at 08:12
  • @Nkosi - Edited – Scuba Steve Oct 12 '18 at 19:58
  • @IronGeek - That's not the behavior. The Gather verb will wait for the input, and if it doesn't get anything, it will proceed with the other Say verbs (after which point you can't enter any digits). We have a complex dynamic phone message that gets read, it doesn't work to contain the whole message inside a single Say() verb. Our message builder code is ~125 lines of code, to give you an idea. – Scuba Steve Oct 12 '18 at 20:00
  • @philnash - Got any suggestions here? – Scuba Steve Oct 12 '18 at 20:03
  • @IronGeek - The .Say verb doesn't behave as required even following your logic. The new Twilio methods don't work like this. See my edits to the question above: – Scuba Steve Oct 12 '18 at 22:20

1 Answers1

4

Okay I've found the issue. It looks like fourwhey was correct to point at the API docs there. What I didn't catch was that the .Say was being appended to the gather in a specific way.

This:

twiml.Gather(...).Say("say a thing");

doesn't work the same as this:

var gather = new Twilio.TwiML.Voice.Gather(...).Say("say a thing");

best I can work out is that there's actually two gather methods, and that twiml.Gather(...) is actually calling Twilio.TwiML.Gather.

From here we can build our dynamic voice message and nest the Say verb like so:

gather.Say("Say a thing");
gather.Say("Say another thing");

And the twiml will get spit out the way we intended like so:

<gather>
    <say>say a thing</say>
    <say>say another thing</say>
</gather>
Scuba Steve
  • 1,541
  • 1
  • 19
  • 47
  • 1
    that's what I'm trying to say all along... **You call `Say()` on the _newly created `Gather`_ object, not on the `twiml` object...**. `twiml.Gather(...)` returns the original `twiml` not the newly created/ appended `gather`... – IronGeek Oct 13 '18 at 01:50
  • Ah yep. Didn't catch that. Little bit of a paradigm shift on that. – Scuba Steve Oct 15 '18 at 20:41