Como controlar e orientar chamadas com a Automação de Chamadas

A Automação de Chamadas usa uma interface da API REST para receber solicitações de ações e fornecer respostas para notificar se a solicitação foi enviada com êxito. Devido à natureza assíncrona da chamada, a maioria das ações tem eventos correspondentes que são disparados quando a ação é concluída com êxito ou quando falha. Este guia aborda as ações disponíveis para orientar chamadas, como CreateCall, Transferir e Redirecionar, e gerenciar participantes. As ações são acompanhadas por um código de exemplo sobre como invocar a ação e pelos diagramas de sequência que descrevem os eventos esperados após invocar uma ação. Esses diagramas ajudarão você a visualizar como programar o aplicativo de serviço com a Automação de Chamadas.

A Automação de Chamadas oferece suporte a várias outras ações para gerenciar a mídia e a gravação de chamadas, que têm guias separados.

Como pré-requisito, recomendamos que você leia estes artigos para aproveitar ao máximo este guia:

  1. Guia de conceitos da Automação de Chamadas que descreve o modelo de programação de eventos de ação e os retornos de chamada de eventos.
  2. Saiba mais sobre os identificadores de usuário, como CommunicationUserIdentifier e PhoneNumberIdentifier, usados neste guia.

Para todos os exemplos de código, client é o objeto CallAutomationClient que pode ser criado conforme mostrado e callConnection é o objeto CallConnection obtido da resposta Answer ou CreateCall. Você também pode obtê-lo dos eventos de retorno de chamada recebidos pelo aplicativo.

var client = new CallAutomationClient("<resource_connection_string>"); 

Fazer uma chamada de saída

Você pode fazer uma chamada individual ou de grupo para um usuário ou número de telefone da comunicação (número público ou de propriedade dos Serviços de Comunicação). Ao chamar um ponto de extremidade PSTN, você também precisa fornecer um número de telefone que será usado como a ID de Chamadas de origem e mostrado na notificação de chamada para o ponto de extremidade PSTN de destino. Para fazer uma chamada para um usuário dos Serviços de Comunicação, você precisará fornecer um objeto CommunicationUserIdentifier em vez de PhoneNumberIdentifier.

Uri callbackUri = new Uri("https://<myendpoint>/Events"); //the callback endpoint where you want to receive subsequent events 
var callerIdNumber = new PhoneNumberIdentifier("+16044561234"); // This is the Azure Communication Services provisioned phone number for the caller  
var callThisPerson = new CallInvite(new PhoneNumberIdentifier("+16041234567"), callerIdNumber); // person to call
CreateCallResult response = await client.CreateCallAsync(callThisPerson, callbackUri);

Ao fazer uma chamada de grupo que inclua um número de telefone, você deve fornecer um número de telefone que seja usado como um número de ID de Chamadas para o ponto de extremidade PSTN.

Uri callbackUri = new Uri("https://<myendpoint>/Events"); //the callback endpoint where you want to receive subsequent events 
var pstnEndpoint = new PhoneNumberIdentifier("+16041234567");
var voipEndpoint = new CommunicationUserIdentifier("<user_id_of_target>"); //user id looks like 8:a1b1c1-...
var groupCallOptions = new CreateGroupCallOptions(new List<CommunicationIdentifier>{ pstnEndpoint, voipEndpoint }, callbackUri)
{
    SourceCallerIdNumber = new PhoneNumberIdentifier("+16044561234"), // This is the Azure Communication Services provisioned phone number for the caller
};
CreateCallResult response = await client.CreateGroupCallAsync(groupCallOptions);

A resposta fornece o objeto CallConnection que você pode usar para executar demais ações nessa chamada depois que ela for conectada. Depois que a chamada for atendida, dois eventos serão publicados no ponto de extremidade de retorno de chamada fornecido anteriormente:

  1. Evento CallConnected notificando que a chamada foi estabelecida com o receptor.
  2. Evento ParticipantsUpdated que contém a lista mais recente de participantes da chamada. Diagrama de sequência para fazer uma chamada de saída.

Se a chamada falhar, você receberá um evento CallDisconnected e CreateCallFailed com códigos de erro para solução de problemas adicionais (consulte esta página para obter mais informações sobre códigos de erro de Automação de Chamadas).

Conectar-se a uma chamada (em versão prévia)

A ação Conectar permite que seu serviço estabeleça uma conexão com uma chamada em andamento e execute ações nela. Isso é útil para gerenciar uma chamada de Salas ou quando os aplicativos cliente iniciaram uma chamada 1:1 ou de grupo da qual a Automação de Chamadas não participa. A conexão é estabelecida usando a propriedade CallLocator e pode ser de tipos: ServerCallLocator, GroupCallLocator e RoomCallLocator. Essas IDs podem ser encontradas quando a chamada é originalmente estabelecida ou uma Sala é criada e também publicadas como parte do evento CallStarted.

Para se conectar a qualquer chamada de grupo ou 1:1, use o ServerCallLocator. Se você iniciou uma chamada usando GroupCallId, também pode usar o GroupCallLocator.

Uri callbackUri = new Uri("https://<myendpoint>/Events"); //the callback endpoint where you want to receive subsequent events
CallLocator serverCallLocator = new ServerCallLocator("<ServerCallId>");
ConnectCallResult response = await client.ConnectCallAsync(serverCallLocator, callbackUri);

Para se conectar a uma chamada de Salas, use RoomCallLocator que usa RoomId. Saiba mais sobre Rooms e como a API de automação de chamadas pode ser usada para gerenciar chamadas de salas em andamento.

Uri callbackUri = new Uri("https://<myendpoint>/Events"); //the callback endpoint where you want to receive subsequent events
CallLocator roomCallLocator = new RoomCallLocator("<RoomId>");
ConnectCallResult response = await client.ConnectCallAsync(roomCallLocator, callbackUri);

Uma resposta bem-sucedida fornece um objeto CallConnection que pode ser usado para realizar outras ações nessa chamada. Dois eventos serão publicados no ponto de extremidade de retorno de chamada que você forneceu anteriormente:

  1. CallConnected evento notificando que você se conectou com sucesso à chamada.
  2. Evento ParticipantsUpdated que contém a lista mais recente de participantes da chamada.

A qualquer momento após uma conexão bem-sucedida, se o serviço for desconectado dessa chamada, você será notificado por meio de um evento CallDisconected. Falha ao se conectar à chamada em primeiro lugar resulta em evento ConnectFailed.

Diagrama de sequência para se conectar à chamada.

Responder a uma chamada de entrada

Depois de se inscrever para receber notificações de chamada de entrada ao recurso, você atenderá a uma chamada de entrada. Ao atender uma chamada, é necessário fornecer uma URL de retorno de chamada. Os Serviços de Comunicação postarão todos os eventos subsequentes sobre essa chamada para essa URL.

string incomingCallContext = "<IncomingCallContext_From_IncomingCall_Event>"; 
Uri callBackUri = new Uri("https://<myendpoint_where_I_want_to_receive_callback_events"); 

var answerCallOptions = new AnswerCallOptions(incomingCallContext, callBackUri);  
AnswerCallResult answerResponse = await client.AnswerCallAsync(answerCallOptions);
CallConnection callConnection = answerResponse.CallConnection; 

A resposta fornece o objeto CallConnection que você pode usar para executar demais ações nessa chamada depois que ela for conectada. Depois que a chamada for atendida, dois eventos serão publicados no ponto de extremidade de retorno de chamada fornecido anteriormente:

  1. Evento CallConnected notificando que a chamada foi estabelecida com o chamador.
  2. Evento ParticipantsUpdated que contém a lista mais recente de participantes da chamada.

Diagrama de sequência para atender uma chamada de entrada.

Rejeitar uma chamada

Você pode optar por rejeitar uma chamada de entrada, conforme mostrado abaixo. Você pode fornecer um motivo para a rejeição: nenhum, ocupado ou proibido. Se nada for fornecido, nenhum será escolhido por padrão.

string incomingCallContext = "<IncomingCallContext_From_IncomingCall_Event>"; 
var rejectOption = new RejectCallOptions(incomingCallContext); 
rejectOption.CallRejectReason = CallRejectReason.Forbidden; 
_ = await client.RejectCallAsync(rejectOption); 

Nenhum evento é publicado para ação de rejeição.

Redirecionar uma chamada

Você pode optar por redirecionar uma chamada de entrada para outro ponto de extremidade sem atendê-la. Redirecionar uma chamada removerá a capacidade do aplicativo de controlar a chamada usando a Automação de Chamadas.

string incomingCallContext = "<IncomingCallContext_From_IncomingCall_Event>"; 
var target = new CallInvite(new CommunicationUserIdentifier("<user_id_of_target>")); //user id looks like 8:a1b1c1-... 
_ = await client.RedirectCallAsync(incomingCallContext, target); 

Para redirecionar a chamada para um número de telefone, construa a ID de Chamadas e de destino com PhoneNumberIdentifier.

var callerIdNumber = new PhoneNumberIdentifier("+16044561234"); // This is the Azure Communication Services provisioned phone number for the caller
var target = new CallInvite(new PhoneNumberIdentifier("+16041234567"), callerIdNumber);

Nenhum evento foi publicado para redirecionamento. Se o destino for um usuário dos Serviços de Comunicação ou um número de telefone de propriedade do recurso, ele gerará um novo evento IncomingCall com o campo 'to' definido como o destino especificado.

Transferir um participante na chamada

Quando o aplicativo atende a uma chamada ou faz uma chamada de saída para um ponto de extremidade, esse ponto de extremidade pode ser transferido para outro ponto de extremidade de destino. A transferência de uma chamada individual removerá o aplicativo da chamada e, assim, removerá a capacidade dele de controlar a chamada usando a Automação de Chamadas. O convite de chamada para o destino exibirá a ID de Chamadas do ponto de extremidade que está sendo transferido. Não há suporte para fornecer uma ID de Chamadas personalizada.

var transferDestination = new CommunicationUserIdentifier("<user_id>"); 
var transferOption = new TransferToParticipantOptions(transferDestination) {
    OperationContext = "<Your_context>",
    OperationCallbackUri = new Uri("<uri_endpoint>") // Sending event to a non-default endpoint.
};
// adding customCallingContext
transferOption.CustomCallingContext.AddVoip("customVoipHeader1", "customVoipHeaderValue1");
transferOption.CustomCallingContext.AddVoip("customVoipHeader2", "customVoipHeaderValue2");

TransferCallToParticipantResult result = await callConnection.TransferCallToParticipantAsync(transferOption);

Quando seu aplicativo atende a uma chamada de grupo ou faz uma chamada de grupo de saída para um ponto de extremidade ou adicionado um participante a uma chamada 1:1, um ponto de extremidade pode ser transferido da chamada para outro ponto de extremidade de destino, exceto o ponto de extremidade de automação de chamadas. A transferência de um participante em uma chamada de grupo remove o ponto de extremidade que está sendo transferido da chamada. O convite de chamada para o destino exibirá a ID de Chamadas do ponto de extremidade que está sendo transferido. Não há suporte para fornecer uma ID de Chamadas personalizada.

// Transfer User
var transferDestination = new CommunicationUserIdentifier("<user_id>");
var transferee = new CommunicationUserIdentifier("<transferee_user_id>"); 
var transferOption = new TransferToParticipantOptions(transferDestination);
transferOption.Transferee = transferee;

// adding customCallingContext
transferOption.CustomCallingContext.AddVoip("customVoipHeader1", "customVoipHeaderValue1");
transferOption.CustomCallingContext.AddVoip("customVoipHeader2", "customVoipHeaderValue2");

transferOption.OperationContext = "<Your_context>";
transferOption.OperationCallbackUri = new Uri("<uri_endpoint>");
TransferCallToParticipantResult result = await callConnection.TransferCallToParticipantAsync(transferOption);

// Transfer PSTN User
var transferDestination = new PhoneNumberIdentifier("<target_phoneNumber>");
var transferee = new PhoneNumberIdentifier("<transferee_phoneNumber>"); 
var transferOption = new TransferToParticipantOptions(transferDestination);
transferOption.Transferee = transferee;

// adding customCallingContext
transferOption.CustomCallingContext.AddSipUui("uuivalue");
transferOption.CustomCallingContext.AddSipX("header1", "headerValue");

transferOption.OperationContext = "<Your_context>";

// Sending event to a non-default endpoint.
transferOption.OperationCallbackUri = new Uri("<uri_endpoint>");

TransferCallToParticipantResult result = await callConnection.TransferCallToParticipantAsync(transferOption);

O diagrama de sequência mostra o fluxo esperado quando o aplicativo faz uma chamada de saída e a transfere para outro ponto de extremidade.

Diagrama de sequência para fazer uma chamada individual e transferi-la.

Adicionar um participante a uma chamada

Você pode adicionar um participante (usuário ou número de telefone dos Serviços de Comunicação) a uma chamada existente. Ao adicionar um número de telefone, é obrigatório fornecer a ID de Chamadas. Essa ID de Chamadas será mostrada na notificação da chamada para o participante que está sendo adicionado.

// Add user
var addThisPerson = new CallInvite(new CommunicationUserIdentifier("<user_id>"));
// add custom calling context
addThisPerson.CustomCallingContext.AddVoip("myHeader", "myValue");
AddParticipantsResult result = await callConnection.AddParticipantAsync(addThisPerson);

// Add PSTN user
var callerIdNumber = new PhoneNumberIdentifier("+16044561234"); // This is the Azure Communication Services provisioned phone number for the caller
var addThisPerson = new CallInvite(new PhoneNumberIdentifier("+16041234567"), callerIdNumber);
// add custom calling context
addThisPerson.CustomCallingContext.AddSipUui("value");
addThisPerson.CustomCallingContext.AddSipX("header1", "customSipHeaderValue1");

// Use option bag to set optional parameters
var addParticipantOptions = new AddParticipantOptions(new CallInvite(addThisPerson))
{
    InvitationTimeoutInSeconds = 60,
    OperationContext = "operationContext",
    OperationCallbackUri = new Uri("uri_endpoint"); // Sending event to a non-default endpoint.
};

AddParticipantsResult result = await callConnection.AddParticipantAsync(addParticipantOptions); 

Para adicionar um usuário dos Serviços de Comunicação, forneça um CommunicationUserIdentifier em vez de um PhoneNumberIdentifier. A ID de Chamadas não é obrigatória nesse caso.

AddParticipant publicará um evento AddParticipantSucceeded ou AddParticipantFailed, juntamente com um ParticipantUpdated fornecendo a lista mais recente de participantes na chamada.

Diagrama de sequência para adicionar um participante à chamada.

Cancelar uma solicitação para adicionar participante

// add a participant
var addThisPerson = new CallInvite(new CommunicationUserIdentifier("<user_id>"));
var addParticipantResponse = await callConnection.AddParticipantAsync(addThisPerson);

// cancel the request with optional parameters
var cancelAddParticipantOperationOptions = new CancelAddParticipantOperationOptions(addParticipantResponse.Value.InvitationId)
{
    OperationContext = "operationContext",
    OperationCallbackUri = new Uri("uri_endpoint"); // Sending event to a non-default endpoint.
}
await callConnection.CancelAddParticipantOperationAsync(cancelAddParticipantOperationOptions);

Remover um participante de uma chamada

var removeThisUser = new CommunicationUserIdentifier("<user_id>"); 

// remove a participant from the call with optional parameters
var removeParticipantOptions = new RemoveParticipantOptions(removeThisUser)
{
    OperationContext = "operationContext",
    OperationCallbackUri = new Uri("uri_endpoint"); // Sending event to a non-default endpoint.
}

RemoveParticipantsResult result = await callConnection.RemoveParticipantAsync(removeParticipantOptions);

RemoveParticipant publicará um evento RemoveParticipantSucceeded ou RemoveParticipantFailed, juntamente com um evento ParticipantUpdated fornecendo a lista mais recente de participantes na chamada. O participante removido será omitido da lista.
Diagrama da sequência para remover um participante da chamada.

Desligar uma chamada

A ação Desligar pode ser usada para remover seu aplicativo da chamada ou para encerrar uma chamada de grupo definindo o parâmetro forEveryone como true. Para uma chamada individual, desligar encerrará a chamada com o outro participante por padrão.

_ = await callConnection.HangUpAsync(forEveryone: true); 

O evento CallDisconnected é publicado depois que a ação hangUp é concluída com êxito.

Obter informações sobre um participante da chamada

CallParticipant participantInfo = await callConnection.GetParticipantAsync(new CommunicationUserIdentifier("<user_id>"));

Obter informações sobre todos os participantes da chamada

List<CallParticipant> participantList = (await callConnection.GetParticipantsAsync()).Value.ToList(); 

Obter as informações mais recentes sobre uma chamada

CallConnectionProperties callConnectionProperties = await callConnection.GetCallConnectionPropertiesAsync();