Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -55,8 +55,10 @@
import reactor.core.publisher.Mono;

import java.net.URISyntaxException;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

import static com.azure.core.util.FluxUtil.monoError;
Expand Down Expand Up @@ -395,6 +397,13 @@ Mono<Response<AnswerCallResult>> answerCallWithResponseInternal(AnswerCallOption
= getTranscriptionConfigurationInternal(answerCallOptions.getTranscriptionConfiguration());
request.setTranscriptionConfiguration(transcriptionConfigurationInternal);
}
if (answerCallOptions.getCustomCallingContext().getSipHeaders() != null
|| answerCallOptions.getCustomCallingContext().getVoipHeaders() != null) {
CustomCallingContext customContext = new CustomCallingContext();
customContext.setSipHeaders(answerCallOptions.getCustomCallingContext().getSipHeaders());
customContext.setVoipHeaders(answerCallOptions.getCustomCallingContext().getVoipHeaders());
request.setCustomCallingContext(customContext);
}

return azureCommunicationCallAutomationServiceInternal.answerCallWithResponseAsync(request, context)
.map(response -> {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@

package com.azure.communication.callautomation.models;

import java.util.HashMap;

import com.azure.core.annotation.Fluent;

/**
Expand Down Expand Up @@ -40,6 +42,11 @@ public final class AnswerCallOptions {
*/
private String operationContext;

/*
* Used by customer to send custom calling context to targets when answering On-Behalf-Of call
*/
private CustomCallingContext customCallingContext;

/**
* Constructor
*
Expand All @@ -49,6 +56,7 @@ public final class AnswerCallOptions {
public AnswerCallOptions(String incomingCallContext, String callbackUrl) {
this.incomingCallContext = incomingCallContext;
this.callbackUrl = callbackUrl;
this.customCallingContext = new CustomCallingContext(new HashMap<String, String>(), new HashMap<String, String>());
}

/**
Expand Down Expand Up @@ -148,4 +156,13 @@ public AnswerCallOptions setMediaStreamingConfiguration(MediaStreamingOptions me
this.mediaStreamingOptions = mediaStreamingOptions;
return this;
}

/**
* Get the Custom Calling Context.
*
* @return the customCallingContext.
*/
public CustomCallingContext getCustomCallingContext() {
return customCallingContext;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

package com.azure.communication.callautomation;

import com.azure.communication.callautomation.implementation.models.CustomCallingContext;
import com.azure.communication.callautomation.models.AnswerCallOptions;
import com.azure.communication.callautomation.models.AnswerCallResult;
import com.azure.communication.callautomation.models.CreateCallResult;
Expand Down Expand Up @@ -211,4 +212,121 @@ public void createVOIPCallAndRejectAutomatedTest(HttpClient httpClient) {
fail("Unexpected exception received", ex);
}
}

@DoNotRecord(skipInPlayback = true)
@ParameterizedTest
@MethodSource("com.azure.core.test.TestBase#getHttpClients")
@DisabledIfEnvironmentVariable(
named = "SKIP_LIVE_TEST",
matches = "(?i)(true)",
disabledReason = "Requires environment to be set up")
public void createVOIPCallAndAnswerWithCustomContextThenHangupAutomatedTest(HttpClient httpClient) {
/* Test case: ACS to ACS call
* 1. create a CallAutomationClient.
* 2. create a call from source to one ACS target.
* 3. get updated call properties and check for the connected state.
* 4. hang up the call.
* 5. once call is hung up, verify disconnected event
*/

CommunicationIdentityAsyncClient identityAsyncClient
= getCommunicationIdentityClientUsingConnectionString(httpClient)
.addPolicy((context, next) -> logHeaders("createVOIPCallAndAnswerWithCustomContextThenHangupAutomatedTest", next))
.buildAsyncClient();

List<CallConnectionAsync> callDestructors = new ArrayList<>();

try {
// create caller and receiver
CommunicationUserIdentifier caller = identityAsyncClient.createUser().block();
CommunicationIdentifier target = identityAsyncClient.createUser().block();

// Create call automation client and use source as the caller.
CallAutomationAsyncClient callerAsyncClient = getCallAutomationClientUsingConnectionString(httpClient)
.addPolicy((context, next) -> logHeaders("createVOIPCallAndAnswerWithCustomContextThenHangupAutomatedTest", next))
.sourceIdentity(caller)
.buildAsyncClient();
// Create call automation client for receivers.
CallAutomationAsyncClient receiverAsyncClient = getCallAutomationClientUsingConnectionString(httpClient)
.addPolicy((context, next) -> logHeaders("createVOIPCallAndAnswerWithCustomContextThenHangupAutomatedTest", next))
.buildAsyncClient();

String uniqueId = serviceBusWithNewCall(caller, target);

// create a call
List<CommunicationIdentifier> targets = new ArrayList<>(Collections.singletonList(target));
CreateGroupCallOptions createCallOptions
= new CreateGroupCallOptions(targets, DISPATCHER_CALLBACK + String.format("?q=%s", uniqueId));
Response<CreateCallResult> createCallResultResponse
= callerAsyncClient.createGroupCallWithResponse(createCallOptions).block();

assertNotNull(createCallResultResponse);
CreateCallResult createCallResult = createCallResultResponse.getValue();
assertNotNull(createCallResult);
assertNotNull(createCallResult.getCallConnectionProperties());
String callerConnectionId = createCallResult.getCallConnectionProperties().getCallConnectionId();
assertNotNull(callerConnectionId);

// wait for the incomingCallContext
String incomingCallContext = waitForIncomingCallContext(uniqueId, Duration.ofSeconds(10));
assertNotNull(incomingCallContext);

// answer the call
AnswerCallOptions answerCallOptions
= new AnswerCallOptions(incomingCallContext, DISPATCHER_CALLBACK + String.format("?q=%s", uniqueId));
if (answerCallOptions.getCustomCallingContext().getSipHeaders() != null
|| answerCallOptions.getCustomCallingContext().getVoipHeaders() != null) {
CustomCallingContext customContext = new CustomCallingContext();
customContext.setSipHeaders(answerCallOptions.getCustomCallingContext().getSipHeaders());
customContext.setVoipHeaders(answerCallOptions.getCustomCallingContext().getVoipHeaders());
}
AnswerCallResult answerCallResult
= Objects.requireNonNull(receiverAsyncClient.answerCallWithResponse(answerCallOptions).block())
.getValue();
assertNotNull(answerCallResult);
assertNotNull(answerCallResult.getCallConnectionAsync());
assertNotNull(answerCallResult.getCallConnectionProperties());
String receiverConnectionId = answerCallResult.getCallConnectionProperties().getCallConnectionId();
callDestructors.add(answerCallResult.getCallConnectionAsync());

// check events to caller side
CallConnected callerCallConnected
= waitForEvent(CallConnected.class, callerConnectionId, Duration.ofSeconds(10));
ParticipantsUpdated callerParticipantUpdatedEvent
= waitForEvent(ParticipantsUpdated.class, callerConnectionId, Duration.ofSeconds(10));
assertNotNull(callerCallConnected);
assertNotNull(callerParticipantUpdatedEvent);

// check events to receiver side
CallConnected receiverCallConnected
= waitForEvent(CallConnected.class, receiverConnectionId, Duration.ofSeconds(10));
ParticipantsUpdated receiverParticipantUpdatedEvent
= waitForEvent(ParticipantsUpdated.class, callerConnectionId, Duration.ofSeconds(10));
assertNotNull(receiverCallConnected);
assertNotNull(receiverParticipantUpdatedEvent);

// hang up the call.
answerCallResult.getCallConnectionAsync().hangUp(true).block();

// check if both parties had the call terminated.
CallDisconnected callerCallDisconnected
= waitForEvent(CallDisconnected.class, receiverConnectionId, Duration.ofSeconds(10));
CallDisconnected receiverCallDisconnected
= waitForEvent(CallDisconnected.class, callerConnectionId, Duration.ofSeconds(10));
assertNotNull(callerCallDisconnected);
assertNotNull(receiverCallDisconnected);

} catch (Exception ex) {
fail("Unexpected exception received", ex);
} finally {
if (!callDestructors.isEmpty()) {
try {
callDestructors.forEach(callConnection -> callConnection.hangUpWithResponse(true).block());
} catch (Exception ignored) {
// Some call might have been terminated during the test, and it will cause exceptions here.
// Do nothing and iterate to next call connection.
}
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,29 @@ public void answerCall() {
assertNotNull(answerCallResult);
}

@Test
public void answerCallWithResponseAndCustomContext() {
CallAutomationAsyncClient callAutomationAsyncClient = getCallAutomationAsyncClient(new ArrayList<>(
Collections.singletonList(new AbstractMap.SimpleEntry<>(generateCallProperties(CALL_CONNECTION_ID,
CALL_SERVER_CALL_ID, CALL_CALLER_ID, CALL_CALLER_DISPLAY_NAME, CALL_TARGET_ID, CALL_CONNECTION_STATE,
CALL_SUBJECT, CALL_CALLBACK_URL, MEDIA_SUBSCRIPTION_ID, DATA_SUBSCRIPTION_ID), 200))));

AnswerCallOptions answerCallOptions = new AnswerCallOptions(CALL_INCOMING_CALL_CONTEXT, CALL_CALLBACK_URL)
.setMediaStreamingConfiguration(MEDIA_STREAMING_CONFIGURATION)
.setTranscriptionConfiguration(TRANSCRIPTION_CONFIGURATION);

Response<AnswerCallResult> answerCallResult
= callAutomationAsyncClient.answerCallWithResponse(answerCallOptions).block();

assertNotNull(answerCallResult);
assertEquals(200, answerCallResult.getStatusCode());
assertNotNull(answerCallResult.getValue());
assertEquals(MEDIA_SUBSCRIPTION_ID,
answerCallResult.getValue().getCallConnectionProperties().getMediaSubscriptionId());
assertEquals(DATA_SUBSCRIPTION_ID,
answerCallResult.getValue().getCallConnectionProperties().getDataSubscriptionId());
}

@Test
public void answerCallWithResponse() {
CallAutomationAsyncClient callAutomationAsyncClient = getCallAutomationAsyncClient(new ArrayList<>(
Expand Down
Loading