你当前正在访问 Microsoft Azure Global Edition 技术文档网站。 如果需要访问由世纪互联运营的 Microsoft Azure 中国技术文档网站,请访问 https://docs.azure.cn

使用呼叫自动化控制并引导呼叫

通话自动化使用 REST API 接口来接收操作请求,并提供响应以告知请求是否已成功提交。 由于调用的异步性质,大多数操作在成功完成或失败时会触发相应的事件。 本文介绍用于指导电话操作的动作,例如CreateCallTransferRedirect,以及参与者管理。 示例代码演示如何调用特定操作。 序列图描述调用作后预期的事件。 此图可帮助你可视化如何使用呼叫自动化对服务应用程序进行编程。

呼叫自动化支持其他操作来管理呼叫媒体和录制,这些功能都有单独的文章。

Prerequisites

  • 介绍操作事件编程模型和事件回调的通话自动化概念指南
  • 了解本文中使用的用户标识符CommunicationUserIdentifierPhoneNumberIdentifier

对于所有代码示例, clientCallAutomationClient 可以创建的对象,如下所示。 此外,callConnection是你从CallConnectionAnswer响应中获取的CreateCall对象。 还可以从应用程序收到的回调事件中获取它。

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

发起传出通话

可以向通信服务用户或电话号码(公用电话号码或 Azure 通信服务拥有的电话号码)发起一对一或群组通话。 呼叫公用电话交换网 (PSTN) 终端时,还需提供一个电话号码,该号码用于作为源来电 ID,并作为拨打目标 PSTN 终端时的呼叫通知进行显示。

若要向 Azure 通信服务用户发出调用,需要提供对象 CommunicationUserIdentifier 而不是 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);

进行包含电话号码的组呼叫时,必须提供一个电话号码,以用作 PSTN 终结点的呼叫方 ID 号码。

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

响应提供了一个 CallConnection 对象,可用于在连接后对此调用执行进一步操作。 接听电话后,以下两个事件将发布到先前提供的回调终结点:

  • CallConnected:通知主叫方已建立呼叫。

  • ParticipantsUpdated:包含通话中参与者的最新列表。

    显示呼出呼叫顺序的顺序图。

如果调用失败,则会收到一个 CallDisconnected 事件和一个 CreateCallFailed 包含错误代码的事件,以便进一步进行故障排除。 有关错误代码的详细信息,请参阅 调用端响应代码疑难解答

连接到通话

连接操作使您的服务能够与正在进行的通话建立连接,并在通话上执行操作。 此功能在管理会议室通话时非常有用,或者当客户端应用程序启动一对一或群组通话时(不包括呼叫自动化)也同样适用。 使用属性 CallLocator 建立连接。 类型选项是 ServerCallLocatorGroupCallLocatorRoomCallLocator。 可以在最初建立呼叫或创建会议室时找到这些 ID,也可以作为 CallStarted 事件的一部分发布。

若要连接到任何 1:1 或组呼叫,请使用 ServerCallLocator。 如果您使用 GroupCallId 来启动呼叫,还可以使用 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);

若要连接到会议室呼叫,请使用 RoomCallLocator,这需要 RoomId。 详细了解 会议室 以及如何使用呼叫自动化 API 管理正在进行的会议室呼叫

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

成功的响应提供一个可以用于对此调用执行进一步操作的CallConnection对象。 两个事件被发布到您之前提供的回调终结点。

  • CallConnected:提醒你已成功连接到通话。
  • ParticipantsUpdated:包含通话中参与者的最新列表。

在成功连接后的任何时刻,如果服务与此调用断开连接,则你会收到 CallDisconnected 事件的通知。 未能在第一位置连接到调用会导致 ConnectFailed 事件。

显示连接到调用的顺序的关系图。

接听来电

订阅接收资源的 传入呼叫通知 后,可以接听传入呼叫。 接听呼叫时,需要提供回调 URL。 Azure 通信服务会发布有关此 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; 

响应提供给您一个 CallConnection 对象,您可以在连接后使用它执行进一步操作。 接听电话后,以下两个事件将发布到先前提供的回调终结点:

  • CallConnected:通知主叫方已建立呼叫。
  • ParticipantsUpdated:包含通话中参与者的最新列表。

显示接听来电顺序的图示。

如果回答操作失败,您将收到带有错误代码的事件,以进一步进行故障排除。 有关错误代码的详细信息,请参阅 调用端响应代码疑难解答

拒绝通话

可以拒绝传入呼叫。 拒绝的原因是 NoneBusyForbidden。 如果未提供任何内容,则默认值为 None

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

不会针对拒绝操作发布任何事件。

重定向通话

可以将传入呼叫重定向到另一终结点,而无需应答。 重定向调用可消除应用程序使用呼叫自动化控制调用的能力。

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

若要将通话重定向到某个电话号码,请使用 PhoneNumberIdentifier 构造目标和呼叫者 ID。

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

不会针对重定向发布任何事件。 如果目标是 Azure 通信服务用户或资源拥有的电话号码,则会生成一个新 IncomingCall 事件,并将 to 字段设置为指定的目标。

在通话中转移参与者

当应用程序接听呼叫或向终结点发出出站调用时,应用可以将终结点传输到另一个目标终结点。 转移 1:1 通话会将您的应用程序从通话中移除,并解除其通过呼叫自动化控制通话的能力。 对目标的呼叫邀请会显示要转移的终结点的调用方 ID。 不支持提供自定义调用方 ID。

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

当应用程序应答组呼叫、向终结点发出出站组呼叫或将参与者添加到 1:1 呼叫时,应用可以将终结点从呼叫转移到另一个目标终结点(呼叫自动化终结点除外)。 在群组呼叫中转接参与者会删除从呼叫转移的终结点。 对目标的呼叫邀请会显示要转移的终结点的调用方 ID。 不支持提供自定义调用方 ID。

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

序列图显示了当应用程序发起出站通话,然后将其转接到另一个终结点时的预期流程。

此图显示了进行 1:1 通话并转接通话的顺序。

向通话添加参与者

可以将参与者(例如 Azure 通信服务用户或电话号码)添加到现有呼叫。 添加电话号码时,必须提供呼叫方 ID。 此来电号码在呼叫通知中显示给新增的参与者。

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

若要添加 Azure 通信服务用户,请提供 CommunicationUserIdentifier 而不是 PhoneNumberIdentifier。 在这种情况下,源呼叫方 ID 不是必需的。

接下来,AddParticipant发布一个AddParticipantSucceededAddParticipantFailed事件,并由ParticipantUpdated提供通话中参与者的最新列表。

显示将参与者添加到通话的步骤的示意图。

取消添加参与者请求

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

将参与者从一个通话转移到另外一个通话

使用 Azure 通信服务呼叫自动化 SDK,可以使用 MoveParticipants API 将参与者从一个正在进行的调用移动到另一个调用中。 这可实现动态路由和灵活的呼叫业务流程-在将翻译器移动到医生-患者呼叫或将客户从大厅呼叫转移到活动支持呼叫等方案中很常见。

示例方案:

  • 医生 + 译者房间路由 — 将单独拨入的译者移入主通话中。

  • 大厅呼叫转移 – 将参与者保存在单独的呼叫中,直到获准加入主呼叫。

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

// CallConnectionId for the call that you want to move the participant from
var fromCallId = "<callConnectionId>";

// Move a participant from another call to current call with optional parameters
var moveParticipantsOptions = new MoveParticipantOptions(
    new List<CommunicationIdentifier> { targetParticipant }, 
    fromCallId)
{
    OperationContext = "operationContext",
    OperationCallbackUri = new Uri("uri_endpoint") // Sending event to a non-default endpoint.
};

MoveParticipantsResult result = await callConnection.MoveParticipantsAsync(moveParticipantsOptions);

MoveParticipants 会将 MoveParticipantSucceeded 或 MoveParticipantFailed 事件发布到目标呼叫。

删除通话参与者

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发布RemoveParticipantSucceededRemoveParticipantFailed事件,并发布提供通话中参与者最新列表的ParticipantUpdated事件。 从列表中省略已删除的参与者。

显示删除通话参与者步骤的示意图。

挂断通话

可以使用hangUp操作,通过将forEveryone参数设置为true,来从调用中删除应用程序或终止组调用。 对于 1:1 呼叫, hangUp 默认终止与其他参与者的通话。

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

CallDisconnected 动作成功完成后,hangUp 事件被发布。

获取有关某个通话参与者的信息

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

获取有关所有通话参与者的信息

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

获取有关呼叫的最新信息

CallConnectionProperties callConnectionProperties = await callConnection.GetCallConnectionPropertiesAsync();