Manejo de llamadas telefónicas entrantes con Java y Twilio

April 23, 2021
Redactado por
Revisado por

Manejo de llamadas telefónicas entrantes con Java y Twilio

Realizar llamadas telefónicas salientes con Java y Twilio solo es la mitad del proceso. Para crear una app de teléfono útil e interesante, tendrá que manejar lo que sucede cuando las personas le devuelven el llamado.

Para ello, deberá configurar una dirección URL en su consola de Twilio. Las llamadas entrantes activarán las solicitudes HTTP a esa URL y la respuesta a esas webhooksolicitudes determinará qué sucede a continuación en la llamada. Las respuestas HTTP contienen un dialecto XML llamado TwiML, que le ofrece mucha flexibilidad en la forma de manejar la llamada.

En esta publicación, mostraré cómo configurar un servidor web medianteSpring Boot para manejar las llamadas entrantes con un “Saludos, mundo” hablado y, a continuación, mostraré cómo crear una configuración más interesante e interactiva.

Si desea saltar al final, revise el proyecto finalizado en GitHub.

Configuración

Antes de comenzar, necesitará:

La manera más rápida de iniciar un nuevo proyecto de Spring Boot es utilizando Spring InitializrEste enlace lo llevará a una configuración preconfigurada que tenga la dependencia web seleccionada y algunos nombres preconfigurados. Cargue esa página, haga clic en “Generate” (generar) y descomprima el proyecto descargado en un directorio vacío. Luego, abra el proyecto en su IDE de elección y comencemos.

Creación de la aplicación

Cuando abra el código en su IDE, verá el nivel superior del proyecto. Dentro de la carpeta src/main/java hay un paquete llamado com.example.twilio.calls con una clase denominada TwilioJavaHandlePhoneCallsApplication. No es necesario editar esa clase, pero tiene un método main que será útil más adelante.

Creación de un endpoint HTTP

Cree otra clase en el mismo paquete. Llámela PhoneCallHandler y colóquele el siguiente contenido:

@RestController
public class PhoneCallHandler {

    @PostMapping("/")
    @ResponseBody
    public String handleIncomingCall(){
        return "Hello from your app 👋";
    }
}

[este código con importaciones en GitHub]

Ejecute esta aplicación ahora, ya sea ejecutando el método main TwilioJavaHandlePhoneCallsApplication en su IDE o ./mvnw spring-boot:run en una ventana de terminal en la raíz de su proyecto.

Después del inicio, pruébelo mediante el comando que aparece a continuación.

curl -XPOST http://localhost:8080/

Debería ver como respuesta “Saludos de su app”.

Devolución de TwiML por HTTP

Hasta ahora, todo bien. La app maneja solicitudes HTTP y devuelve texto puro. A continuación, modifíquelo para devolver el código de Twilio Markup Language (TwiML) con un tipo de contenido de application/xml. TwiML se puede escribir a mano, pero es más fácil y seguro crearlo mediante la biblioteca Twilio Java Helper. Agréguela como una dependencia de su proyecto poniendo lo siguiente en la sección <dependencies> de pom.xml en la raíz de su proyecto:

<dependency>
         <groupId>com.twilio.sdk</groupId>
         <artifactId>twilio</artifactId>
         <version>8.10.0</version>
</dependency>

Siempre recomendamos utilizar la última versión de Twilio Helper Library. Al momento de escribir esta publicación, la versión más reciente es 8.10.0, pero se lanzan nuevas versiones con frecuencia. Siempre puede comprobar la versión más reciente en mvnreporistory.com.

A continuación, debemos utilizar TwiML para definir lo que sucede durante la llamada. Esto se realiza en la clase PhoneCallHandler. En primer lugar, daré un breve ejemplo con texto-voz para decir algo. A continuación, proporcionaré un ejemplo más largo que muestra cómo puede crear una app de voz interactiva.

<Diga> algo

Cambie el contenido del método handleIncomingCall en PhoneCallHandler para devolver TwiML con un tipo de contenido de application/xml:

@PostMapping(value = "/", produces = "application/xml")
@ResponseBody
public String handleIncomingCall(){
    return new VoiceResponse.Builder()
        .say(
            new Say.Builder("Hello from Twilio").build()
        ).build().toXml();
}

[este código con importaciones en GitHub]

Este método ahora devuelve la siguiente TwiML, que he formateado para que se lea mejor:

<?xml version="1.0" encoding="UTF-8"?>
<Response>
  <Say>Hello from Twilio</Say>
</Response>

Conectar Twilio a su aplicación

El contenido que devuelve handleIncomingCall es exactamente lo que necesitamos, pero Twilio debe poder acceder a él desde Internet. Hay muchas opciones para alojar aplicaciones Java en línea, pero para realizar una prueba rápida, como esta, me gusta utilizar una herramienta llamada ngrok que puede crear direcciones URL públicas que reenvían a sus aplicaciones web del localhost.

Una vez que haya instalado ngrok, inicie la app con su IDE o el comando de arriba. A continuación, ejecute el siguiente comando para crear una URL pública para su servidor local:

ngrok http 8080

Una vez conectado, ngrok muestra la dirección URL generada aleatoriamente que ahora apunta a su aplicación. Debería verse como https://RANDOM_STRING.ngrok.io. Abra su consola de Twilio a sus números entrantes y elija el número que desea utilizar para esta app, o compre uno nuevo. Edite el número y agregue la URL de ngrok como el webhook para “cuando entre una llamada” (dejando el método como POST).

Si tiene CLI de Twilio instalado, también puede hacerlo en la línea de comandos, con el siguiente comando:

twilio phone-numbers:update PHONE_NUMBER --sms-url http://localhost:8080/messages

La CLI detectará que se trata de una dirección URL de host local y configurará ngrok por usted.

Llame a su número y escuche el mensaje de voz “Saludos de Twilio”.  Buen trabajo. Felicitaciones 

Un ejemplo interactivo

Vamos un paso más allá del “Saludos, mundo” de las aplicaciones de voz. Para calmar sus ansias por algunas posibilidades emocionantes, le mostraré cómo construir algo más divertido e interactivo. La persona que llama escuchará un breve menú de opciones y puede elegir una al decir un número o escribirlo en el teclado.

Modifique el método handleIncomingCall para utilizar el verbo TwiML <gather>, que puede hacer reconocimiento de voz y de tono DTMF:

private static final String MENU_OPTIONS = "Hello. Press or say One for a joke, or Two for some music.";
private static final String GOODBYE = "Thanks for calling, have a great day";

@PostMapping(value = "/", produces = "application/xml")
@ResponseBody
public String handleIncomingCall() {

    return new VoiceResponse.Builder()
        .gather(new Gather.Builder()
            .say(new Say.Builder(MENU_OPTIONS).build())
            .inputs(Arrays.asList(Gather.Input.DTMF, Gather.Input.SPEECH))
            .hints("one, two")
            .numDigits(1)
            .action("/gatherResult")
            .build())
        .say(new Say.Builder(GOODBYE).build())
        .build().toXml();
}

[este código con importaciones en GitHub]

Se le pide a la persona que llama que diga un número o presione un botón en su teclado usando las opciones que están documentadas en recopilar documentos TwiML. Lo más importante se encuentra en la línea 14 que proporciona otra dirección URL para llamar cuando Twilio ha reconocido una palabra o lo que se presionó en el teclado. Si no hay ninguna entrada después de los 5 segundos predeterminados, diremos el mensaje GOODBYE y colgaremos.

/gatherResult es una URL relativa por lo que se necesita otro método en PhoneCallHandler a fin de determinar lo que sucede después de que la persona que llama haya hecho una elección:

private static final String JOKE = "How do you know if a bee is using your phone? The line will be buzzy.";
private static final String MUSIC_URL = "http://demo.twilio.com/docs/classic.mp3";

@PostMapping(value = "/gatherResult", produces = "application/xml")
@ResponseBody
public String handleGatherResult(
    @RequestParam(value = "Digits", required = false) String digits,
    @RequestParam(value = "SpeechResult", required = false) String speechResult) {

    if ("1".equals(digits) || "one".equals(speechResult)) {
        return new VoiceResponse.Builder()
            .say(new Say.Builder(JOKE).build())
            .build().toXml();
    }

    if ("2".equals(digits) || "two".equals(speechResult)) {
        return new VoiceResponse.Builder()
            .play(new Play.Builder(MUSIC_URL).build())
            .build().toXml();
    }

    // if they said or typed something we didn't expect, read the choices again.
    return handleIncomingCall();
}

[este código incluidas las importaciones en GitHub]

Según la forma en que la persona que llama haya realizado su elección, se incluirán digits o speechResult en la solicitud HTTP que Twilio envía para saber qué hacer a continuación. Si elige una opción válida, podemos generar TwiML para contar un chiste o poner algo de música mediante los verbos <Say> y <Play>. La llamada finaliza después de que se ejecuta cualquiera de esos verbos. Si la persona que llama hizo algo inesperado, el código llama a handleIncomingCall para generar TwiML que lee las opciones nuevamente a la persona que llama.

Reinicie la aplicación y realice otra llamada para escucharla en acción. Divertido, ¿no?

Conclusión

Aprendió cómo responder a las llamadas de voz entrantes mediante Twilio y Java, y verá que puede concatenar llamadas para crear aplicaciones de voz interactivas. Ahora el límite es su imaginación.

¡Estoy ansioso por ver lo que es capaz de crear!

Este artículo fue traducido del original "Handling Incoming Phone Calls with Java and Twilio". Mientras estamos en nuestros procesos de traducción, nos encantaría recibir sus comentarios en help@twilio.com - las contribuciones valiosas pueden generar regalos de Twilio.