本文內容
通話自動化會使用 REST API 介面來接收動作要求,並提供回應以通知是否有成功提交要求。 由於通話的非同步本質,大部分動作都會在動作順利完成或失敗時觸發對應的事件。 本指南涵蓋開發人員可在通話期間使用的動作,例如傳送 DTMF 和連續 DTMF 辨識。 動作隨附如何叫用所述動作的範例程式碼。
通話自動化還支援其他各種動作,這些動作可用來管理本指南未包含的通話和錄音。
注意
通話自動化目前無法與 Microsoft Teams 交互操作。 不支援使用通話自動化與 Teams 使用者通話、將通話重新導向他們,或對他們播放音訊等動作。
作為必要條件,建議您閱讀下列文章,以充分利用本指南:
通話自動化概念指南 ,會說明動作事件程式設計模型和事件回呼。
了解本指南中使用的使用者識別碼 ,例如 CommunicationUserIdentifier 和 PhoneNumberIdentifier。
深入了解如何使用通話自動化來控制和引導通話 ,這會教導您如何處理通話的基本概念。
在所有程式碼範例中,client
是 CallAutomationClient 物件,可以如所示加以建立,callConnection
則是從 Answer 或 CreateCall 回應取得的 CallConnection 物件。 您也可以從應用程式收到的回呼事件來取得。
var callAutomationClient = new CallAutomationClient("<Azure Communication Services connection string>");
CallAutomationClient callAutomationClient = new CallAutomationClientBuilder()
.connectionString("<Azure Communication Services connection string>")
.buildClient();
callAutomationClient = new CallAutomationClient(("<Azure Communication Services connection string>");
call_automation_client = CallAutomationClient.from_connection_string((("<Azure Communication Services connection string>")
傳送 DTMF
您可以將 DTMF 音調傳送給外部參與者,這在您已在通話時很有用,而且需要邀請另一位有分機號碼或有 IVR 功能表可瀏覽的參與者。
注意
這僅支援外部 PSTN 參與者,且支援一次最多傳送 18 個音調。
SendDtmfAsync 方法
將 DTMF 音調清單傳送給外部參與者。
var tones = new DtmfTone[] { DtmfTone.One, DtmfTone.Two, DtmfTone.Three, DtmfTone.Pound };
var sendDtmfTonesOptions = new SendDtmfTonesOptions(tones, new PhoneNumberIdentifier(calleePhonenumber))
{
OperationContext = "dtmfs-to-ivr"
};
var sendDtmfAsyncResult = await callAutomationClient.GetCallConnection(callConnectionId)
.GetCallMedia()
.SendDtmfTonesAsync(sendDtmfTonesOptions);
List<DtmfTone> tones = Arrays.asList(DtmfTone.ONE, DtmfTone.TWO, DtmfTone.THREE, DtmfTone.POUND);
SendDtmfTonesOptions options = new SendDtmfTonesOptions(tones, new PhoneNumberIdentifier(c2Target));
options.setOperationContext("dtmfs-to-ivr");
callAutomationClient.getCallConnectionAsync(callConnectionId)
.getCallMediaAsync()
.sendDtmfTonesWithResponse(options)
.block();
const tones = [DtmfTone.One, DtmfTone.Two, DtmfTone.Three];
const sendDtmfTonesOptions: SendDtmfTonesOptions = {
operationContext: "dtmfs-to-ivr"
};
const result: SendDtmfTonesResult = await callAutomationClient.getCallConnection(callConnectionId)
.getCallMedia()
.sendDtmfTones(tones, {
phoneNumber: c2Target
}, sendDtmfTonesOptions);
console.log("sendDtmfTones, result=%s", result);
tones = [DtmfTone.ONE, DtmfTone.TWO, DtmfTone.THREE]
result = call_automation_client.get_call_connection(call_connection_id).send_dtmf_tones(
tones = tones,
target_participant = PhoneNumberIdentifier(c2_target),
operation_context = "dtmfs-to-ivr")
app.logger.info("Send dtmf, result=%s", result)
當您的應用程式傳送這些 DTMF 音調時,您會收到事件更新。 您可使用 SendDtmfTonesCompleted
和 SendDtmfTonesFailed
事件,在應用程式中建立商業規則,以判斷後續步驟。
SendDtmfTonesCompleted 事件的範例
if (acsEvent is SendDtmfTonesCompleted sendDtmfCompleted)
{
logger.LogInformation("Send DTMF succeeded, context={context}", sendDtmfCompleted.OperationContext);
}
if (acsEvent instanceof SendDtmfTonesCompleted) {
SendDtmfTonesCompleted event = (SendDtmfTonesCompleted) acsEvent;
log.info("Send dtmf succeeded: context=" + event.getOperationContext());
}
if (event.type === "Microsoft.Communication.SendDtmfTonesCompleted") {
console.log("Send dtmf succeeded: context=%s", eventData.operationContext);
}
if event.type == "Microsoft.Communication.SendDtmfTonesCompleted":
app.logger.info("Send dtmf succeeded: context=%s", event.data['operationContext']);
SendDtmfTonesFailed 的範例
if (acsEvent is SendDtmfTonesFailed sendDtmfFailed)
{
logger.LogInformation("Send dtmf failed: result={result}, context={context}",
sendDtmfFailed.ResultInformation?.Message, sendDtmfFailed.OperationContext);
}
if (acsEvent instanceof SendDtmfTonesFailed) {
SendDtmfTonesFailed event = (SendDtmfTonesFailed) acsEvent;
log.info("Send dtmf failed: result=" + event.getResultInformation().getMessage() + ", context="
+ event.getOperationContext());
}
if (event.type === "Microsoft.Communication.SendDtmfTonesFailed") {
console.log("sendDtmfTones failed: result=%s, context=%s",
eventData.resultInformation.message,
eventData.operationContext);
}
if event.type == "Microsoft.Communication.SendDtmfTonesFailed":
app.logger.info("Send dtmf failed: result=%s, context=%s", event.data['resultInformation']['message'], event.data['operationContext'])
連續 DTMF 辨識
您可以訂閱在整個通話中接收連續 DTMF 音調。 當目標參與者在其鍵盤上按下按鍵時,您的應用程式會收到 DTMF 音調。 當參與者按下按鍵時,這些音調會逐一傳送到您的應用程式。
StartContinuousDtmfRecognitionAsync 方法
開始偵測參與者所傳送的 DTMF 音調。
await callAutomationClient.GetCallConnection(callConnectionId)
.GetCallMedia()
.StartContinuousDtmfRecognitionAsync(new PhoneNumberIdentifier(c2Target), "dtmf-reco-on-c2");
ContinuousDtmfRecognitionOptions options = new ContinuousDtmfRecognitionOptions(new PhoneNumberIdentifier(c2Target));
options.setOperationContext("dtmf-reco-on-c2");
callAutomationClient.getCallConnectionAsync(callConnectionId)
.getCallMediaAsync()
.startContinuousDtmfRecognitionWithResponse(options)
.block();
const continuousDtmfRecognitionOptions: ContinuousDtmfRecognitionOptions = {
operationContext: "dtmf-reco-on-c2"
};
await callAutomationclient.getCallConnection(callConnectionId)
.getCallMedia()
.startContinuousDtmfRecognition({
phoneNumber: c2Target
}, continuousDtmfRecognitionOptions);
call_automation_client.get_call_connection(
call_connection_id
).start_continuous_dtmf_recognition(
target_participant=PhoneNumberIdentifier(c2_target),
operation_context="dtmf-reco-on-c2",
)
app.logger.info("Started continuous DTMF recognition")
當您的應用程式不再希望從參與者接收 DTMF 音調時,您可以使用 StopContinuousDtmfRecognitionAsync
方法讓 Azure 通訊服務知道停止偵測 DTMF 音調。
StopContinuousDtmfRecognitionAsync
停止偵測參與者所傳送的 DTMF 音調。
var continuousDtmfRecognitionOptions = new ContinuousDtmfRecognitionOptions(new PhoneNumberIdentifier(callerPhonenumber))
{
OperationContext = "dtmf-reco-on-c2"
};
var startContinuousDtmfRecognitionAsyncResult = await callAutomationClient.GetCallConnection(callConnectionId)
.GetCallMedia()
.StartContinuousDtmfRecognitionAsync(continuousDtmfRecognitionOptions);
ContinuousDtmfRecognitionOptions options = new ContinuousDtmfRecognitionOptions(new PhoneNumberIdentifier(c2Target));
options.setOperationContext("dtmf-reco-on-c2");
callAutomationClient.getCallConnectionAsync(callConnectionId)
.getCallMediaAsync()
.stopContinuousDtmfRecognitionWithResponse(options)
.block();
const continuousDtmfRecognitionOptions: ContinuousDtmfRecognitionOptions = {
operationContext: "dtmf-reco-on-c2"
};
await callAutomationclient.getCallConnection(callConnectionId)
.getCallMedia()
.stopContinuousDtmfRecognition({
phoneNumber: c2Target
}, continuousDtmfRecognitionOptions);
call_automation_client.get_call_connection(call_connection_id).stop_continuous_dtmf_recognition(
target_participant=PhoneNumberIdentifier(c2_target),
operation_context="dtmf-reco-on-c2")
app.logger.info("Stopped continuous DTMF recognition")
當這些動作成功或失敗時,您的應用程式就會收到事件更新。 您可使用這些事件來建立自訂商業規則,以設定應用程式在收到這些事件更新時需要採取的下一個步驟。
ContinuousDtmfRecognitionToneReceived 事件
如何處理成功偵測到的 DTMF 音調的範例。
if (acsEvent is ContinuousDtmfRecognitionToneReceived continuousDtmfRecognitionToneReceived)
{
logger.LogInformation("Tone detected: sequenceId={sequenceId}, tone={tone}",
continuousDtmfRecognitionToneReceived.SequenceId,
continuousDtmfRecognitionToneReceived.Tone);
}
if (acsEvent instanceof ContinuousDtmfRecognitionToneReceived) {
ContinuousDtmfRecognitionToneReceived event = (ContinuousDtmfRecognitionToneReceived) acsEvent;
log.info("Tone detected: sequenceId=" + event.getSequenceId()
+ ", tone=" + event.getTone().convertToString()
+ ", context=" + event.getOperationContext());
}
if (event.type === "Microsoft.Communication.ContinuousDtmfRecognitionToneReceived") {
console.log("Tone detected: sequenceId=%s, tone=%s, context=%s",
eventData.sequenceId,
eventData.tone,
eventData.operationContext);
}
if event.type == "Microsoft.Communication.ContinuousDtmfRecognitionToneReceived":
app.logger.info("Tone detected: sequenceId=%s, tone=%s, context=%s",
event.data['sequenceId'],
event.data['tone'],
event.data['operationContext'])
Azure 通訊服務提供 SequenceId
作為 ContinuousDtmfRecognitionToneReceived
事件的一部分,您的應用程式可用來重新建構參與者輸入 DTMF 音調的順序。
ContinuousDtmfRecognitionFailed 事件
如何處理 DTMF 音調偵測失敗的範例。
if (acsEvent is ContinuousDtmfRecognitionToneFailed continuousDtmfRecognitionToneFailed)
{
logger.LogInformation("Start continuous DTMF recognition failed, result={result}, context={context}",
continuousDtmfRecognitionToneFailed.ResultInformation?.Message,
continuousDtmfRecognitionToneFailed.OperationContext);
}
if (acsEvent instanceof ContinuousDtmfRecognitionToneFailed) {
ContinuousDtmfRecognitionToneFailed event = (ContinuousDtmfRecognitionToneFailed) acsEvent;
log.info("Tone failed: result="+ event.getResultInformation().getMessage()
+ ", context=" + event.getOperationContext());
}
if (event.type === "Microsoft.Communication.ContinuousDtmfRecognitionToneFailed") {
console.log("Tone failed: result=%s, context=%s", eventData.resultInformation.message, eventData.operationContext);
}
if event.type == "Microsoft.Communication.ContinuousDtmfRecognitionToneFailed":
app.logger.info(
"Tone failed: result=%s, context=%s",
event.data["resultInformation"]["message"],
event.data["operationContext"],
)
ContinuousDtmfRecogntionStopped 事件
當連續 DTMF 辨識停止時如何處理的範例,這可能是因為您的應用程式叫用了 StopContinuousDtmfRecognitionAsync
事件或因為通話已結束。
if (acsEvent is ContinuousDtmfRecognitionStopped continuousDtmfRecognitionStopped)
{
logger.LogInformation("Continuous DTMF recognition stopped, context={context}", continuousDtmfRecognitionStopped.OperationContext);
}
if (acsEvent instanceof ContinuousDtmfRecognitionStopped) {
ContinuousDtmfRecognitionStopped event = (ContinuousDtmfRecognitionStopped) acsEvent;
log.info("Tone stopped, context=" + event.getOperationContext());
}
if (event.type === "Microsoft.Communication.ContinuousDtmfRecognitionStopped") {
console.log("Tone stopped: context=%s", eventData.operationContext);
}
if event.type == "Microsoft.Communication.ContinuousDtmfRecognitionStopped":
app.logger.info("Tone stoped: context=%s", event.data["operationContext"])
保留
通話保留動作可讓開發人員暫時暫停參與者與系統或通話專員之間的交談。 這在參與者需要轉移到另一個通話專員或部門,或當通話專員需要諮詢背景主管才能繼續交談的案例中,這非常有用。 在此期間,您可以選擇對通話保留中的參與者播放音訊。
// Option 1: Hold without additional options
await callAutomationClient.GetCallConnection(callConnectionId)
.GetCallMedia().HoldAsync(c2Target);
/*
// Option 2: Hold with play source
PlaySource playSource = /* initialize playSource */;
await callAutomationClient.GetCallConnection(callConnectionId)
.GetCallMedia().HoldAsync(c2Target, playSource);
// Option 3: Hold with options
var holdOptions = new HoldOptions(target)
{
OperationCallbackUri = new Uri(""),
OperationContext = "holdcontext"
};
await callMedia.HoldAsync(holdOptions);
*/
// Option 1: Hold with options
PlaySource playSource = /* initialize playSource */;
HoldOptions holdOptions = new HoldOptions(target)
.setOperationCallbackUrl(appConfig.getBasecallbackuri())
.setPlaySource(playSource)
.setOperationContext("holdPstnParticipant");
client.getCallConnection(callConnectionId).getCallMedia().holdWithResponse(holdOptions, Context.NONE);
/*
// Option 2: Hold without additional options
client.getCallConnection(callConnectionId).getCallMedia().hold(target);
*/
// Option 1: Hold with options
const options = {
playSource: playSource,
operationContext: "holdUserContext",
operationCallbackUrl: "URL" // replace with actual callback URL
};
await callMedia.hold(targetuser, options);
/*
// Option 2: Hold without additional options
await callMedia.hold(targetuser);
*/
# Option 1: Hold without additional options
call_connection_client.hold(target_participant=PhoneNumberIdentifier(TARGET_PHONE_NUMBER))
'''
# Option 2: Hold with options
call_connection_client.hold(
target_participant=PhoneNumberIdentifier(TARGET_PHONE_NUMBER),
play_source=play_source,
operation_context="holdUserContext",
operation_callback_url="URL" # replace with actual callback URL
)
'''
取消保留
取消通話保留動作可讓開發人員繼續參與者與系統或通話專員之間之前暫停的交談。 當參與者被取消保留時,他們將能夠再次聽到系統或通話專員。
var unHoldOptions = new UnholdOptions(target)
{
OperationContext = "UnHoldPstnParticipant"
};
// Option 1
var UnHoldParticipant = await callMedia.UnholdAsync(unHoldOptions);
/*
// Option 2
var UnHoldParticipant = await callMedia.UnholdAsync(target);
*/
// Option 1
client.getCallConnection(callConnectionId).getCallMedia().unholdWithResponse(target, "unholdPstnParticipant", Context.NONE);
/*
// Option 2
client.getCallConnection(callConnectionId).getCallMedia().unhold(target);
*/
const unholdOptions = {
operationContext: "unholdUserContext"
};
// Option 1
await callMedia.unhold(target);
/*
// Option 2
await callMedia.unhold(target, unholdOptions);
*/
# Option 1
call_connection_client.unhold(target_participant=PhoneNumberIdentifier(TARGET_PHONE_NUMBER))
'''
# Option 2
call_connection_client.unhold(target_participant=PhoneNumberIdentifier(TARGET_PHONE_NUMBER), operation_context="holdUserContext")
'''
音訊串流 (公開預覽)
音訊串流可讓您訂閱進行中通話的即時音訊串流。 如需如何開始使用音訊串流以及如何開始使用音訊串流回呼事件的詳細資訊,請參閱 此頁面 。
實時轉譯 (公開預覽)
即時轉譯可讓您存取進行中通話音訊的實時轉譯。 如需如何開始使用即時轉譯和實時轉譯回呼事件的詳細資訊,請參閱 此頁面 。
下表說明如果先前的作業仍在執行/佇列中,允許執行/佇列的媒體作業。
現有作業
通話腿
允許
不允許
PlayToAll
主要
PlayToAll、Recognize(非群組通話)、PlayTo、Recognize(群組通話)、SendDTMF、StartContinuousDtmfRecognition
無
Recognize(非群組通話)
主要
PlayToAll、Recognize(非群組通話)、PlayTo、Recognize(群組通話)、SendDTMF、StartContinuousDtmfRecognition
無
PlayTo
Sub
PlayToAll, Recognize(非群組通話)
PlayTo、Recognize(群組通話)、SendDTMF、StartContinuousDtmfRecognition
Recognize(群組通話)
Sub
PlayToAll, Recognize(非群組通話)
PlayTo、Recognize(群組通話)、SendDTMF、StartContinuousDtmfRecognition
SendDTMF
Sub
PlayToAll, Recognize(非群組通話)
PlayTo、Recognize(群組通話)、SendDTMF、StartContinuousDtmfRecognition
StartContinuousDtmfRecognition
Sub
PlayToAll、Recognize(非群組通話)、PlayTo、Recognize(群組通話)、SendDTMF、StartContinuousDtmfRecognition
無