https://a.storyblok.com/f/270183/127232/3a28a1a7a9/selective-audio-controls_1200x675.jpg

Chamada silenciosa com controles seletivos de áudio

Publicado em May 11, 2021

Tempo de leitura: 5 minutos

A Nexmo já é, há muito tempo, uma escolha popular para soluções de centrais de atendimento, mas com o lançamento hoje dos Controles Seletivos de Áudio, estamos levando isso a um novo patamar. Os controles seletivos de áudio resolvem um caso de uso comum — um supervisor que ouve uma chamada, mas só é ouvido pelo funcionário e não pelo cliente — de maneira intuitiva.

A cada participante de uma conversa na plataforma Nexmo é atribuído um ID. Utilizando esses IDs e a ação de conversa , você pode criar um aplicativo que controle quais participantes uma pessoa nova na conversa pode ouvir. Nesta postagem, vamos desenvolver o caso de uso em que um supervisor ouve um funcionário.

O código deste aplicativo está disponível no GitHub

Inicialização de um aplicativo

Para criar esse fluxo de chamadas, precisamos escrever um pequeno aplicativo em Node.js. Vamos criar um novo projeto e instalar express para hospedar nosso answer_url.

mkdir selective-audio cd selective-audio npm init -y npm install express body-parser --save

Depois de fazer isso, você precisará criar uma instância de express, registrar uma answer_url e ficar à escuta em uma porta. Para isso, crie index.js com o seguinte conteúdo:

const express = require('express');
const bodyParser = require('body-parser');

const app = express();
app.use(bodyParser.urlencoded({"extended": true}));
app.use(bodyParser.json());

app.get('/webhooks/answer', (req, res) => {
    return res.json([]);
});

app.listen(3000, () => {
    console.log('Listening');
});

Como criar sua URL de resposta

Agora que já temos um aplicativo inicializado, é hora de começar a adicionar nossa lógica de negócios. Há três participantes em nossa chamada:

  • Alice, supervisora do centro de atendimento

  • Bob, o atendente do centro de atendimento

  • Charlie, o cliente

No mundo real, usaríamos um banco de dados para armazenar todas as informações necessárias para que isso funcionasse, mas, para este post, vamos usar apenas um objeto na memória. A chave é o número de telefone do participante, e ela está associada a um objeto que contém informações sobre ele. Por enquanto, trata-se apenas da função que ele desempenha. Adicione o código a seguir após app.use(bodyParser.json());, certificando-se de atualizar o código abaixo, substituindo as chaves pelos seus números de telefone reais.

const conversationName = 'selective-audio-demo';
const participants = {
  "<supervisor_phone_number>": {
    "role": "supervisor",
  },
  "<agent_phone_number>": {
    "role": "agent",
  },
  "<customer_phone_number>": {
    "role": "customer",
  }
};

Depois de fazer isso, você precisa atualizar sua /webhooks/answer URL para que ela retorne um NCCO válido. Como precisaremos de um NCCO diferente para cada tipo de chamador, vamos adicionar uma switch instrução e chamar um método que retorne um NCCO para cada tipo de chamador:

app.get('/webhooks/answer', (req, res) => {
    const caller = participants[req.query.from];

    if (!caller) {
        return res.status(400).json("Unknown caller type: " + req.query.from);
    }

    // Generate an NCCO based on role
    let ncco;
    switch (caller.role) {
        case 'supervisor':
            ncco = createSupervisorNcco(caller);
            break;
        case 'agent':
            ncco = createAgentNcco(caller);
            break;
        case 'customer':
            ncco = createCustomerNcco(caller);
            break;
        default:
            return res.status(400).json("Unknown caller type: " + caller.type);

    }
    return res.json(ncco);
});

Este código chama createSupervisorNcco, createAgentNcco ou createCustomerNcco dependendo do tipo de chamador fornecido. Precisamos criar essas funções e retornar NCCO.

O Cliente NCCO

Vamos começar com o cliente NCCO. Quando o cliente entrar na chamada, queremos que ele possa ouvir o atendente, mas não o supervisor, e que possa falar tanto com o atendente quanto com o supervisor. Além disso, quando o cliente ligar, queremos que ele seja colocado em espera até que um atendente entre na conversa.

Adicione o seguinte ao final do seu arquivo para gerar o NCCO do cliente. Usamos a conversation ação, atribuímos à conversa um name, especificamos que a chamada não deve iniciar automaticamente e que o usuário deve ser colocado em espera. Todos esses são parâmetros existentes na Voice API da Nexmo.

O que torna esse NCCO interessante são os canSpeak e canHear . Esses dois parâmetros aceitam uma lista de UUIDs que identificam outros participantes e controlam com quem a pessoa que está se conectando à chamada pode falar e de quem pode ouvir. Se o UUID de um participante não for fornecido, o usuário que está se conectando não poderá falar com esse participante nem ouvi-lo.

Neste exemplo, nosso cliente pode falar com o atendente e com o supervisor dele, mas só consegue ouvir o áudio do atendente. Adicione o seguinte ao final do seu arquivo:

function createCustomerNcco(caller){
    // Customer can hear agent, and speak to everyone
    return [
        {
            "action": "conversation",
            "name": conversationName,
            "startOnEnter": false,
            "musicOnHoldUrl": ["https://nexmo-community.github.io/ncco-examples/assets/voice_api_audio_streaming.mp3"],
            "canSpeak": findParticipants('agent').concat(findParticipants('supervisor')),
            "canHear": findParticipants('agent')
        }
    ]
}

O Agente NCCO

Em seguida, temos o agente NCCO. Os agentes devem poder falar com todos os participantes e ser ouvidos por todos eles. Como ele é o proprietário desta teleconferência, definimos startOnEnter como “true” para indicar que a teleconferência se torna ativa quando ele entra. Além disso, definimos record para true para que a chamada seja gravada.

Como o agente pode falar com todos e ouvir todos, localizamos todos os clientes e todos os supervisores e fornecemos seus UUIDs à conversation ação.

Nesse caso, poderíamos omitir canSpeak e canHear do NCCO, já que os valores padrão permitem a transmissão de áudio entre todos os participantes. Para ter controle total sobre os participantes, optei por fornecê-los mesmo assim

function createAgentNcco(caller){
    // Agent can hear everyone, and speak to everyone
    return [
        {
            "action": "conversation",
            "name": conversationName,
            "startOnEnter": true,
            "record": true,
            "canSpeak": findParticipants('customer').concat(findParticipants('supervisor')),
            "canHear": findParticipants('customer').concat(findParticipants('supervisor'))
        }
    ]
}

O Supervisor NCCO

Por fim, temos o supervisor NCCO. O supervisor pode ouvir todos, mas só pode falar com o atendente (isso é o oposto do que acontece com o cliente). Assim como antes, ele não é o responsável pela chamada, portanto startOnEnter está definido como “false”.

Oferecemos canSpeak e canHear uma lista de UUIDs, assim como nossos NCCOs anteriores, e isso garante que o supervisor só possa falar com o agente, mas ouça tanto o agente quanto o cliente.

function createSupervisorNcco(caller){
    // Supervisor can hear everyone, but only speak to agents
    return [
        {
            "action": "conversation",
            "name": conversationName,
            "startOnEnter": false,
            "musicOnHoldUrl": ["https://nexmo-community.github.io/ncco-examples/assets/voice_api_audio_streaming.mp3"],
            "canSpeak": findParticipants('agent'),
            "canHear": findParticipants('customer').concat(findParticipants('agent'))
        }
    ]
}

Fazendo tudo funcionar

Estamos quase lá! Faltam apenas duas coisas para que nosso aplicativo funcione. A primeira é implementar nosso findParticipants método. Adicione a seguinte função ao final do seu arquivo:

function findParticipants(callerType) {
    let legs = [];
    Object.entries(participants).forEach(([number, participant]) => {
        if (participant.role == callerType && participant.legId) {
            legs.push(participant.legId);
        }
    });

    return legs;
}

Isso pesquisa entre todos os participantes a função fornecida. Se a função corresponder, o UUID da etapa é inserido em um array e retornado.

A segunda coisa a fazer é garantir que armazenemos o UUID da etapa do chamador quando for feita uma solicitação para /webhooks/answer. Atualize seu código para armazenar o ID da etapa após verificarmos se o chamador atual pode ser encontrado:

if (!caller) {
    return res.status(400).json("Unknown caller type: " + req.query.from);
}

// Add their leg ID to the caller
caller.legId = req.query.uuid;

Neste momento, seu aplicativo já deve estar funcionando. Certifique-se de que seu answer_url esteja acessível (talvez usando ngrok , caso esteja na sua máquina local) e ligue para um número que aponte para o aplicativo que você acabou de criar. Se precisar criar um aplicativo Nexmo e alugar um número, dê uma olhada em nossos conceitos de aplicativos em nosso portal de desenvolvedores.

Compartilhar:

https://a.storyblok.com/f/270183/384x384/1c8825919c/mheap.png
Michael HeapEx-funcionários da Vonage

Michael é um engenheiro de software poliglota, empenhado em reduzir a complexidade dos sistemas e torná-los mais previsíveis. Trabalhando com diversas linguagens e ferramentas, ele compartilha seus conhecimentos técnicos com públicos de todo o mundo em grupos de usuários e conferências. No dia a dia, Michael é ex-representante de desenvolvedores da Vonage, onde dedicava seu tempo a aprender, ensinar e escrever sobre todos os tipos de tecnologia.