All skills
microsoft avatar

/azure-communication-callautomation-java

@e7ee58f
by microsoftmicrosoft/skills3.1k stars
351

Build call automation workflows with Azure Communication Services Call Automation Java SDK. Use when implementing IVR systems, call routing, call recording, DTMF recognition, text-to-speech, or AI-powered call flows.

Use this Skill: https://skilld.dev/gh/microsoft/skills/azure-communication-callautomation-java

This session only. Nothing lands on disk.

referencesexamples.md

≈4.1k tokens on demand. Your agent reads this file only when SKILL.md points to it.

Azure Communication Call Automation SDK for Java - Examples

Comprehensive code examples for the Azure Communication Call Automation SDK for Java.

Table of Contents

Maven Dependency

<dependency>
    <groupId>com.azure</groupId>
    <artifactId>azure-communication-callautomation</artifactId>
    <version>1.5.2</version>
</dependency>

Client Creation

Sync Client

import com.azure.communication.callautomation.CallAutomationClient;
import com.azure.communication.callautomation.CallAutomationClientBuilder;

CallAutomationClient callAutomationClient = new CallAutomationClientBuilder()
    .connectionString("<Azure Communication Services connection string>")
    .buildClient();

Async Client

import com.azure.communication.callautomation.CallAutomationAsyncClient;

CallAutomationAsyncClient asyncClient = new CallAutomationClientBuilder()
    .connectionString("<acsConnectionString>")
    .buildAsyncClient();

Creating Outbound Calls

Single PSTN Call

import com.azure.communication.callautomation.models.*;
import com.azure.communication.common.PhoneNumberIdentifier;
import com.azure.core.util.Context;

String callbackUri = "https://<myendpoint>/Events";
PhoneNumberIdentifier callerIdNumber = new PhoneNumberIdentifier("+18001234567");
PhoneNumberIdentifier target = new PhoneNumberIdentifier("+16471234567");

CallInvite callInvite = new CallInvite(target, callerIdNumber);
CreateCallOptions createCallOptions = new CreateCallOptions(callInvite, callbackUri);

// Optional: Add AI capabilities
CallIntelligenceOptions callIntelligenceOptions = new CallIntelligenceOptions()
    .setCognitiveServicesEndpoint("https://your-cognitive-services.cognitiveservices.azure.com/");
createCallOptions.setCallIntelligenceOptions(callIntelligenceOptions);

Response<CreateCallResult> result = callAutomationClient.createCallWithResponse(
    createCallOptions, 
    Context.NONE
);
String callConnectionId = result.getValue().getCallConnectionProperties().getCallConnectionId();

Group Call

import com.azure.communication.common.CommunicationUserIdentifier;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

List<CommunicationIdentifier> targets = new ArrayList<>(Arrays.asList(
    new PhoneNumberIdentifier("+16471234567"),
    new CommunicationUserIdentifier("<user_id>")
));

CreateGroupCallOptions groupCallOptions = new CreateGroupCallOptions(targets, callbackUri);
groupCallOptions.setSourceCallIdNumber(callerIdNumber);

Response<CreateCallResult> response = callAutomationClient.createGroupCallWithResponse(
    groupCallOptions, 
    Context.NONE
);

Answering Inbound Calls

Basic Answer

import com.azure.communication.callautomation.models.*;

String incomingCallContext = "<IncomingCallContext_From_IncomingCall_Event>";
String callbackUri = "https://<myendpoint>/Events";

AnswerCallOptions answerCallOptions = new AnswerCallOptions(incomingCallContext, callbackUri);
Response<AnswerCallResult> response = callAutomationClient.answerCallWithResponse(
    answerCallOptions, 
    Context.NONE
);

Answer with AI Capabilities

CallIntelligenceOptions callIntelligenceOptions = new CallIntelligenceOptions()
    .setCognitiveServicesEndpoint("https://cognitive-services.cognitiveservices.azure.com/");

AnswerCallOptions answerCallOptions = new AnswerCallOptions(incomingCallContext, callbackUri)
    .setCallIntelligenceOptions(callIntelligenceOptions);

Response<AnswerCallResult> response = callAutomationClient.answerCallWithResponse(
    answerCallOptions, 
    Context.NONE
);

Answer with Transcription

TranscriptionOptions transcriptionOptions = new TranscriptionOptions(
    "wss://your-websocket-url",
    TranscriptionTransport.WEBSOCKET,
    "en-US",
    false,
    "your-endpoint-id"
);

AnswerCallOptions answerCallOptions = new AnswerCallOptions(incomingCallContext, callbackUri)
    .setCallIntelligenceOptions(callIntelligenceOptions)
    .setTranscriptionOptions(transcriptionOptions);

Playing Audio/TTS

Play Text-to-Speech to All

import com.azure.communication.callautomation.CallConnection;

String textToPlay = "Welcome to Contoso. How can I help you today?";

TextSource textSource = new TextSource()
    .setText(textToPlay)
    .setVoiceName("en-US-NancyNeural");

CallConnection callConnection = callAutomationClient.getCallConnection(callConnectionId);
callConnection.getCallMedia().playToAll(textSource);

Play Audio File to Participant

import java.util.Arrays;

CommunicationIdentifier targetParticipant = new PhoneNumberIdentifier("+16471234567");

FileSource playSource = new FileSource()
    .setUrl("https://storage.blob.core.windows.net/audio/welcome.wav")
    .setPlaySourceCacheId("<playSourceId>");  // Optional: cache for repeated playback

var playTo = Arrays.asList(targetParticipant);
PlayOptions playOptions = new PlayOptions(playSource, playTo);

callAutomationClient.getCallConnection(callConnectionId)
    .getCallMedia()
    .playWithResponse(playOptions, Context.NONE);

Play with SSML

String ssmlText = "<speak version=\"1.0\" xmlns=\"http://www.w3.org/2001/10/synthesis\" xml:lang=\"en-US\">" +
    "<voice name=\"en-US-JennyNeural\">Hello, welcome to our service!</voice></speak>";

SsmlSource ssmlSource = new SsmlSource()
    .setSsmlText(ssmlText);

callConnection.getCallMedia().playToAll(ssmlSource);

Recognizing DTMF Tones

DTMF Recognition

import java.time.Duration;
import java.util.Arrays;

CommunicationIdentifier targetParticipant = new PhoneNumberIdentifier("+16471234567");
int maxTonesToCollect = 3;

TextSource playSource = new TextSource()
    .setText("Please enter 3 digits.")
    .setVoiceName("en-US-ElizabethNeural");

CallMediaRecognizeDtmfOptions recognizeOptions = new CallMediaRecognizeDtmfOptions(
    targetParticipant, 
    maxTonesToCollect
)
    .setInitialSilenceTimeout(Duration.ofSeconds(30))
    .setPlayPrompt(playSource)
    .setInterToneTimeout(Duration.ofSeconds(5))
    .setInterruptPrompt(true)
    .setStopTones(Arrays.asList(DtmfTone.POUND));

callAutomationClient.getCallConnection(callConnectionId)
    .getCallMedia()
    .startRecognizingWithResponse(recognizeOptions, Context.NONE);

Speech or DTMF Recognition

CallMediaRecognizeSpeechOrDtmfOptions recognizeOptions = 
    new CallMediaRecognizeSpeechOrDtmfOptions(
        targetParticipant, 
        maxTonesToCollect, 
        Duration.ofMillis(1000)
    )
    .setPlayPrompt(playSource)
    .setInitialSilenceTimeout(Duration.ofSeconds(30))
    .setInterruptPrompt(true)
    .setOperationContext("OpenQuestionSpeechOrDtmf");

callAutomationClient.getCallConnection(callConnectionId)
    .getCallMedia()
    .startRecognizingWithResponse(recognizeOptions, Context.NONE);

Choice Recognition

import java.util.List;

List<RecognitionChoice> choices = Arrays.asList(
    new RecognitionChoice()
        .setLabel("Confirm")
        .setPhrases(Arrays.asList("Confirm", "Yes", "One"))
        .setTone(DtmfTone.ONE),
    new RecognitionChoice()
        .setLabel("Cancel")
        .setPhrases(Arrays.asList("Cancel", "No", "Two"))
        .setTone(DtmfTone.TWO)
);

TextSource playSource = new TextSource()
    .setText("Say Confirm or press 1 to confirm, or say Cancel or press 2 to cancel.")
    .setVoiceName("en-US-ElizabethNeural");

CallMediaRecognizeChoiceOptions recognizeOptions = new CallMediaRecognizeChoiceOptions(
    targetParticipant, 
    choices
)
    .setInterruptPrompt(true)
    .setInitialSilenceTimeout(Duration.ofSeconds(30))
    .setPlayPrompt(playSource)
    .setOperationContext("AppointmentReminderMenu");

callAutomationClient.getCallConnection(callConnectionId)
    .getCallMedia()
    .startRecognizingWithResponse(recognizeOptions, Context.NONE);

Send DTMF Tones

List<DtmfTone> tones = Arrays.asList(
    DtmfTone.ONE, 
    DtmfTone.TWO, 
    DtmfTone.THREE, 
    DtmfTone.POUND
);

SendDtmfTonesOptions options = new SendDtmfTonesOptions(
    tones, 
    new PhoneNumberIdentifier(targetPhoneNumber)
);
options.setOperationContext("dtmfs-to-ivr");

callAutomationClient.getCallConnection(callConnectionId)
    .getCallMedia()
    .sendDtmfTonesWithResponse(options, Context.NONE);

Recording Calls

Start Recording

import com.azure.communication.callautomation.CallRecording;

CallRecording callRecording = callAutomationClient.getCallRecording();

StartRecordingOptions startRecordingOptions = new StartRecordingOptions(
    new ServerCallLocator(serverCallId)
)
    .setRecordingContent(RecordingContent.AUDIO_VIDEO)
    .setRecordingChannel(RecordingChannel.MIXED)
    .setRecordingFormat(RecordingFormat.MP4);

Response<RecordingStateResult> response = callRecording.startWithResponse(
    startRecordingOptions, 
    Context.NONE
);

String recordingId = response.getValue().getRecordingId();

Pause/Resume Recording

// Pause
callRecording.pause(recordingId);

// Resume
callRecording.resume(recordingId);

Stop Recording

callRecording.stop(recordingId);

Download Recording

callRecording.downloadToWithResponse(
    recordingUrl,
    Paths.get("recording.mp4"),
    null,  // HttpRange (optional)
    Context.NONE
);

Transfer Calls

Blind Transfer

CommunicationIdentifier transferDestination = new PhoneNumberIdentifier("+16471234567");

TransferCallToParticipantOptions transferOptions = new TransferCallToParticipantOptions(
    transferDestination
);

Response<TransferCallResult> response = callAutomationClient
    .getCallConnection(callConnectionId)
    .transferCallToParticipantWithResponse(transferOptions, Context.NONE);

Transfer with Announcement

TextSource transferee Prompt = new TextSource()
    .setText("Please hold while we transfer your call.")
    .setVoiceName("en-US-NancyNeural");

TransferCallToParticipantOptions transferOptions = new TransferCallToParticipantOptions(
    transferDestination
)
    .setSourceCallerIdNumber(new PhoneNumberIdentifier("+18001234567"))
    .setTransfereeGreeting(transfereePrompt);

callAutomationClient.getCallConnection(callConnectionId)
    .transferCallToParticipantWithResponse(transferOptions, Context.NONE);

Add/Remove Participants

Add Participant

CommunicationIdentifier participant = new PhoneNumberIdentifier("+16471234567");
PhoneNumberIdentifier callerId = new PhoneNumberIdentifier("+18001234567");

AddParticipantOptions addOptions = new AddParticipantOptions(
    new CallInvite(participant, callerId)
);

Response<AddParticipantResult> response = callAutomationClient
    .getCallConnection(callConnectionId)
    .addParticipantWithResponse(addOptions, Context.NONE);

Remove Participant

CommunicationIdentifier participant = new PhoneNumberIdentifier("+16471234567");

callAutomationClient.getCallConnection(callConnectionId)
    .removeParticipant(participant);

List Participants

ListParticipantsResult participants = callAutomationClient
    .getCallConnection(callConnectionId)
    .listParticipants();

participants.getValues().forEach(p -> 
    System.out.println("Participant: " + p.getIdentifier().getRawId()));

Handling Call Events

Event Grid Webhook Handler (Spring Boot)

import com.azure.communication.callautomation.CallAutomationEventParser;
import com.azure.communication.callautomation.models.events.*;
import org.springframework.web.bind.annotation.*;

@RestController
public class CallbackController {

    @PostMapping("/Events")
    public ResponseEntity<String> handleCallEvents(@RequestBody String requestBody) {
        List<CallAutomationEventBase> events = CallAutomationEventParser.parseEvents(requestBody);
        
        for (CallAutomationEventBase event : events) {
            String callConnectionId = event.getCallConnectionId();
            
            if (event instanceof CallConnected) {
                handleCallConnected((CallConnected) event);
            } else if (event instanceof RecognizeCompleted) {
                handleRecognizeCompleted((RecognizeCompleted) event);
            } else if (event instanceof RecognizeFailed) {
                handleRecognizeFailed((RecognizeFailed) event);
            } else if (event instanceof PlayCompleted) {
                handlePlayCompleted((PlayCompleted) event);
            } else if (event instanceof CallDisconnected) {
                handleCallDisconnected((CallDisconnected) event);
            }
        }
        
        return ResponseEntity.ok("");
    }
    
    private void handleCallConnected(CallConnected event) {
        System.out.println("Call connected: " + event.getCallConnectionId());
    }
    
    private void handleRecognizeCompleted(RecognizeCompleted event) {
        CollectTonesResult result = (CollectTonesResult) event.getRecognizeResult();
        String tones = result.getTones().stream()
            .map(DtmfTone::toString)
            .collect(Collectors.joining());
        System.out.println("DTMF tones received: " + tones);
    }
    
    private void handleRecognizeFailed(RecognizeFailed event) {
        System.out.println("Recognition failed: " + event.getResultInformation().getMessage());
    }
    
    private void handlePlayCompleted(PlayCompleted event) {
        System.out.println("Play completed: " + event.getOperationContext());
    }
    
    private void handleCallDisconnected(CallDisconnected event) {
        System.out.println("Call disconnected: " + event.getCallConnectionId());
    }
}

Async Client Patterns

Create Call Async

asyncClient.createCall(callInvite, callbackUri)
    .subscribe(
        result -> System.out.println("Call ID: " + 
            result.getCallConnectionProperties().getCallConnectionId()),
        error -> System.err.println("Error: " + error.getMessage())
    );

Play Audio Async

asyncClient.getCallConnectionAsync(callConnectionId)
    .getCallMediaAsync()
    .playToAll(textSource)
    .subscribe(
        unused -> System.out.println("Play started"),
        error -> System.err.println("Error: " + error.getMessage())
    );

Recognize Async

asyncClient.getCallConnectionAsync(callConnectionId)
    .getCallMediaAsync()
    .startRecognizingWithResponse(recognizeOptions)
    .subscribe(
        response -> System.out.println("Recognition started"),
        error -> System.err.println("Error: " + error.getMessage())
    );

Error Handling

Sync Error Handling

import com.azure.core.exception.HttpResponseException;

try {
    Response<CreateCallResult> result = callAutomationClient.createCallWithResponse(
        createCallOptions, 
        Context.NONE
    );
} catch (HttpResponseException e) {
    System.err.println("HTTP Status: " + e.getResponse().getStatusCode());
    System.err.println("Error: " + e.getMessage());
} catch (Exception e) {
    System.err.println("Unexpected error: " + e.getMessage());
}

Async Error Handling

asyncClient.createCall(callInvite, callbackUri)
    .subscribe(
        result -> System.out.println("Success"),
        error -> {
            if (error instanceof HttpResponseException) {
                HttpResponseException httpError = (HttpResponseException) error;
                System.err.println("HTTP error: " + httpError.getResponse().getStatusCode());
            } else {
                System.err.println("Error: " + error.getMessage());
            }
        }
    );

Common Error Codes

Code Meaning
400 Invalid request
401 Authentication failed
403 Not authorized
404 Call/resource not found
429 Rate limited
500 Server error

Source: SKILL.md on GitHub

1 warning15d4 checks · Risk SAFE
  • Gen Agent Trust Hub15d

    This skill provides documentation for building call automation workflows with Azure Communication Services. It includes some security considerations related to processing external call data, which is typical for communication-based tools. These patterns are used within the skill's intended functionality.

  • Socket15d

    No alerts

  • Snyk15d

    Risk: LOW · No issues

  • Runlayer7mo

    3/3 files flagged

Signed by skilld at e7ee58f. This ties the file your Agent reads to that commit on GitHub. It does not review the instructions.

Last checked against GitHub yesterday.

Activeupdated 5 months ago
Other metadata
metadata
{
  "author": "Microsoft",
  "version": "1.0.0",
  "package": "com.azure:azure-communication-callautomation"
}

README badge

README badge for microsoft/skills/azure-communication-callautomation-java