Como lidar com chamadas telefônicas recebidas com Java e Twilio

April 23, 2021
Escrito por
Revisado por

Como lidar com chamadas telefônicas recebidas com Java e Twilio

Fazer chamadas outbound telefônicas com o Java e a Twilio é apenas uma parte do que é possível. Para criar um aplicativo de telefone útil e envolvente, você precisará lidar com o que acontece quando as pessoas ligam de volta.

Para isso, você precisará configurar um URL no console da Twilio. As chamadas recebidas acionarão solicitações HTTP para esse URL, e a resposta a essas solicitações de webhook determinará o que acontecerá em seguida na chamada. As respostas HTTP contêm um dialeto XML chamado TwiML, que oferece muita flexibilidade na forma como a chamada é tratada.

Nesta publicação vou mostrar como configurar um servidor Web usando o Spring Boot para lidar com chamadas recebidas com um "Hello World" (Olá, mundo" falado e mostrar como criar uma configuração mais interessante e interativa.

Se você quiser pular para o final, confira o projeto concluído no GitHub.

Configuração

Antes de começar, você precisará de:

A maneira mais rápida de começar um novo projeto do Spring Boot é usando o Spring InitializrEste link levará você a uma configuração inicial com a dependência da Web selecionada e alguns nomes pré-configurados. Carregue essa página, clique em "Generate" (Gerar) e descompacte o projeto baixado em um diretório vazio. Em seguida, abra o projeto no IDE de sua escolha. Vamos colocar a mão na massa.

Como criar o aplicativo

Ao abrir o código no IDE, você verá o nível superior do projeto. Na pasta src/main/java, há um pacote chamado com.example.twilio.calls, que tem uma classe chamada TwilioJavaHandlePhoneCallsApplication. Apesar de você não precisar editar essa classe, ela tem um método main que será útil mais tarde.

Como criar um endpoint HTTP

Crie outra classe no mesmo pacote. Chame-a de PhoneCallHandler e adicione o seguinte conteúdo:

@RestController
public class PhoneCallHandler {

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

[este código com importações no GitHub]

Abra o aplicativo executando o método main de TwilioJavaHandlePhoneCallsApplication no seu IDE ou por ./mvnw spring-boot:run em uma janela de terminal na raiz do projeto.

Após a inicialização, teste usando o comando abaixo.

curl -XPOST http://localhost:8080/

Você deve ver "Hello from your app " (Olá! Aqui é o seu aplicativo) como resposta.

Como retornar TwiML via HTTP

Até agora, tudo bem. O aplicativo está lidando com solicitações HTTP e retornando texto sem formatação. Agora, modifique-o para retornar o código Twilio Markup Language (TwiML) com um content-type de application/xml. O TwiML pode ser escrito à mão, mas é mais fácil e seguro criá-lo usando a biblioteca Twilio Java Helper. Adicione-o como uma dependência de seu projeto colocando o seguinte na seção <dependencies> de pom.xml na raiz de seu projeto:

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

[este código no GitHub]

Recomendamos sempre o uso da versão mais recente da biblioteca auxiliar da Twilio. No momento da gravação, a versão mais recente é a 8.10.0, mas novas versões são lançadas com frequência. Você sempre pode verificar a versão mais recente em mvnreporistory.com.

Em seguida, precisamos usar o TwiML para definir o que acontece durante a chamada. Isso é feito na classe PhoneCallHandler. Primeiro, vou dar um breve exemplo usando a opção de texto para voz para dizer algo. Em seguida, vou dar um exemplo mais longo que mostra como você pode criar um aplicativo de voz interativo.

Adicionar frases com o recurso <Say>

Altere o conteúdo do método handleIncomingCall em PhoneCallHandler para retornar o TwiML com um tipo de conteúdo 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 com importações no GitHub]

Esse método retorna o seguinte TwiML, que eu formatei para torná-lo mais legível:

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

Como conectar a Twilio ao seu aplicativo

O conteúdo retornado pelo handleIncomingCall é exatamente o que precisamos, mas a Twilio precisa ser capaz de acessá-lo pela Internet. Há muitas opções para hospedar aplicativos Java on-line, mas para um teste rápido como este, gosto de usar uma ferramenta chamada ngrok, que pode criar URLs públicos que encaminham para seus aplicativos da Web localhost.

Depois de instalar o ngrok, abra seu aplicativo usando seu IDE ou o comando acima. Em seguida, execute o seguinte comando para criar um URL público para seu servidor local:

ngrok http 8080

Uma vez conectado, o ngrok exibe o URL gerado aleatoriamente que agora direciona para o seu aplicativo. Ele deve ser parecido com o https://RANDOM_STRING.ngrok.io. Abra o console da Twilio e acesse seus números de recebimento e escolha o número que deseja usar para este aplicativo ou compre um novo. Edite o número e adicione seu URL ngrok como o webhook para quando uma chamada for recebida, deixando o método como POST.

Se você tiver a CLI da Twilio instalada, também poderá fazer isso na linha de comando, com o comando abaixo.

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

O CLI detectará que esta é um URL do localhost e definirá o ngrok para você.

Ligue para o seu número e ouça uma voz dizendo "Hello from Twilio" (Olá! Aqui é a Twilio). Ótimo trabalho. Parabéns!

Um exemplo interativo

Vamos além do "Hello, World" (Olá, mundo) dos aplicativos de voz. Para instigar você a tentar novas possibilidades emocionantes, vou mostrar como criar algo mais divertido e interativo. O autor da chamada ouvirá um pequeno menu de opções e poderá escolher uma delas dizendo um número ou digitando-o no teclado.

Modifique o método handleIncomingCall para usar o verbo TwiML <Gather>, que pode fazer o reconhecimento de fala e tom 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 com importações no GitHub]

O autor da chamada precisa dizer um número ou pressionar um botão do telefone usando as opções documentadas nos documentos Gather TwiML. A mais importante é a linha 14, que dá outro URL para ligar quando a Twilio reconhece uma palavra ou um pressionamento de teclado. Se não houver interação após o padrão de cinco segundos, dizemos uma mensagem de despedida GOODBYE e desligamos.

/gatherResult é um URL relativo, portanto, outro método é necessário no PhoneCallHandler para determinar o que acontece depois que o autor da chamada faz uma escolha:

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 com importações no GitHub]

Dependendo de como o autor da chamada fez a escolha, digits ou speechResult será incluído na solicitação HTTP que a Twilio envia para descobrir o que fazer em seguida. Se for escolhida uma opção válida, poderemos gerar um TwiML para contar uma piada ou tocar música usando os verbos <Say> e <Play>. A chamada termina após qualquer um desses verbos serem executados. Se o autor da chamada fizer algo inesperado, o código chama handleIncomingCall para gerar o TwiML que lê as opções novamente.

Reinicie o aplicativo e ligue de novo para ouvi-lo em ação. Divertido, não é?

Para finalizar

Você aprendeu como responder a chamadas de voz recebidas usando Twilio e Java e viu que você pode encadear chamadas para criar aplicativos de voz interativos. Agora sua imaginação é o limite.

Este artigo foi traduzido do original "Handling Incoming Phone Calls with Java and Twilio". Enquanto melhoramos nossos processos de tradução, adoraríamos receber seus comentários em help@twilio.com - contribuições valiosas podem render brindes da Twilio.