如何透過通話自動化來控制和引導通話

通話自動化會使用 REST API 介面來接收動作要求,並提供回應以通知是否有成功提交要求。 由於通話的非同步本質,大部分動作都會在動作順利完成或失敗時觸發對應的事件。 本指南涵蓋可用於引導通話的動作,例如 CreateCall、Transfer、Redirect 和管理參與者。 動作會隨附範例程式碼,以說明如何叫用上述動作,並有順序圖會說明叫用動作之後所預期的事件。 這些圖表可讓您透過視覺化方式,了解如何透過通話自動化來撰寫服務應用程式。

通話自動化還支援其他各種動作,可用來管理個別指南的通話媒體和錄製。

注意

通話自動化目前不支援會議室通話。

作為必要條件,建議您閱讀下列文章,以充分利用本指南:

  1. 通話自動化概念指南,會說明動作事件程式設計模型和事件回呼。
  2. 了解本指南中使用的使用者識別碼,例如 CommunicationUserIdentifier 和 PhoneNumberIdentifier。

在所有程式碼範例中,client 是 CallAutomationClient 物件,可以如所示加以建立,callConnection 則是從 Answer 或 CreateCall 回應取得的 CallConnection 物件。 您也可以從應用程式收到的回呼事件來取得。

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

向外撥打電話

您可以向通訊使用者或電話號碼 (公用或通訊服務擁有的號碼) 撥打 1 對 1 通話或群組通話。 在撥打電話至 PSTN 端點時,您也需要提供電話號碼,以作為來源來電者識別碼,並顯示在目標 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 端點的來電者識別碼。

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 事件包含通話中的最新參與者清單。 Sequence diagram for placing an outbound call.

接聽來電

在已訂閱要接收資源的來電通知後,您將接聽來電。 在接聽來電時,必須提供回呼 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 事件包含通話中的最新參與者清單。

Sequence diagram for answering an incoming call.

拒絕通話

您可以選擇拒絕來電,如下所示。 您可以提供拒絕原因:無、忙碌或禁止。 如果未提供任何原因,則預設會選擇無。

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建構目標和來電者識別碼。

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' 欄位設定為您指定的目標。

轉接通話中的參與者

當您的應用程式接聽通話或對端點撥打電話時,該端點可以轉接至另一個目的地端點。 轉接 1 對 1 通話會將應用程式從通話中移除,進而讓應用程式無法使用通話自動化來控制通話。 目標的通話邀請將顯示轉接端點的來電者識別碼。 不支援提供自訂來電者識別碼。

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 通話,端點可從通話轉接至其他目的地端點,但通話自動化端點除外。 轉接群組通話中的參與者會移除從通話轉接的端點。 目標的通話邀請將顯示轉接端點的來電者識別碼。 不支援提供自訂來電者識別碼。

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

順序圖會顯示預期流程,說明應用程式進行外撥通話,然後將通話轉接至另一個端點的情況。

Sequence diagram for placing a 1:1 call and then transferring it.

將參與者新增至通話

您可將參與者 (通訊服務使用者或電話號碼) 新增至現有通話。 新增電話號碼時,必須提供來電者識別碼。 此來電者識別碼會顯示在所新增參與者的通話通知上。

// 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。 在此情況下,來電者識別碼並非必要項目。

AddParticipant 將會發佈 AddParticipantSucceededAddParticipantFailed 事件,以及發佈 ParticipantUpdated 來提供通話中的最新參與者清單。

Sequence diagram for adding a participant to the call.

取消新增參與者要求

// 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 事件來提供通話中的最新參與者清單。 清單將省略已移除的參與者。
Sequence diagram for removing a participant from the call.

掛斷通話

掛斷動作可用來將應用程式從通話中移除,或藉由將 forEveryone 參數設定為 true 來終止群組通話。 在 1 對 1 通話中,掛斷動作預設會終止與其他參與者的通話。

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

一旦 hangUp 動作成功完成,就會發佈 CallDisconnected 事件。

取得通話參與者的相關資訊

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

取得所有通話參與者的相關資訊

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

取得通話的最新資訊

CallConnectionProperties callConnectionProperties = await callConnection.GetCallConnectionPropertiesAsync();