Edit

Share via


Control mid-call media actions with Call Automation

Call Automation uses a REST API interface to receive requests for actions and provide responses to notify whether the request was successfully submitted or not. Because of the asynchronous nature of calling, most actions have corresponding events that are triggered when the action finishes successfully or fails. This article covers the actions that are available to developers during calls, like SendDTMF and ContinuousDtmfRecognition. Actions are accompanied with sample code on how to invoke the particular action.

Call Automation supports other actions to manage calls and recordings that aren't included in this article.

Note

Call Automation currently doesn't interoperate with Microsoft Teams. Actions like making or redirecting a call to a Teams user or playing audio to a Teams user by using Call Automation aren't supported.

Prerequisites

For all the code samples, client is the CallAutomationClient object that you can create, as shown, and callConnection is the CallConnection object that you obtain from the Answer or CreateCall response. You can also obtain it from callback events that your application receives.

var callAutomationClient = new CallAutomationClient("<Azure Communication Services connection string>");

Send DTMF

You can send dual-tone multifrequency (DTMF) tones to an external participant. This capability might be useful when you're already on a call and need to invite another participant who has an extension number or uses an interactive voice response menu.

Note

This feature is supported only for external participants on public-switched telephone networks and supports sending a maximum of 18 tones at a time.

SendDtmfAsync method

Send a list of DTMF tones to an external participant.

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

When your application sends these DTMF tones, you receive event updates. You can use the SendDtmfTonesCompleted and SendDtmfTonesFailed events to create business logic in your application to determine the next steps.

An example of a SendDtmfTonesCompleted event:

if (acsEvent is SendDtmfTonesCompleted sendDtmfCompleted) 
{ 
    logger.LogInformation("Send DTMF succeeded, context={context}", sendDtmfCompleted.OperationContext); 
} 

An example of a SendDtmfTonesFailed event:

if (acsEvent is SendDtmfTonesFailed sendDtmfFailed) 
{ 
    logger.LogInformation("Send dtmf failed: result={result}, context={context}", 
        sendDtmfFailed.ResultInformation?.Message, sendDtmfFailed.OperationContext); 
} 

Continuous DTMF recognition

You can subscribe to receive continuous DTMF tones throughout the call. Your application receives DTMF tones when the targeted participant presses on a key on their keypad. The tones are sent to your application one by one as the participant presses on them.

StartContinuousDtmfRecognitionAsync method

Start detecting DTMF tones sent by a participant.

await callAutomationClient.GetCallConnection(callConnectionId) 
    .GetCallMedia() 
    .StartContinuousDtmfRecognitionAsync(new PhoneNumberIdentifier(c2Target), "dtmf-reco-on-c2"); 

When your application no longer wants to receive DTMF tones from the participant, use the StopContinuousDtmfRecognitionAsync method to let Azure Communication Services know to stop detecting DTMF tones.

StopContinuousDtmfRecognitionAsync

Stop detecting DTMF tones sent by a participant.

var continuousDtmfRecognitionOptions = new ContinuousDtmfRecognitionOptions(new PhoneNumberIdentifier(callerPhonenumber)) 
{ 
    OperationContext = "dtmf-reco-on-c2" 
}; 

var startContinuousDtmfRecognitionAsyncResult = await callAutomationClient.GetCallConnection(callConnectionId) 
    .GetCallMedia() 
    .StartContinuousDtmfRecognitionAsync(continuousDtmfRecognitionOptions); 

Your application receives event updates when these actions either succeed or fail. You can use these events to build custom business logic to configure the next step that your application needs to take when it receives these event updates.

ContinuousDtmfRecognitionToneReceived Event

An example of how you can handle a DTMF tone that was successfully detected.

if (acsEvent is ContinuousDtmfRecognitionToneReceived continuousDtmfRecognitionToneReceived) 
{ 
	logger.LogInformation("Tone detected: sequenceId={sequenceId}, tone={tone}", 
	continuousDtmfRecognitionToneReceived.SequenceId, 
        continuousDtmfRecognitionToneReceived.Tone); 
} 

Azure Communication Services provides you with SequenceId as part of the ContinuousDtmfRecognitionToneReceived event. Your application can use it to reconstruct the order in which the participant entered the DTMF tones.

ContinuousDtmfRecognitionFailed Event

An example of what to do when DTMF tone detection fails.

if (acsEvent is ContinuousDtmfRecognitionToneFailed continuousDtmfRecognitionToneFailed) 
{ 
    logger.LogInformation("Start continuous DTMF recognition failed, result={result}, context={context}", 
        continuousDtmfRecognitionToneFailed.ResultInformation?.Message, 
        continuousDtmfRecognitionToneFailed.OperationContext); 
} 

ContinuousDtmfRecognitionStopped Event

An example of what to do when continuous DTMF recognition stops. Maybe your application invoked the StopContinuousDtmfRecognitionAsync event or the call ended.

if (acsEvent is ContinuousDtmfRecognitionStopped continuousDtmfRecognitionStopped) 
{ 
    logger.LogInformation("Continuous DTMF recognition stopped, context={context}", continuousDtmfRecognitionStopped.OperationContext); 
} 

Hold

The hold action allows developers to temporarily pause a conversation between a participant and a system or agent. This capability is useful in scenarios where the participant needs to be transferred to another agent or department or when the agent needs to consult a supervisor before continuing the conversation. During this time, you can choose to play audio to the participant who is on hold.

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

Unhold

The unhold action allows developers to resume a conversation between a participant and a system or agent that was previously paused. When the participant is taken off hold, they can hear the system or agent again.

var unHoldOptions = new UnholdOptions(target) 
{ 
    OperationContext = "UnHoldPstnParticipant" 
}; 

// Option 1
var UnHoldParticipant = await callMedia.UnholdAsync(unHoldOptions);

/* 
// Option 2
var UnHoldParticipant = await callMedia.UnholdAsync(target);
*/

Audio streaming (public preview)

With audio streaming, you can subscribe to real-time audio streams from an ongoing call. For more information on how to get started with audio streaming and information about audio-streaming callback events, see Quickstart: Server-side audio streaming.

Real-time transcription (public preview)

By using real-time transcription, you can access live transcriptions for the audio of an ongoing call. For more information on how to get started with real-time transcription and information about real-time transcription callback events, see Add real-time transcription into your application.

Media action compatibility table

The following table illustrates what media operations are allowed to run or queue if a previous operation is still running or queued.

Existing operation Call leg Allowed Disallowed
PlayToAll Main PlayToAll, Recognize(Non-Group Call), PlayTo, Recognize(Group Call), SendDTMF, StartContinuousDtmfRecognition None
Recognize(Non-Group Call) Main PlayToAll, Recognize(Non-Group Call), PlayTo, Recognize(Group Call), SendDTMF, StartContinuousDtmfRecognition None
PlayTo Sub PlayToAll, Recognize(Non-Group Call) PlayTo, Recognize(Group Call), SendDTMF, StartContinuousDtmfRecognition
Recognize(Group Call) Sub PlayToAll, Recognize(Non-Group Call) PlayTo, Recognize(Group Call), SendDTMF, StartContinuousDtmfRecognition
SendDTMF Sub PlayToAll, Recognize(Non-Group Call) PlayTo, Recognize(Group Call), SendDTMF, StartContinuousDtmfRecognition
StartContinuousDtmfRecognition Sub PlayToAll, Recognize(Non-Group Call),PlayTo, Recognize(Group Call), SendDTMF, StartContinuousDtmfRecognition None