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

如何使用通话自动化操控通话

通话自动化使用 REST API 接口来接收操作请求,并提供响应以告知请求是否已成功提交。 由于通话的异步性,大多数操作将在操作成功完成或失败时触发相应的事件。 本指南将介绍可用于操控通话的操作,例如 CreateCall、转接、重定向和管理参与者。 操作随附了有关如何调用所述操作的示例代码,以及描述调用操作后预期发生的事件的序列图。 这些图可帮助你直观地了解如何使用通话自动化对服务应用程序进行编程。

通话自动化支持使用其他各种操作来管理具有单独指南的通话媒体和录音。

作为先决条件,我们建议阅读以下文章以充分理解本指南:

  1. 介绍操作事件编程模型和事件回调的通话自动化概念指南
  2. 了解本指南中使用的用户标识符,例如 CommunicationUserIdentifier 和 PhoneNumberIdentifier。

对于所有代码示例,client 是可以按示例所示创建的 CallAutomationClient 对象,callConnection 是从 Answer 或 CreateCall 响应中获取的 CallConnection 对象。 也可以从应用程序收到的回调事件中获取该对象。

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

发起传出通话

可以向通信用户或电话号码(公共电话号码或通信服务拥有的号码)发起一对一通话或群组通话。 呼叫 PSTN 终结点时,还需要提供一个电话号码作为源呼叫方 ID,该号码将显示在发送到目标 PSTN 终结点的通话通知中。 若要向通信服务用户发起通话,需要提供 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 对象,在连接后你可以使用该对象对此通话执行进一步的操作。 接听电话后,以下两个事件将发布到先前提供的回调终结点:

  1. CallConnected 事件,告知已与被呼叫方建立通话。
  2. ParticipantsUpdated 事件,其中包含最新的通话参与者列表。 发起出站通话的序列图。

如果呼叫失败,你将收到 CallDisconnectedCreateCallFailed 事件以及错误代码,以便进一步的故障排除(有关呼叫自动化错误代码的详细信息,请参阅此页面)。

连接到通话(预览版)

连接操作使服务能够与正在进行的调用建立连接,并对其执行操作。 这可用于管理会议室呼叫,或者在客户端应用程序启动呼叫自动化不属于的 1:1 或组调用时。 连接使用 CallLocator 属性建立,可以是以下类型:ServerCallLocator、GroupCallLocator 和 RoomCallLocator。 在最初建立呼叫或创建会议室时,还可以找到这些 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 对象,可以使用该对象对此通话执行进一步的操作。 以下两个事件将发布到先前提供的回调终结点:

  1. CallConnected 事件,通知你已成功连接到呼叫。
  2. ParticipantsUpdated 事件,其中包含最新的通话参与者列表。

在成功连接后的任何时间点,如果服务与此呼叫断开连接,将通过 CallDisconected 事件收到通知。 未能在第一位置连接到调用会导致 ConnectFailed 事件。

用于连接到呼叫的序列图。

应答传入呼叫

在资源中订阅接收来电通知后,将接听一通来电。 接听电话时,需要提供回调 URL。 通信服务会将有关此通话的所有后续事件发布到该 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 对象,在连接后你可以使用该对象对此通话执行进一步的操作。 接听电话后,以下两个事件将发布到先前提供的回调终结点:

  1. CallConnected 事件,告知已与呼叫方建立通话。
  2. ParticipantsUpdated 事件,其中包含最新的通话参与者列表。

接听来电的序列图。

拒绝通话

可以如下所示选择拒绝来电。 可以提供拒绝原因:无、忙碌或禁止。 如果未提供任何原因,则默认会选择“无”。

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

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

转接通话参与者

当应用程序接听通话或向某个终结点发起出站通话时,该终结点可以转接到另一个目标终结点。 转接一对一通话会从该通话中删除你的应用程序,从而导致它无法使用通话自动化来控制通话。 对目标的呼叫邀请将显示要转移的终结点的调用方 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);

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

发起一对一通话,然后转接通话的序列图。

向通话添加参与者

可以将一个参与者(通信服务用户或电话号码)添加到现有通话。 添加电话号码时,必须提供呼叫方 ID。 此呼叫方 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); 

若要添加通信服务用户,请提供 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);

删除通话参与者

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 事件。 从列表中省略已删除的参与者。
从通话中删除参与者的序列图。

挂断通话

使用挂断操作可以从通话中删除应用程序,或通过将 forEveryone 参数设置为 true 来终止群组通话。 对于一对一通话,挂断操作默认将终止与另一方的通话。

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

挂断操作成功完成后,将发布 CallDisconnected 事件。

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

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

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

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

获取有关通话的最新信息

CallConnectionProperties callConnectionProperties = await callConnection.GetCallConnectionPropertiesAsync();