Como migrar para o SDK do Voice JavaScript 2.0
A versão 2.1.0 do SDK do Voice JavaScript foi lançada. Depois de usar este guia de migração para atualizar para a versão 2.0.1, acesse a página Changelog para ver as novidades da versão 2.1.0.
Você pode visualizar os detalhes das atualizações do SDK no Changelog do repositório do GitHub. Você encontrará a documentação completa da API gerada automaticamente no site de páginas do GitHub.
Nesse guia, você verá referências a uma classe Call
. Essa é a classe Connection
renomeada. Você encontrará mais detalhes no guia abaixo.
Use o novo módulo NPM em vez do CDN
O SDK do Voice JavaScript está publicado em @twilio/voice-sdk. Os SDKs 1.x ainda estarão disponíveis como twilio-client.
Com o objetivo de promover as práticas recomendadas, não será realizado o upload das versões 2.0 e mais recentes para a CDN da Twilio. As versões existentes (anteriores à 2.0) e qualquer outra versão 1.x continuarão a ser fornecidas por meio da CDN. No entanto, ainda é altamente recomendável não vincular diretamente a esses arquivos na produção, pois isso introduz o potencial de interrupção devido a indisponibilidade da CDN.
Para os clientes que atualmente usam a CDN, há algumas opções para alternar:
- Se seu projeto usa NPM, instale a versão mais recente do @twilio/voice-sdk. A partir daqui, os arquivos de distribuição criados estarão disponíveis em
node_modules/@twilio/voice-sdk/dist
. - Se seu projeto não usar NPM, é possível baixar o artefato mais recente criado e servi‐lo a partir dos seus próprios servidores. Cada versão terá sua própria tag no GitHub. Baixe a versão mais recente (a tag mais recente sem
-rc
), descompacte‐a e navegue até/dist
para os arquivostwilio.js
etwilio.min.js
.
Pare de usar o singleton Device e, em vez disso, instancie uma nova instância Device
O comportamento singleton do Device
foi removido em favor das práticas recomendadas. device.setup()
não funcionará mais; em vez disso, uma nova instância Device
deve ser instanciada via new Device(token, options?)
.
const device = new Device(token, deviceOptions);
Pare de usar device.setup() e, em vez disso, use device.updateOptions()
device.setup()
não funcionará mais para criar uma nova instância Device
.
Além disso, o device.setup()
não funcionará mais para atualizar a instância Device
depois que ela tiver sido criada. Em vez disso, use device.updateOptions(deviceOptions)
para atualizar qualquer uma das opções da instância Device
após a criação de uma nova instância Device
.
Parar de ouvir o device.on('ready')
As instâncias do Device
agora ficam lentas ao abrir a conexão de sinalização. Isso significa que o construtor do Device
é síncrono e não fará com que um canal de sinalização seja aberto.
O websocket de sinalização será aberto quando:
- device.register() for invocado, o que registra a instância
Device
para receber chamadas de entrada - device.connect() for chamado, o que faz uma chamada outbound.
Se seu aplicativo precisar monitorar o status de registro da instância Device
, os seguintes eventos serão emitidos pela instância Device
:
Para monitorar o status da conexão de sinalização durante uma chamada outbound quando não estiver registrada (você não invocou device.register()
para permitir que a instância Device
receba chamadas recebidas), você deve monitorar o status da Call
.
A lista completa de eventos do Device
agora é:
enum Device.EventName {
Erro = "error",
Entrada = "incoming",
Não registrado = "unregistered",
Registro = "registering",
Registrado = "registered",
Destruído = "destroyed",
}
Certifique‐se de que o AccessToken (Token de acesso) seja mantido atualizado
Agora que a sinalização está lenta, o AccessToken (Token de acesso) deve ser mantido atualizado com device.updateToken(accessToken) antes de registrar (com device.register()
) ou fazer uma Call
outbound (com device.connect()
).
Um AccessToken (Token de acesso) expirado impedirá que as estatísticas do Voice Insights sejam publicadas. Esse é um comportamento existente de 1.x. No futuro, à medida que explorarmos o suporte à reconexão de sinalização, manter esse token atualizado será ainda mais importante para restaurar automaticamente a conexão a uma Call
ou registrar novamente o endpoint de forma automática.
Veja abaixo um exemplo de como manter o AccessToken (Token de acesso) atualizado:
const ttl = 600.000; // 10 minutos
const refreshBuffer = 30.000; // 30 seconds
const token = await getTokenViaAjax({ ttl });
const device = new Device(token);
setInterval(async () => {
const newToken = await getTokenViaAjax({ ttl });
device.updateToken(token);
}, ttl - refreshBuffer); // Concede um buffer generoso de 30 segundos
Atualizar referências ao estado do dispositivo
Os estados do Device
mudaram para:
namespace do dispositivo {
isBusy: boolean;
enumeração de estado {
não registrado = "unregistered";
registrar = "registering";
registrado = "registered";
destruído = "destroyed";
}
}
Não representamos mais o estado busy
como parte do estado do Device
; nós o movemos para o booleano device.isBusy.
O estado ready
agora é representado pelo estado Registered
Device
.
O estado offline
agora é representado pelo estado Unregistered
Device
.
Uma observação importante aqui é que ready
e offline
sempre indicaram o status do registro em vez de sinalizar o status da conexão. Essa alteração na versão 2 visa eliminar essa confusão.
Atualize os argumentos device.connect() e call.accept()
O objeto AcceptOptions passado para call.accept()
agora tem as seguintes propriedades:
interface Call.AcceptOptions {
/**
* Uma RTCConfiguration para passar ao construtor RTCPeerConnection.
*/
rtcConfiguration?: RTCConfiguration;
/**
* MediaStreamConstraints para passar para getUserMedia ao fazer ou atender uma chamada.
*/
rtcConstraints?: MediaStreamConstraints;
}
O objeto ConnectOptions passado para device.connect() estende a interface AcceptOptions e adiciona uma propriedade opcional params
:
a interface Device.ConnectOptions estende Call.AcceptOptions {
/**
* Um objeto plano que contém pares key:value a serem enviados para o app TwiML.
*/
params?: Record<string, string>;
}
Observe que os objetos agora podem usar MediaStreamConstraints. Por exemplo:
device.connect({ To: 'client:alice' }, { deviceId: 'default' });
pode ser reescrito como:
device.connect({
params: { To: 'client:alice' },
rtcConstraints: { audio: { deviceId: 'default' } },
});
Atualize os manipuladores de erros
Para compatibilidade com versões anteriores, o novo formato de erro foi anexado ao formato antigo em error.twilioError
:
class oldError extends Error {
//...
code: number;
message: string;
twilioError: TwilioError;
}
O novo formato de erro é um objeto TwilioError:
class TwilioError extends Error {
/**
* Uma lista de possíveis causas para o erro.
*/
causes: string[];
/**
* O código numérico associado a este erro.
*/
code: number;
/**
* Uma descrição do que o erro significa.
*/
description: string;
/**
* Uma explicação de quando o erro pode ser observado.
*/
explanation: string;
/**
* Qualquer informação adicional descoberta e transmitida no tempo de execução.
*/
message: string;
/**
* O nome desse erro.
*/
name: string;
/**
* O erro original recebido do sistema externo, se houver.
*/
originalError?: Error;
/**
* Uma lista de possíveis soluções para o erro.
*/
solutions: string[];
}
Se você já estiver usando o novo formato, a migração deverá ser simples:
// changing...
device.on('error', e => {
handleError(e.twilioError);
});
// to...
device.on('error', e => {
handleError(e);
});
Caso contrário, alguns dos códigos de erro e mensagens podem ter mudado dos códigos antigos específicos da plataforma para os novos códigos que são mais consistentes com o Twilio, nossa API REST e outros SDKs.
Atualize os códigos de erro
Com a transição para usar o formato TwilioError, os seguintes códigos de erro foram alterados:
Código antigo | Novo código | Descrição |
31003 | 53405 | Quando a conexão ICE falhar |
31201 | 31402 | Quando a obtenção de mídia do usuário falhar |
31208 | 31401 | Quando o usuário nega o acesso à mídia do usuário |
31901 | 53000 | Quando o websocket atinge o tempo limite no pré‐envio |
Atualize a lógica de chamada para incluir estados de toque, se necessário
Em um patch anterior, incluímos estados de toque em Call
, que foram ativados por trás da propriedade DeviceOptions
enableRingingState
. Removemos esse sinalizador em 2.0, já que agora ele é ativado por padrão.
Para obter funcionalidade completa, isso ainda requer a configuração answerOnBridge em seu TwiML. No entanto, mesmo sem answerOnBridge
, a Call
passará pelo novo estado ringing
(brevemente, por alguns ms) antes de ser open
. Quando o answerOnBridge
estiver ativado, o estado ringing
começará quando o telefone do destinatário começar a tocar e passará para open
quando ele atender e a mídia for estabelecida.
Isso não deve afetar a maioria dos aplicativos; no entanto, pode ser necessário que seu aplicativo saiba sobre o estado Call.Ringing
e o evento ringing
, dependendo da sua implementação.
Atualize métodos e opções removidos
call.mediaStream
- Use call.getRemoteStream() e call.getLocalStream() para adquirir os fluxos de mídia ativos.
call.message
- O call.customParameters contém as mesmas informações de um mapa
call.options
- Foi planejado para ser uma propriedade privada
call.pstream
- Foi planejado para ser uma propriedade privada
call.sendHangup()
- Foi planejado para ser um método privado
deviceOptions.enableIceRestart
- Agora, o padrão é
true
- Agora, o padrão é
deviceOptions.enableRingingState
- Agora, o padrão é
true
- Agora, o padrão é
deviceOptions.fakeLocalDtmf
- Agora, o padrão é
true
- Agora, o padrão é
device.activeCall
- O aplicativo deve manter referências a instâncias
Call
retornadas em manipuladores de eventosdevice.on('incoming')
ou pordevice.connect()
- O aplicativo deve manter referências a instâncias
O evento "cancel" não é mais emitido pela instância Call em resposta a um call.ignore() local
A instância Call
não emite mais o evento 'cancel'
em resposta a um call.ignore()
local. Em vez disso, ele só será acionado quando a extremidade remota for cancelada.
Atualize suas DeviceOptions
A nova interface DeviceOptions é:
interface Device.Options {
allowIncomingWhileBusy?: boolean;
appName?: string;
appVersion?: string;
closeProtection?: boolean | string;
codecPreferences?: Connection.Codec[];
disableAudioContextSounds?: boolean;
dscp?: boolean;
edge?: string[] | string;
forceAggressiveIceNomination?: boolean;
logLevel: number;
maxAverageBitrate?: number;
sounds?: Partial<Record<Device.SoundName, string>>;
}
(Opcional) Renomear Connection para Call
Renomeamos a classe Connection
para Call
. Isso não deve afetar nenhuma API pública; no entanto, alguns nomes de métodos internos foram atualizados. Portanto, qualquer código que entrar internamente dará errado se não for atualizado.
Precisa de ajuda?
Às vezes, todos nós precisamos; a programação é difícil. Receba ajuda agora da nossa equipe de suporte, ou confie na sabedoria da multidão navegando pelo Stack Overflow Collective da Twilio ou buscando a tag Twilio no Stack Overflow.