Cómo controlar y dirigir las llamadas con Automatización de llamadas

La automatización de llamadas usa una interfaz de API REST para recibir solicitudes de acciones y proporcionar respuestas que notifiquen si la solicitud se ha enviado correctamente o no. Debido a la naturaleza asincrónica de las llamadas, la mayoría de las acciones tienen eventos correspondientes que se desencadenan cuando la acción se completa correctamente o se produce un error. En esta guía se tratan las acciones disponibles para dirigir las llamadas, como CreateCall, Transfer, Redirect y la administración de participantes. Las acciones van acompañadas de código de ejemplo sobre cómo invocar la acción indicada y diagramas de secuencia que describen los eventos que se esperan después de invocar una acción. Estos diagramas ayudarán a visualizar cómo programar la aplicación de servicio con la automatización de llamadas.

La automatización de llamadas admite otras acciones para administrar los medios y la grabación de llamadas que tienen guías separadas.

Como requisito previo, se recomienda leer estos artículos para sacar el máximo partido a esta guía:

  1. Guía de conceptos de la automatización de llamadas que describe el modelo de programación de eventos de acción y las devoluciones de llamada de evento.
  2. Obtenga información sobre los identificadores de usuario, como CommunicationUserIdentifier y PhoneNumberIdentifier, que se usan en esta guía.

Para todos los ejemplos de código, client es el objeto CallAutomationClient que se puede crear tal como se muestra y callConnection es el objeto CallConnection que se obtiene de la respuesta Answer o CreateCall. También se puede obtener de los eventos de devolución de llamada que recibe la aplicación.

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

Realización de una llamada saliente

Puede realizar una llamada 1:1 o grupal a un usuario de comunicación o a un número de teléfono (número público o propiedad de Communication Services). Al llamar a un punto de conexión RTC, también debe proporcionar un número de teléfono que se usará como identificador de llamada de origen y que se mostrará en la notificación de llamada al punto de conexión RTC de destino. Para realizar una llamada a un usuario de Communication Services, deberá proporcionar un objeto CommunicationUserIdentifier en lugar 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);

Al realizar una llamada grupal que incluya un número de teléfono, debe proporcionar un número de teléfono que se usa como número de identificador de llamada al punto de conexión RTC.

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);

La respuesta le proporciona el objeto CallConnection, que puede usar para realizar otras acciones en esta llamada una vez establecida la conexión. Una vez que se responde a la llamada, se publicarán dos eventos en el punto de conexión de devolución de llamada que ha proporcionado anteriormente:

  1. Evento CallConnected que notifica que la llamada se ha establecido con el destinatario.
  2. Evento ParticipantsUpdated que contiene la lista más reciente de participantes en la llamada. Diagrama de secuencia para colocar una llamada saliente.

Conexión a una llamada (en versión preliminar)

La acción Conectar permite a su servicio establecer una conexión con una llamada en curso y realizar acciones sobre ella. Esto resulta útil para gestionar una llamada de Salas o cuando las aplicaciones cliente inician una llamada 1:1 o de grupo de la que no forma parte la automatización de llamadas. La conexión se establece mediante la propiedad CallLocator y puede ser de los tipos ServerCallLocator, GroupCallLocator y RoomCallLocator. Estos ID se pueden encontrar cuando se establece originalmente la llamada o se crea una Sala, y también se publican como parte del evento CallStarted.

Para conectarse a cualquier llamada de grupo o 1:1, use ServerCallLocator. Si inició una llamada mediante GroupCallId, también puede usar 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 conectarse a una llamada de Salas, use RoomCallLocator que toma RoomId. Obtenga más información sobre Salas y cómo se puede usar la API de automatización de llamadas para administrar las llamadas de Salas en curso.

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);

Una respuesta correcta le proporciona el objeto CallConnection que puede utilizar para realizar otras acciones en esta llamada. Se publicarán dos eventos en el punto de conexión de devolución de llamada que ha proporcionado anteriormente:

  1. Evento CallConnected que notifica que se ha conectado correctamente a la llamada.
  2. Evento ParticipantsUpdated que contiene la lista más reciente de participantes en la llamada.

En cualquier momento después de una conexión correcta, si su servicio se desconecta de esta llamada se le notificará a través de un evento CallDisconected. Si no se conecta a la llamada en primer lugar, se produce el evento ConnectFailed.

Diagrama de secuencia para conectarse a la llamada.

Respuesta a una llamada entrante

Una vez que se haya suscrito para recibir notificaciones de llamadas entrantes en su recurso, responderá a una llamada entrante. Al responder a una llamada, es necesario proporcionar una dirección URL de devolución de llamada. Communication Services publica todos los eventos posteriores relacionados con esta llamada a esa dirección 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; 

La respuesta le proporciona el objeto CallConnection, que puede usar para realizar otras acciones en esta llamada una vez establecida la conexión. Una vez que se responde a la llamada, se publicarán dos eventos en el punto de conexión de devolución de llamada que ha proporcionado anteriormente:

  1. Evento CallConnected que notifica que la llamada se ha establecido con el autor de llamada.
  2. Evento ParticipantsUpdated que contiene la lista más reciente de participantes en la llamada.

Diagrama de secuencia para responder a una llamada entrante.

Rechazo de una llamada

Puede optar por rechazar una llamada entrante tal y como se muestra a continuación. Se puede proporcionar un motivo de rechazo: none, busy o forbidden. Si no se proporciona ningún motivo, se elige "none" de forma predeterminada.

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

No se publica ningún evento para la acción de rechazo.

Redireccionamiento de una llamada

Puede optar por redirigir una llamada entrante a otro punto de conexión sin responderla. Al redirigir una llamada, se elimina la posibilidad de que la aplicación controle la llamada mediante la automatización de llamadas.

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 redirigir la llamada a un número de teléfono, construya el destino y el identificador de la persona que llama con 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);

No se publica ningún evento para redireccionamiento. Si el destino es un usuario de Communication Services o un número de teléfono propiedad del recurso, generará un nuevo evento IncomingCall con el campo "to" establecido en el destino especificado.

Transferencia de un participante en la llamada

Cuando la aplicación responde a una llamada o hace una llamada saliente a un punto de conexión, ese punto de conexión se puede transferir a otro punto de conexión de destino. Al transferir una llamada 1:1, se elimina la aplicación de la llamada y, así, se elimina su capacidad de controlar la llamada mediante la automatización de llamadas. La invitación a llamar al destino mostrará el identificador de llamada del punto de conexión que se está transfiriendo. No se admite proporcionar un identificador de llamador personalizado.

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);

Cuando la aplicación responde a una llamada de grupo o coloca una llamada de grupo saliente a un punto de conexión o agrega un participante a una llamada de 1:1, se puede transferir un punto de conexión desde la llamada a otro punto de conexión de destino, excepto el punto de conexión de automatización de llamadas. La transferencia de un participante en una llamada de grupo quita el punto de conexión que se transfiere de la llamada. La invitación a llamar al destino mostrará el identificador de llamada del punto de conexión que se está transfiriendo. No se admite proporcionar un identificador de llamador personalizado.

// 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);

En el diagrama de secuencia se muestra el flujo esperado cuando la aplicación realiza una llamada saliente y, a continuación, la transfiere a otro punto de conexión.

Diagrama de secuencia para realizar una llamada 1:1 y, a continuación, transferirla.

Incorporación de un participante a una llamada

Puede agregar un participante (usuario o número de teléfono de Communication Services) a una llamada existente. Al agregar un número de teléfono, es obligatorio proporcionar un identificador de llamada. Este identificador de llamada se mostrará en la notificación de llamada al participante que se agrega.

// 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 agregar un usuario de Communication Services, proporcione un objeto CommunicationUserIdentifier en lugar de PhoneNumberIdentifier. El identificador de llamada de origen no es obligatorio en este caso.

AddParticipant publicará un evento AddParticipantSucceeded o AddParticipantFailed, junto con un elemento ParticipantUpdated que proporciona la lista de participantes en la llamada más reciente.

Diagrama de secuencia para agregar un participante a la llamada.

Cancelación de una solicitud de incorporación de participantes

// 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);

Eliminación de un participante de una llamada

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á un evento RemoveParticipantSucceeded o RemoveParticipantFailed, junto con un evento ParticipantUpdated que proporciona la lista de participantes en la llamada más reciente. El participante quitado se omite de la lista.
Diagrama de secuencia para quitar un participante de la llamada.

Colgar una llamada

La acción de colgar se puede usar para quitar la aplicación de la llamada o para finalizar una llamada de grupo al establecer el parámetro forEveryone en true. En una llamada 1:1, al colgar se finalizará la llamada con el otro participante de forma predeterminada.

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

El evento CallDisconnected se publica una vez que la acción hangUp se ha completado correctamente.

Obtención de información sobre un participante en la llamada

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

Obtención de información sobre todos los participantes en la llamada

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

Obtención de la información más reciente sobre una llamada

CallConnectionProperties callConnectionProperties = await callConnection.GetCallConnectionPropertiesAsync();