Share via


Inicio rápido: cómo realizar una llamada saliente mediante la automatización de llamadas

Las API de automatización de llamadas de Azure Communication Services son una manera eficaz de crear experiencias de llamada interactivas. En este inicio rápido, explicamos una manera de realizar una llamada saliente y de reconocer varios eventos en la llamada.

Requisitos previos

Código de ejemplo

Descargue o clone el código de ejemplo de inicio rápido desde GitHub.

Vaya a la carpeta CallAutomation_OutboundCalling y abra la solución en un editor de código.

Configurar y hospedar Azure DevTunnel

Azure DevTunnels es un servicio de Azure que permite compartir servicios web locales hospedados en internet. Ejecute los comandos para conectar el entorno de desarrollo local a la red pública de internet. DevTunnels crea una dirección URL de punto de conexión persistente que permite el acceso anónimo. Usamos este punto de conexión para notificar a la aplicación los eventos de llamada desde el servicio de automatización de llamadas de Azure Communication Services.

devtunnel create --allow-anonymous
devtunnel port create -p 8080
devtunnel host

Actualización de la configuración de la aplicación

A continuación, actualice el archivo Program.cs con los siguientes valores:

  • acsConnectionString: la cadena de conexión del recurso de Azure Communication Services. Puede encontrar la cadena de conexión de Azure Communication Services mediante las instrucciones que se indican aquí.
  • callbackUriHost: una vez que haya inicializado el host de DevTunnel, actualice este campo con ese URI.
  • acsPhonenumber: actualice este campo con el número de teléfono de Azure Communication Services que ha adquirido. Dicho número de teléfono debe usar el formato de número de teléfono E164 (por ejemplo, +18881234567)
  • targetPhonenumber: actualice el campo con el número de teléfono al que quiere que la aplicación llame. Dicho número de teléfono debe usar el formato de número de teléfono E164 (por ejemplo, +18881234567)
  • cognitiveServiceEndpoint: actualiza el campo con el punto de conexión de servicios de Azure AI.
  • targetTeamsUserId: (opcional) actualiza el campo con el id. de usuario de Microsoft Teams que quieres agregar a la llamada. Consulta Uso de Graph API para obtener el id. de usuario de Teams.
// Your ACS resource connection string 
var acsConnectionString = "<ACS_CONNECTION_STRING>"; 

// Your ACS resource phone number will act as source number to start outbound call 
var acsPhonenumber = "<ACS_PHONE_NUMBER>"; 
 
// Target phone number you want to receive the call. 
var targetPhonenumber = "<TARGET_PHONE_NUMBER>";

// Base url of the app 
var callbackUriHost = "<CALLBACK_URI_HOST_WITH_PROTOCOL>"; 

// Your cognitive service endpoint 
var cognitiveServiceEndpoint = "<COGNITIVE_SERVICE_ENDPOINT>";

// (Optional) User Id of the target teams user you want to receive the call.
var targetTeamsUserId = "<TARGET_TEAMS_USER_ID>";

Realización de una llamada saliente

Para realizar la llamada de salida desde Azure Communication Services, en este ejemplo se usa el targetPhonenumber que definiste anteriormente en la aplicación a fin de crear la llamada mediante la API CreateCallAsync. Este código realizará una llamada saliente usando el número de teléfono de destino.

PhoneNumberIdentifier target = new PhoneNumberIdentifier(targetPhonenumber);
PhoneNumberIdentifier caller = new PhoneNumberIdentifier(acsPhonenumber);
var callbackUri = new Uri(callbackUriHost + "/api/callbacks");
CallInvite callInvite = new CallInvite(target, caller);
var createCallOptions = new CreateCallOptions(callInvite, callbackUri) {
  CallIntelligenceOptions = new CallIntelligenceOptions() {
    CognitiveServicesEndpoint = new Uri(cognitiveServiceEndpoint)
  }
};
CreateCallResult createCallResult = await callAutomationClient.CreateCallAsync(createCallOptions);

Controlar eventos de automatización de llamadas

Anteriormente en nuestra aplicación, registramos el callbackUriHost en el servicio de automatización de llamadas. El host indica el punto de conexión que el servicio requiere para notificarnos los eventos de llamada que se producen. Después, podemos recorrer en iteración los eventos y detectar los eventos específicos que la aplicación quiere comprender. En el código que aparece a continuación, respondemos al evento CallConnected.

app.MapPost("/api/callbacks", async (CloudEvent[] cloudEvents, ILogger < Program > logger) => {
  foreach(var cloudEvent in cloudEvents) {
    logger.LogInformation($"Event received: {JsonConvert.SerializeObject(cloudEvent)}");
    CallAutomationEventBase parsedEvent = CallAutomationEventParser.Parse(cloudEvent);
    logger.LogInformation($"{parsedEvent?.GetType().Name} parsedEvent received for call connection id: {parsedEvent?.CallConnectionId}");
    var callConnection = callAutomationClient.GetCallConnection(parsedEvent.CallConnectionId);
    var callMedia = callConnection.GetCallMedia();
    if (parsedEvent is CallConnected) {
      //Handle Call Connected Event
    }
  }
});

(Opcional) Incorporación de un usuario de Microsoft Teams a la llamada

Puedes agregar un usuario de Microsoft Teams a la llamada mediante el método AddParticipantAsync con un elemento MicrosoftTeamsUserIdentifier y el id. del usuario de Teams. Primero debes completar el paso de requisito previo: Autorización para el recurso de Azure Communication Services a fin de habilitar la llamada a usuarios de Microsoft Teams. Opcionalmente, también puedes pasar un elemento SourceDisplayName a fin de controlar el texto que se muestra en la notificación del sistema para el usuario de Teams.

await callConnection.AddParticipantAsync(
    new CallInvite(new MicrosoftTeamsUserIdentifier(targetTeamsUserId))
    {
        SourceDisplayName = "Jack (Contoso Tech Support)"
    });

Iniciar la grabación de una llamada

El servicio de automatización de llamadas también permite iniciar la grabación y almacenar grabaciones de llamadas de voz y vídeo. Puede obtener más información sobre las distintas funcionalidades de las API de grabación de llamadas aquí.

CallLocator callLocator = new ServerCallLocator(parsedEvent.ServerCallId);
var recordingResult = await callAutomationClient.GetCallRecording().StartAsync(new StartRecordingOptions(callLocator));
recordingId = recordingResult.Value.RecordingId;

Reproducir mensaje de bienvenida y reconocer

Con TextSource, puedes proporcionar al servicio el texto que quieres sintetizar y usar para el mensaje de bienvenida. El servicio de automatización de llamadas de Azure Communication Services reproduce este mensaje tras el evento CallConnected.

A continuación, pasamos el texto a CallMediaRecognizeChoiceOptions y, después, llamamos a StartRecognizingAsync. Esto permite que la aplicación reconozca la opción que elige el autor de la llamada.

if (parsedEvent is CallConnected callConnected) {
  logger.LogInformation($"Start Recording...");
  CallLocator callLocator = new ServerCallLocator(parsedEvent.ServerCallId);
  var recordingResult = await callAutomationClient.GetCallRecording().StartAsync(new StartRecordingOptions(callLocator));
  recordingId = recordingResult.Value.RecordingId;

  var choices = GetChoices();

  // prepare recognize tones 
  var recognizeOptions = GetMediaRecognizeChoiceOptions(mainMenu, targetPhonenumber, choices);

  // Send request to recognize tones 
  await callMedia.StartRecognizingAsync(recognizeOptions);
}

CallMediaRecognizeChoiceOptions GetMediaRecognizeChoiceOptions(string content, string targetParticipant, List < RecognitionChoice > choices, string context = "") {
  var playSource = new TextSource(content) {
    VoiceName = SpeechToTextVoice
  };

  var recognizeOptions = new CallMediaRecognizeChoiceOptions(targetParticipant: new PhoneNumberIdentifier(targetParticipant), choices) {
    InterruptCallMediaOperation = false,
      InterruptPrompt = false,
      InitialSilenceTimeout = TimeSpan.FromSeconds(10),
      Prompt = playSource,
      OperationContext = context
  };
  return recognizeOptions;
}

List < RecognitionChoice > GetChoices() {
  return new List < RecognitionChoice > {
    new RecognitionChoice("Confirm", new List < string > {
      "Confirm",
      "First",
      "One"
    }) {
      Tone = DtmfTone.One
    },
    new RecognitionChoice("Cancel", new List < string > {
      "Cancel",
      "Second",
      "Two"
    }) {
      Tone = DtmfTone.Two
    }
  };
}

Control de eventos de elección

La Automatización de llamadas de Azure Communication Services desencadena el api/callbacks en el webhook que tenemos configurado y nos notificará el evento RecognizeCompleted. El evento nos ofrece la capacidad de responder a la entrada recibida y de desencadenar una acción. Después, la aplicación reproduce un mensaje al autor de la llamada en función de la entrada específica recibida.

if (parsedEvent is RecognizeCompleted recognizeCompleted) {
  var choiceResult = recognizeCompleted.RecognizeResult as ChoiceResult;
  var labelDetected = choiceResult?.Label;
  var phraseDetected = choiceResult?.RecognizedPhrase;

  // If choice is detected by phrase, choiceResult.RecognizedPhrase will have the phrase detected,  
  // If choice is detected using dtmf tone, phrase will be null  
  logger.LogInformation("Recognize completed succesfully, labelDetected={labelDetected}, phraseDetected={phraseDetected}", labelDetected, phraseDetected);

  var textToPlay = labelDetected.Equals(ConfirmChoiceLabel, StringComparison.OrdinalIgnoreCase) ? ConfirmedText : CancelText;

  await HandlePlayAsync(callMedia, textToPlay);
}

async Task HandlePlayAsync(CallMedia callConnectionMedia, string text) {
  // Play goodbye message 
  var GoodbyePlaySource = new TextSource(text) {
    VoiceName = "en-US-NancyNeural"
  };
  await callConnectionMedia.PlayToAllAsync(GoodbyePlaySource);
}

Colgar y detener la grabación

Por último, cuando detectamos una condición que hace que tenga sentido finalizar la llamada, podemos usar el método HangUpAsync para colgar.

if ((parsedEvent is PlayCompleted) || (parsedEvent is PlayFailed))
{
    logger.LogInformation($"Stop recording and terminating call.");
    callAutomationClient.GetCallRecording().Stop(recordingId);
    await callConnection.HangUpAsync(true);
}

Ejecución del código

Para ejecutar la aplicación con VS Code, abra una ventana de terminal y ejecute el siguiente comando

dotnet run

Requisitos previos

Código de ejemplo

Descargue o clone el código de ejemplo de inicio rápido desde GitHub.

Vaya a la carpeta CallAutomation_OutboundCalling y abra la solución en un editor de código.

Configurar y hospedar Azure DevTunnel

Azure DevTunnels es un servicio de Azure que permite compartir servicios web locales hospedados en internet. Ejecute los comandos de DevTunnel para conectar el entorno de desarrollo local a la red pública de internet. A continuación, DevTunnels crea un túnel con una dirección URL de punto de conexión persistente que permite el acceso anónimo. Azure Communication Services usa este punto de conexión para notificar a la aplicación los eventos de llamada desde el servicio de automatización de llamadas de Azure Communication Services.

devtunnel create --allow-anonymous
devtunnel port create -p MY_SPRINGAPP_PORT
devtunnel host

Actualización de la configuración de la aplicación

A continuación, abra el archivo application.yml en la carpeta /resources para configurar los valores siguientes:

  • connectionstring: la cadena de conexión del recurso de Azure Communication Services. Puede encontrar la cadena de conexión de Azure Communication Services mediante las instrucciones que se indican aquí.
  • basecallbackuri: una vez que haya inicializado el host de DevTunnel, actualice este campo con ese URI.
  • callerphonenumber: actualice este campo con el número de teléfono de Azure Communication Services que ha adquirido. Dicho número de teléfono debe usar el formato de número de teléfono E164 (por ejemplo, +18881234567)
  • targetphonenumber: actualice el campo con el número de teléfono al que quiere que la aplicación llame. Dicho número de teléfono debe usar el formato de número de teléfono E164 (por ejemplo, +18881234567)
  • cognitiveServiceEndpoint: actualiza el campo con el punto de conexión de servicios de Azure AI.
  • targetTeamsUserId: (opcional) actualiza el campo con el id. de usuario de Microsoft Teams que quieres agregar a la llamada. Consulta Uso de Graph API para obtener el id. de usuario de Teams.
acs:
  connectionstring: <YOUR ACS CONNECTION STRING> 
  basecallbackuri: <YOUR DEV TUNNEL ENDPOINT> 
  callerphonenumber: <YOUR ACS PHONE NUMBER ex. "+1425XXXAAAA"> 
  targetphonenumber: <YOUR TARGET PHONE NUMBER ex. "+1425XXXAAAA"> 
  cognitiveServiceEndpoint: <YOUR COGNITIVE SERVICE ENDPOINT>
  targetTeamsUserId: <(OPTIONAL) YOUR TARGET TEAMS USER ID ex. "ab01bc12-d457-4995-a27b-c405ecfe4870">

Realizar una llamada saliente y reproducir elementos multimedia

Para realizar la llamada de salida desde Azure Communication Services, en este ejemplo se usa el elemento targetphonenumber que definiste en el archivo application.yml a fin de crear la llamada mediante la API createCallWithResponse.

PhoneNumberIdentifier caller = new PhoneNumberIdentifier(appConfig.getCallerphonenumber());
PhoneNumberIdentifier target = new PhoneNumberIdentifier(appConfig.getTargetphonenumber());
CallInvite callInvite = new CallInvite(target, caller);
CreateCallOptions createCallOptions = new CreateCallOptions(callInvite, appConfig.getCallBackUri());
CallIntelligenceOptions callIntelligenceOptions = new CallIntelligenceOptions().setCognitiveServicesEndpoint(appConfig.getCognitiveServiceEndpoint());
createCallOptions = createCallOptions.setCallIntelligenceOptions(callIntelligenceOptions);
Response<CreateCallResult> result = client.createCallWithResponse(createCallOptions, Context.NONE);

(Opcional) Incorporación de un usuario de Microsoft Teams a la llamada

Puedes agregar un usuario de Microsoft Teams a la llamada mediante el método addParticipant con un elemento MicrosoftTeamsUserIdentifier y el id. del usuario de Teams. Primero debes completar el paso de requisito previo: Autorización para el recurso de Azure Communication Services a fin de habilitar la llamada a usuarios de Microsoft Teams. Opcionalmente, también puedes pasar un elemento SourceDisplayName a fin de controlar el texto que se muestra en la notificación del sistema para el usuario de Teams.

client.getCallConnection(callConnectionId).addParticipant(
    new CallInvite(new MicrosoftTeamsUserIdentifier(targetTeamsUserId))
        .setSourceDisplayName("Jack (Contoso Tech Support)"));

Iniciar la grabación de una llamada

El servicio de automatización de llamadas también permite iniciar la grabación y almacenar grabaciones de llamadas de voz y vídeo. Puede obtener más información sobre las distintas funcionalidades de las API de grabación de llamadas aquí.

ServerCallLocator serverCallLocator = new ServerCallLocator(
    client.getCallConnection(callConnectionId)
        .getCallProperties()
        .getServerCallId());
        
StartRecordingOptions startRecordingOptions = new StartRecordingOptions(serverCallLocator);

Response<RecordingStateResult> response = client.getCallRecording()
    .startWithResponse(startRecordingOptions, Context.NONE);

recordingId = response.getValue().getRecordingId();

Responder a eventos de llamada

Anteriormente en nuestra aplicación, registramos el basecallbackuri en el servicio de automatización de llamadas. El URI indica el punto de conexión que el servicio usará para notificarnos los eventos de llamada que se produzcan. Después, podemos recorrer en iteración los eventos y detectar los eventos específicos que la aplicación quiere comprender. En el código que aparece a continuación, respondemos al evento CallConnected.

List<CallAutomationEventBase> events = CallAutomationEventParser.parseEvents(reqBody);
for (CallAutomationEventBase event : events) {
    String callConnectionId = event.getCallConnectionId();
    if (event instanceof CallConnected) {
        log.info("CallConnected event received");
    }
    else if (event instanceof RecognizeCompleted) {
        log.info("Recognize Completed event received");
    }
}

Reproducir mensaje de bienvenida y reconocer

Con TextSource, puedes proporcionar al servicio el texto que quieres sintetizar y usar para el mensaje de bienvenida. El servicio de automatización de llamadas de Azure Communication Services reproduce este mensaje tras el evento CallConnected.

A continuación, pasamos el texto a CallMediaRecognizeChoiceOptions y, después, llamamos a StartRecognizingAsync. Esto permite que la aplicación reconozca la opción que elige el autor de la llamada.

var playSource = new TextSource().setText(content).setVoiceName("en-US-NancyNeural");

var recognizeOptions = new CallMediaRecognizeChoiceOptions(new PhoneNumberIdentifier(targetParticipant), getChoices())
  .setInterruptCallMediaOperation(false)
  .setInterruptPrompt(false)
  .setInitialSilenceTimeout(Duration.ofSeconds(10))
  .setPlayPrompt(playSource)
  .setOperationContext(context);

client.getCallConnection(callConnectionId)
  .getCallMedia()
  .startRecognizing(recognizeOptions);

private List < RecognitionChoice > getChoices() {
  var choices = Arrays.asList(
    new RecognitionChoice().setLabel(confirmLabel).setPhrases(Arrays.asList("Confirm", "First", "One")).setTone(DtmfTone.ONE),
    new RecognitionChoice().setLabel(cancelLabel).setPhrases(Arrays.asList("Cancel", "Second", "Two")).setTone(DtmfTone.TWO)
  );

  return choices;
}

Control de eventos de elección

La Automatización de llamadas de Azure Communication Services desencadena el api/callbacks en el webhook que tenemos configurado y nos notificará el evento RecognizeCompleted. El evento nos ofrece la capacidad de responder a la entrada recibida y de desencadenar una acción. Después, la aplicación reproduce un mensaje al autor de la llamada en función de la entrada específica recibida.

else if (event instanceof RecognizeCompleted) {
  log.info("Recognize Completed event received");

  RecognizeCompleted acsEvent = (RecognizeCompleted) event;

  var choiceResult = (ChoiceResult) acsEvent.getRecognizeResult().get();

  String labelDetected = choiceResult.getLabel();

  String phraseDetected = choiceResult.getRecognizedPhrase();

  log.info("Recognition completed, labelDetected=" + labelDetected + ", phraseDetected=" + phraseDetected + ", context=" + event.getOperationContext());

  String textToPlay = labelDetected.equals(confirmLabel) ? confirmedText : cancelText;

  handlePlay(callConnectionId, textToPlay);
}

private void handlePlay(final String callConnectionId, String textToPlay) {
  var textPlay = new TextSource()
    .setText(textToPlay)
    .setVoiceName("en-US-NancyNeural");

  client.getCallConnection(callConnectionId)
    .getCallMedia()
    .playToAll(textPlay);
}

Finalización de la llamada

Por último, cuando detectamos una condición que hace que tenga sentido finalizar la llamada, podemos usar el método hangUp para colgar.

client.getCallConnection(callConnectionId).hangUp(true);

Ejecución del código

Navegue hasta el directorio que contiene el archivo pom.xml y use los siguientes comandos de mvn:

  • Compilar la aplicación: mvn compile
  • Compilar el paquete: mvn package
  • Ejecutar la aplicación: mvn exec:java

Requisitos previos

Código de ejemplo

Descargue o clone el código de ejemplo de inicio rápido desde GitHub.

Vaya a la carpeta CallAutomation_OutboundCalling y abra la solución en un editor de código.

Configuración del entorno

Descargue el código de ejemplo, vaya al directorio del proyecto, ejecute el comando npm que instala las dependencias necesarias y configure el entorno de desarrollador.

npm install

Configurar y hospedar Azure DevTunnel

Azure DevTunnels es un servicio de Azure que permite compartir servicios web locales hospedados en internet. Use los comandos de la CLI de DevTunnel para conectar el entorno de desarrollo local a la red pública de internet. Usamos este punto de conexión para notificar a la aplicación los eventos de llamada desde el servicio de automatización de llamadas de Azure Communication Services.

devtunnel create --allow-anonymous
devtunnel port create -p 8080
devtunnel host

Actualización de la configuración de la aplicación

A continuación, actualice el archivo .env con los siguientes valores:

  • CONNECTION_STRING: la cadena de conexión del recurso de Azure Communication Services. Puede encontrar la cadena de conexión de Azure Communication Services mediante las instrucciones que se indican aquí.
  • CALLBACK_URI: una vez que haya inicializado el host de DevTunnel, actualice este campo con ese URI.
  • TARGET_PHONE_NUMBER: actualice el campo con el número de teléfono al que quiere que la aplicación llame. Dicho número de teléfono debe usar el formato de número de teléfono E164 (por ejemplo, +18881234567)
  • ACS_RESOURCE_PHONE_NUMBER: actualice este campo con el número de teléfono de Azure Communication Services que ha adquirido. Dicho número de teléfono debe usar el formato de número de teléfono E164 (por ejemplo, +18881234567)
  • COGNITIVE_SERVICES_ENDPOINT: actualiza el campo con el punto de conexión de servicios de Azure AI.
  • TARGET_TEAMS_USER_ID: (opcional) actualiza el campo con el id. de usuario de Microsoft Teams que quieres agregar a la llamada. Consulta Uso de Graph API para obtener el id. de usuario de Teams.
CONNECTION_STRING="<YOUR_CONNECTION_STRING>" 
ACS_RESOURCE_PHONE_NUMBER ="<YOUR_ACS_NUMBER>" 
TARGET_PHONE_NUMBER="<+1XXXXXXXXXX>" 
CALLBACK_URI="<VS_TUNNEL_URL>" 
COGNITIVE_SERVICES_ENDPOINT="<COGNITIVE_SERVICES_ENDPOINT>" 
TARGET_TEAMS_USER_ID="<TARGET_TEAMS_USER_ID>"

Realizar una llamada saliente y reproducir elementos multimedia

Para realizar la llamada saliente desde Azure Communication Services, usa el número de teléfono que proporcionaste al entorno. Asegúrese de que el número de teléfono tiene el formato de número de teléfono E164 (por ejemplo, +18881234567)

El código realiza una llamada saliente usando el target_phone_number que ha proporcionado y realiza una llamada saliente a ese número:

const callInvite: CallInvite = {
	targetParticipant: callee,
	sourceCallIdNumber: {
		phoneNumber: process.env.ACS_RESOURCE_PHONE_NUMBER || "",
	},
};

const options: CreateCallOptions = {
	cognitiveServicesEndpoint: process.env.COGNITIVE_SERVICES_ENDPOINT
};

console.log("Placing outbound call...");
acsClient.createCall(callInvite, process.env.CALLBACK_URI + "/api/callbacks", options);

(Opcional) Incorporación de un usuario de Microsoft Teams a la llamada

Puedes agregar un usuario de Microsoft Teams a la llamada mediante el método addParticipant con la propiedad microsoftTeamsUserId. Primero debes completar el paso de requisito previo: Autorización para el recurso de Azure Communication Services a fin de habilitar la llamada a usuarios de Microsoft Teams. Opcionalmente, también puedes pasar un elemento sourceDisplayName a fin de controlar el texto que se muestra en la notificación del sistema para el usuario de Teams.

await acsClient.getCallConnection(callConnectionId).addParticipant({
    targetParticipant: { microsoftTeamsUserId: process.env.TARGET_TEAMS_USER_ID },
    sourceDisplayName: "Jack (Contoso Tech Support)"
});

Iniciar la grabación de una llamada

El servicio de automatización de llamadas también permite iniciar la grabación y almacenar grabaciones de llamadas de voz y vídeo. Puede obtener más información sobre las distintas funcionalidades de las API de grabación de llamadas aquí.

const callLocator: CallLocator = {
    id: serverCallId,
    kind: "serverCallLocator",
};

const recordingOptions: StartRecordingOptions = {
    callLocator: callLocator,
};

const response = await acsClient.getCallRecording().start(recordingOptions);

recordingId = response.recordingId;

Responder a eventos de llamada

Anteriormente en nuestra aplicación, registramos el CALLBACK_URI en el servicio de automatización de llamadas. El URI indica el punto de conexión que el servicio usa para notificarnos los eventos de llamada que se producen. Después, podemos recorrer en iteración los eventos y detectar los eventos específicos que la aplicación quiere comprender. Respondemos al evento CallConnected para recibir notificaciones e iniciar operaciones de bajada. Con TextSource, puedes proporcionar al servicio el texto que quieres sintetizar y usar para el mensaje de bienvenida. El servicio de automatización de llamadas de Azure Communication Services reproduce este mensaje tras el evento CallConnected.

A continuación, pasamos el texto a CallMediaRecognizeChoiceOptions y, después, llamamos a StartRecognizingAsync. Esto permite que la aplicación reconozca la opción que elige el autor de la llamada.

callConnectionId = eventData.callConnectionId;
serverCallId = eventData.serverCallId;
console.log("Call back event received, callConnectionId=%s, serverCallId=%s, eventType=%s", callConnectionId, serverCallId, event.type);
callConnection = acsClient.getCallConnection(callConnectionId);
const callMedia = callConnection.getCallMedia();

if (event.type === "Microsoft.Communication.CallConnected") {
 	console.log("Received CallConnected event");
 	await startRecording();
	await startRecognizing(callMedia, mainMenu, "");
}

async function startRecognizing(callMedia: CallMedia, textToPlay: string, context: string) {
	const playSource: TextSource = {
 		text: textToPlay,
 		voiceName: "en-US-NancyNeural",
 		kind: "textSource"
 	};

 	const recognizeOptions: CallMediaRecognizeChoiceOptions = {
 		choices: await getChoices(),
 		interruptPrompt: false,
 		initialSilenceTimeoutInSeconds: 10,
 		playPrompt: playSource,
 		operationContext: context,
 		kind: "callMediaRecognizeChoiceOptions"
 	};

 	await callMedia.startRecognizing(callee, recognizeOptions)
 }

Control de eventos de elección

La Automatización de llamadas de Azure Communication Services desencadena el api/callbacks en el webhook que tenemos configurado y nos notificará el evento RecognizeCompleted. El evento nos ofrece la capacidad de responder a la entrada recibida y de desencadenar una acción. Después, la aplicación reproduce un mensaje al autor de la llamada en función de la entrada específica recibida.

else if (event.type === "Microsoft.Communication.RecognizeCompleted") { 
	if(eventData.recognitionType === "choices"){ 
        	console.log("Recognition completed, event=%s, resultInformation=%s",eventData, eventData.resultInformation); 
        	var context = eventData.operationContext; 
            	const labelDetected = eventData.choiceResult.label;  
            	const phraseDetected = eventData.choiceResult.recognizedPhrase; 
            	console.log("Recognition completed, labelDetected=%s, phraseDetected=%s, context=%s", labelDetected, phraseDetected, eventData.operationContext); 
            	const textToPlay = labelDetected === confirmLabel ? confirmText : cancelText;            
            	await handlePlay(callMedia, textToPlay); 
        } 
}  
 
async function handlePlay(callConnectionMedia:CallMedia, textContent:string){ 
	const play : TextSource = { text:textContent , voiceName: "en-US-NancyNeural", kind: "textSource"} 
	await callConnectionMedia.playToAll([play]); 
} 

Finalización de la llamada

Por último, cuando detectamos una condición que hace que tenga sentido finalizar la llamada, podemos usar el método hangUp() para colgar.

  await acsClient.getCallRecording().stop(recordingId);
  callConnection.hangUp(true);

Ejecución del código

Para ejecutar la aplicación, abra una ventana de terminal y ejecute el siguiente comando:

  npm run dev

Requisitos previos

Código de ejemplo

Descargue o clone el código de ejemplo de inicio rápido desde GitHub.

Vaya a la carpeta CallAutomation_OutboundCalling y abra la solución en un editor de código.

Configuración del entorno de Python

Cree y active el entorno de Python e instale los paquetes necesarios mediante el comando siguiente. Puede obtener más información sobre cómo administrar paquetes aquí

pip install -r requirements.txt

Configurar y hospedar Azure DevTunnel

Azure DevTunnels es un servicio de Azure que permite compartir servicios web locales hospedados en internet. Use los comandos para conectar el entorno de desarrollo local a la red pública de internet. DevTunnels crea un túnel con una dirección URL de punto de conexión persistente que permite el acceso anónimo. Usamos este punto de conexión para notificar a la aplicación los eventos de llamada desde el servicio de automatización de llamadas de Azure Communication Services.

devtunnel create --allow-anonymous
devtunnel port create -p 8080
devtunnel host

Actualización de la configuración de la aplicación

A continuación, actualice el archivo main.py con los siguientes valores:

  • ACS_CONNECTION_STRING: la cadena de conexión del recurso de Azure Communication Services. Puede encontrar la cadena de conexión de Azure Communication Services mediante las instrucciones que se indican aquí.
  • CALLBACK_URI_HOST: una vez que haya inicializado el host de DevTunnel, actualice este campo con ese URI.
  • TARGET_PHONE_NUMBER: actualice el campo con el número de teléfono al que quiere que la aplicación llame. Dicho número de teléfono debe usar el formato de número de teléfono E164 (por ejemplo, +18881234567)
  • ACS_PHONE_NUMBER: actualice este campo con el número de teléfono de Azure Communication Services que ha adquirido. Dicho número de teléfono debe usar el formato de número de teléfono E164 (por ejemplo, +18881234567)
  • COGNITIVE_SERVICES_ENDPOINT: actualiza el campo con el punto de conexión de servicios de Azure AI.
  • TARGET_TEAMS_USER_ID: (opcional) actualiza el campo con el id. de usuario de Microsoft Teams que quieres agregar a la llamada. Consulta Uso de Graph API para obtener el id. de usuario de Teams.
# Your ACS resource connection string 
ACS_CONNECTION_STRING = "<ACS_CONNECTION_STRING>" 

# Your ACS resource phone number will act as source number to start outbound call 
ACS_PHONE_NUMBER = "<ACS_PHONE_NUMBER>" 

# Target phone number you want to receive the call. 
TARGET_PHONE_NUMBER = "<TARGET_PHONE_NUMBER>" 

# Callback events URI to handle callback events. 
CALLBACK_URI_HOST = "<CALLBACK_URI_HOST_WITH_PROTOCOL>" 
CALLBACK_EVENTS_URI = CALLBACK_URI_HOST + "/api/callbacks" 

#Your Cognitive service endpoint 
COGNITIVE_SERVICES_ENDPOINT = "<COGNITIVE_SERVICES_ENDPOINT>" 

#(OPTIONAL) Your target Microsoft Teams user Id ex. "ab01bc12-d457-4995-a27b-c405ecfe4870"
TARGET_TEAMS_USER_ID = "<TARGET_TEAMS_USER_ID>"

Realización de una llamada saliente

Para realizar la llamada saliente desde Azure Communication Services, primero debes proporcionar el número de teléfono que quieres que reciba la llamada. Para simplificarlo, puede actualizar target_phone_number con un número de teléfono que tenga el formato de número de teléfono E164 (por ejemplo, +18881234567)

Realice una llamada saliente con el target_phone_number que ha proporcionado:

target_participant = PhoneNumberIdentifier(TARGET_PHONE_NUMBER) 
source_caller = PhoneNumberIdentifier(ACS_PHONE_NUMBER) 
call_invite = CallInvite(target=target_participant, source_caller_id_number=source_caller) 
call_connection_properties = call_automation_client.create_call(call_invite, CALLBACK_EVENTS_URI, 
cognitive_services_endpoint=COGNITIVE_SERVICES_ENDPOINT) 
    app.logger.info("Created call with connection id: %s",
call_connection_properties.call_connection_id) 
return redirect("/") 

(Opcional) Incorporación de un usuario de Microsoft Teams a la llamada

Puedes agregar un usuario de Microsoft Teams a la llamada mediante el método add_participant con un elemento MicrosoftTeamsUserIdentifier y el id. del usuario de Teams. Primero debes completar el paso de requisito previo: Autorización para el recurso de Azure Communication Services a fin de habilitar la llamada a usuarios de Microsoft Teams. Opcionalmente, también puedes pasar un elemento source_display_name a fin de controlar el texto que se muestra en la notificación del sistema para el usuario de Teams.

call_connection_client.add_participant(target_participant = CallInvite(
    target = MicrosoftTeamsUserIdentifier(user_id=TARGET_TEAMS_USER_ID),
    source_display_name = "Jack (Contoso Tech Support)"))

Iniciar la grabación de una llamada

El servicio de automatización de llamadas también permite iniciar la grabación y almacenar grabaciones de llamadas de voz y vídeo. Puede obtener más información sobre las distintas funcionalidades de las API de grabación de llamadas aquí.

recording_properties = call_automation_client.start_recording(ServerCallLocator(event.data['serverCallId']))
recording_id = recording_properties.recording_id

Responder a eventos de llamada

Anteriormente en nuestra aplicación, registramos el CALLBACK_URI_HOST en el servicio de automatización de llamadas. El URI indica el punto de conexión que el servicio usa para notificarnos los eventos de llamada que se producen. Después, podemos recorrer en iteración los eventos y detectar los eventos específicos que la aplicación quiere comprender. En el código que aparece a continuación, respondemos al evento CallConnected.

@app.route('/api/callbacks', methods=['POST'])
def callback_events_handler():
    for event_dict in request.json:
        event = CloudEvent.from_dict(event_dict)
        if event.type == "Microsoft.Communication.CallConnected":
            # Handle Call Connected Event
            ...
            return Response(status=200)

Reproducir mensaje de bienvenida y reconocer

Con TextSource, puedes proporcionar al servicio el texto que quieres sintetizar y usar para el mensaje de bienvenida. El servicio de automatización de llamadas de Azure Communication Services reproduce este mensaje tras el evento CallConnected.

A continuación, pasamos el texto a CallMediaRecognizeChoiceOptions y, después, llamamos a StartRecognizingAsync. Esto permite que la aplicación reconozca la opción que elige el autor de la llamada.


get_media_recognize_choice_options( 
    call_connection_client=call_connection_client, 
    text_to_play=MainMenu,  
    target_participant=target_participant, 
    choices=get_choices(),context="") 

def get_media_recognize_choice_options(call_connection_client: CallConnectionClient, text_to_play: str, target_participant:str, choices: any, context: str): 
    play_source =  TextSource (text= text_to_play, voice_name= SpeechToTextVoice) 
    call_connection_client.start_recognizing_media( 
        input_type=RecognizeInputType.CHOICES, 

        target_participant=target_participant,
        choices=choices, 
        play_prompt=play_source, 
        interrupt_prompt=False, 
        initial_silence_timeout=10, 
        operation_context=context 
    ) 

def get_choices(): 
    choices = [ 
        RecognitionChoice(label = ConfirmChoiceLabel, phrases= ["Confirm", "First", "One"], tone = DtmfTone.ONE), 
        RecognitionChoice(label = CancelChoiceLabel, phrases= ["Cancel", "Second", "Two"], tone = DtmfTone.TWO) 
    ] 
return choices 

Control de eventos de elección

La Automatización de llamadas de Azure Communication Services desencadena el api/callbacks en el webhook que tenemos configurado y nos notificará el evento RecognizeCompleted. El evento nos ofrece la capacidad de responder a la entrada recibida y de desencadenar una acción. Después, la aplicación reproduce un mensaje al autor de la llamada en función de la entrada específica recibida.

elif event.type == "Microsoft.Communication.RecognizeCompleted":
	app.logger.info("Recognize completed: data=%s", event.data)
if event.data['recognitionType'] == "choices":
	labelDetected = event.data['choiceResult']['label'];
phraseDetected = event.data['choiceResult']['recognizedPhrase'];
app.logger.info("Recognition completed, labelDetected=%s, phraseDetected=%s, context=%s", labelDetected, phraseDetected, event.data.get('operationContext'))
if labelDetected == ConfirmChoiceLabel:
	textToPlay = ConfirmedText
else:
	textToPlay = CancelText
handle_play(call_connection_client = call_connection_client, text_to_play = textToPlay)
def handle_play(call_connection_client: CallConnectionClient, text_to_play: str):
	play_source = TextSource(text = text_to_play, voice_name = SpeechToTextVoice)
call_connection_client.play_media_to_all(play_source)

Finalización de la llamada

Por último, cuando detectamos una condición que hace que tenga sentido finalizar la llamada, podemos usar el método hang_up() para colgar. Por último, también podemos detener de forma segura la operación de grabación de llamadas.

call_automation_client.stop_recording(recording_id)
call_connection_client.hang_up(is_for_everyone=True)

Ejecución del código

Para ejecutar la aplicación con VS Code, abra una ventana de terminal y ejecute el siguiente comando

python main.py