Call Automation を使用して通話を制御および操作する方法

Call Automation は、REST API インターフェイスを使用してアクションの要求を受信し、要求が正常に送信されたかどうかを通知する応答を提供するものです。 通話の非同期性のため、ほとんどのアクションには、アクションが正常に完了または失敗したときにトリガーされる、対応するイベントがあります。 このガイドでは、CreateCall、転送、リダイレクト、参加者の管理など、通話の操作に使用できるアクションについて説明します。 アクションには、そのアクションを呼び出す方法を示すサンプル コードと、アクション呼び出し後に予期されるイベントを記述したシーケンス図が付属しています。 これらの図は、Call Automation を使用してサービス アプリケーションをプログラミングする方法を視覚化するのに役立ちます。

Call Automation では、別のガイドがある通話メディアと記録を管理するための他のさまざまなアクションがサポートされています。

このガイドを最大限に活用するには、前提条件として次の記事を参照することをお勧めします。

  1. Call Automation の概念ガイドでは、アクション イベント プログラミング モデルとイベント コールバックについて説明しています。
  2. このガイドで使用している CommunicationUserIdentifier や PhoneNumberIdentifier などのユーザー識別子についての説明。

すべてのコード サンプルについて、client は示されている方法で作成できる CallAutomationClient オブジェクトであり、callConnection は、Answer または CreateCall 応答から取得される CallConnection オブジェクトです。 アプリケーションで受信するコールバック イベントから取得することもできます。

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

発信通話を実行する

コミュニケーション ユーザーまたは電話番号 (パブリックまたは Communication Services 所有の番号) に対して一対一またはグループでの通話を発信できます。 PSTN エンドポイントを呼び出すときは、電話番号も指定する必要があります。これは発信元の発信者 ID として使用され、ターゲット PSTN エンドポイントへの呼び出し通知に表示されます。 Communication Services ユーザーへの通話を行うには、PhoneNumberIdentifier ではなく CommunicationUserIdentifier オブジェクトを指定する必要があります。

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 オブジェクトが提供されます。このオブジェクトを使用して、接続後にこの呼び出しに対してさらにアクションを実行できます。 通話に応答があると、前に指定したコールバック エンドポイントに 2 つのイベントが発行されます。

  1. 呼び出し先との通話が確立されたことを通知する CallConnected イベント。
  2. 通話参加者の最新リストを含む ParticipantsUpdated イベント。 発信通話を行う場合のシーケンス図。

通話が失敗した場合、詳細なトラブルシューティングを行うために、エラー コードを含む CallDisconnected および CreateCallFailed イベントが表示されます (Call Automation のエラー コードの詳細については、こちらのページを参照してください)。

通話に接続する (プレビュー段階)

接続アクションにより、サービスは進行中の呼び出しとの接続を確立し、それに対してアクションを実行できます。 これは、ルーム通話を管理する場合や、クライアント アプリケーションが呼び出し自動化の一部ではない 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);

ルーム通話に接続するには、RoomId を受け取る RoomCallLocator を使用します。 Rooms の詳細と、Call Automation API を使用して進行中の Rooms 通話を管理する方法を学習します。

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 オブジェクトが提供され、この呼び出しに対してさらにアクションを実行することができます。 前に指定したコールバック エンドポイントに 2 つのイベントが発行されます。

  1. 呼び出しに正常に接続したことを通知する CallConnected イベント。
  2. 通話参加者の最新リストを含む ParticipantsUpdated イベント。

接続が成功した後はいつでも、サービスがこの呼び出しから切断されると、CallDisconected イベントを介して通知されます。 最初の段階で呼び出しへの接続に失敗すると、ConnectFailed イベントが発生します。

呼び出しへの接続のシーケンス図。

着信に応答する

リソースへの着信通知を受信するようにサブスクライブしたら、着信に応答します。 呼び出しに応答するときは、コールバック URL を指定する必要があります。 この通話に関する後続のすべてのイベントが、Communication Services によってその 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 オブジェクトが提供されます。このオブジェクトを使用して、接続後にこの呼び出しに対してさらにアクションを実行できます。 通話に応答があると、前に指定したコールバック エンドポイントに 2 つのイベントが発行されます。

  1. 呼び出し元との通話が確立されたことを通知する CallConnected イベント。
  2. 通話参加者の最新リストを含む ParticipantsUpdated イベント。

着信通話に応答する場合のシーケンス図。

通話を拒否する

次に示すように、着信を拒否することを選択できます。 拒否の理由として、none、busy、または forbidden を指定できます。 何も指定しない場合、既定では none が選択されます。

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

拒否アクションのイベントは発行されません。

通話をリダイレクトする

着信に応答せずに別のエンドポイントにリダイレクトすることを選択できます。 通話をリダイレクトすると、アプリケーションで Call Automation を使用して通話を制御することはできなくなります。

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

リダイレクトのイベントは発行されません。 ターゲットが Communication Services ユーザーまたはリソースによって所有されている電話番号である場合、指定したターゲットが 'to' フィールドに設定された新しい IncomingCall イベントが生成されます。

通話中に参加者を転送する

アプリケーションで通話に応答するか、エンドポイントに発信通話を行った場合、そのエンドポイントを別の宛先エンドポイントに転送できます。 一対一の通話を転送すると、アプリケーションは通話から削除されるため、Call Automation を使用して通話を制御できなくなります。 ターゲットへの通話の招待には、転送されるエンドポイントの発信者 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);

シーケンス図は、アプリケーションで発信通話を実行し、それを別のエンドポイントに転送するときの、予想されるフローを示しています。

一対一の通話を発信し、それを転送する場合のシーケンス図。

通話に参加者を追加する

既存の通話に参加者 (Communication Services ユーザーまたは電話番号) を追加できます。 電話番号を追加する場合は、発信者 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); 

Communication Services ユーザーを追加するには、PhoneNumberIdentifier の代わりに CommunicationUserIdentifier を指定します。 この場合、発信者 ID は必須ではありません。

AddParticipant を使用すると、AddParticipantSucceeded または AddParticipantFailed イベントが、通話参加者の最新リストを提供する 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 を使用すると、RemoveParticipantSucceeded または RemoveParticipantFailed イベントが、通話参加者の最新リストを提供する ParticipantUpdated イベントと共に発行されます。 削除された参加者はリストから省略されます。
通話から参加者を削除する場合のシーケンス図。

通話を切断する

切断アクションを使用すると、アプリケーションを通話から削除したり、forEveryone パラメーターを true に設定してグループ通話を終了したりできます。 一対一の通話の場合、通話を切断すると、既定により、もう一方の参加者との通話が終了します。

_ = 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();