Skip to content

Commit 0538ea3

Browse files
v-pivamshiVinothini Dharmaraj
andauthored
Added interrupt hold audio flag for play media. (Azure#43721)
* Added interrupt hold audio flag for play media. * live test issue resolved. * fixing the unit tests and updating the changes * resolved conflicts and recorded live tests. --------- Co-authored-by: Vinothini Dharmaraj <[email protected]>
1 parent 4ddbed8 commit 0538ea3

25 files changed

+199
-32
lines changed

sdk/communication/azure-communication-callautomation/assets.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,5 +2,5 @@
22
"AssetsRepo": "Azure/azure-sdk-assets",
33
"AssetsRepoPrefixPath": "java",
44
"TagPrefix": "java/communication/azure-communication-callautomation",
5-
"Tag": "java/communication/azure-communication-callautomation_0356c7a692"
5+
"Tag": "java/communication/azure-communication-callautomation_9339e7fc0c"
66
}

sdk/communication/azure-communication-callautomation/src/main/java/com/azure/communication/callautomation/CallMediaAsync.java

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,11 @@
33

44
package com.azure.communication.callautomation;
55

6+
import java.time.Duration;
7+
import java.util.ArrayList;
8+
import java.util.List;
9+
import java.util.stream.Collectors;
10+
611
import com.azure.communication.callautomation.implementation.CallMediasImpl;
712
import com.azure.communication.callautomation.implementation.accesshelpers.SendDtmfTonesResponseConstructorProxy;
813
import com.azure.communication.callautomation.implementation.converters.CommunicationIdentifierConverter;
@@ -62,16 +67,11 @@
6267
import com.azure.core.http.rest.SimpleResponse;
6368
import com.azure.core.util.Context;
6469
import com.azure.core.util.FluxUtil;
65-
import com.azure.core.util.logging.ClientLogger;
66-
import reactor.core.publisher.Mono;
67-
68-
import java.time.Duration;
69-
import java.util.ArrayList;
70-
import java.util.List;
71-
import java.util.stream.Collectors;
72-
7370
import static com.azure.core.util.FluxUtil.monoError;
7471
import static com.azure.core.util.FluxUtil.withContext;
72+
import com.azure.core.util.logging.ClientLogger;
73+
74+
import reactor.core.publisher.Mono;
7575

7676
/**
7777
* CallContent.
@@ -303,6 +303,7 @@ PlayRequest getPlayRequest(PlayOptions options) {
303303
request.setPlayOptions(new PlayOptionsInternal().setLoop(options.isLoop()));
304304
request.setOperationContext(options.getOperationContext());
305305
request.setOperationCallbackUri(options.getOperationCallbackUrl());
306+
request.setPlayOptions(new PlayOptionsInternal().setInterruptHoldAudio(options.isInterruptHoldAudio()));
306307

307308
return request;
308309
}

sdk/communication/azure-communication-callautomation/src/main/java/com/azure/communication/callautomation/models/PlayOptions.java

Lines changed: 28 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,12 @@
33

44
package com.azure.communication.callautomation.models;
55

6-
import com.azure.communication.common.CommunicationIdentifier;
7-
import com.azure.core.annotation.Fluent;
8-
96
import java.util.ArrayList;
107
import java.util.List;
118

9+
import com.azure.communication.common.CommunicationIdentifier;
10+
import com.azure.core.annotation.Fluent;
11+
1212
/** The PlayOptions model. */
1313
@Fluent
1414
public final class PlayOptions {
@@ -39,6 +39,11 @@ public final class PlayOptions {
3939
*/
4040
private String operationCallbackUrl;
4141

42+
/*
43+
* If set, hold audio will be interrupted, then this request will be played, and then the hold audio will be resumed.
44+
*/
45+
private Boolean interruptHoldAudio;
46+
4247
/**
4348
* Constructor
4449
* @param playSources A List of {@link PlaySource} representing the sources to play.
@@ -138,4 +143,24 @@ public PlayOptions setOperationCallbackUrl(String operationCallbackUrl) {
138143
this.operationCallbackUrl = operationCallbackUrl;
139144
return this;
140145
}
146+
147+
/**
148+
* Get the interruptHoldAudio property.
149+
*
150+
* @return the interruptHoldAudio value.
151+
*/
152+
public Boolean isInterruptHoldAudio() {
153+
return this.interruptHoldAudio;
154+
}
155+
156+
/**
157+
* Set the interruptHoldAudio property
158+
*
159+
* @param interruptHoldAudio the interruptHoldAudio value to set.
160+
* @return the PlayOptions object itself.
161+
*/
162+
public PlayOptions setInterruptHoldAudio(Boolean interruptHoldAudio) {
163+
this.interruptHoldAudio = interruptHoldAudio;
164+
return this;
165+
}
141166
}

sdk/communication/azure-communication-callautomation/src/test/java/com/azure/communication/callautomation/CallMediaAsyncAutomatedLiveTests.java

Lines changed: 140 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
import com.azure.communication.callautomation.models.events.CallConnected;
1515
import com.azure.communication.callautomation.models.events.ContinuousDtmfRecognitionStopped;
1616
import com.azure.communication.callautomation.models.events.PlayCompleted;
17+
import com.azure.communication.callautomation.models.events.PlayStarted;
1718
import com.azure.communication.callautomation.models.events.SendDtmfTonesCompleted;
1819
import com.azure.communication.common.CommunicationIdentifier;
1920
import com.azure.communication.common.CommunicationUserIdentifier;
@@ -27,6 +28,7 @@
2728
import com.azure.communication.callautomation.models.MediaStreamingContent;
2829
import com.azure.communication.callautomation.models.MediaStreamingOptions;
2930
import com.azure.communication.callautomation.models.MediaStreamingTransport;
31+
import com.azure.communication.callautomation.models.PlayOptions;
3032
import com.azure.communication.callautomation.models.TranscriptionOptions;
3133
import com.azure.communication.callautomation.models.StartMediaStreamingOptions;
3234
import com.azure.communication.callautomation.models.StopMediaStreamingOptions;
@@ -61,6 +63,11 @@
6163
import static org.junit.jupiter.api.Assertions.assertTrue;
6264
import static org.junit.jupiter.api.Assertions.fail;
6365

66+
import com.azure.communication.callautomation.models.events.HoldAudioResumed;
67+
import com.azure.communication.callautomation.models.events.HoldAudioCompleted;
68+
import com.azure.communication.callautomation.models.events.HoldAudioPaused;
69+
import com.azure.communication.callautomation.models.events.HoldAudioStarted;
70+
6471
public class CallMediaAsyncAutomatedLiveTests extends CallAutomationAutomatedLiveTestBase {
6572

6673
@ParameterizedTest
@@ -1316,4 +1323,137 @@ public void interruptAudioAndAnnounceToholdParticipantInACallTest(HttpClient htt
13161323
}
13171324
}
13181325
}
1326+
1327+
@ParameterizedTest
1328+
@MethodSource("com.azure.core.test.TestBase#getHttpClients")
1329+
@DisabledIfEnvironmentVariable(
1330+
named = "SKIP_LIVE_TEST",
1331+
matches = "(?i)(true)",
1332+
disabledReason = "Requires environment to be set up")
1333+
public void playMultipleFileSourcesWhenParticipantOnHoldTest(HttpClient httpClient) {
1334+
/* Test case: ACS to ACS call
1335+
* 1. create a CallAutomationClient.
1336+
* 2. create a call from source to one ACS target.
1337+
* 3. get updated call properties and check for the connected state.
1338+
* 4. hold the participant
1339+
* 5. play a media to target participant with mutiple file prompts
1340+
* 6. unhold the participant
1341+
* 7. hang up the call.
1342+
*/
1343+
1344+
CommunicationIdentityAsyncClient identityAsyncClient
1345+
= getCommunicationIdentityClientUsingConnectionString(httpClient)
1346+
.addPolicy((context, next) -> logHeaders("playMultipleFileSourcesWhenParticipantOnHoldTest", next))
1347+
.buildAsyncClient();
1348+
1349+
List<CallConnectionAsync> callDestructors = new ArrayList<>();
1350+
1351+
try {
1352+
// create caller and receiver
1353+
CommunicationUserIdentifier caller = identityAsyncClient.createUser().block();
1354+
CommunicationIdentifier receiver = identityAsyncClient.createUser().block();
1355+
1356+
CallAutomationAsyncClient callerAsyncClient = getCallAutomationClientUsingConnectionString(httpClient)
1357+
.addPolicy((context, next) -> logHeaders("playMultipleFileSourcesWhenParticipantOnHoldTest", next))
1358+
.sourceIdentity(caller)
1359+
.buildAsyncClient();
1360+
1361+
// Create call automation client for receivers.
1362+
CallAutomationAsyncClient receiverAsyncClient = getCallAutomationClientUsingConnectionString(httpClient)
1363+
.addPolicy((context, next) -> logHeaders("playMultipleFileSourcesWhenParticipantOnHoldTest", next))
1364+
.buildAsyncClient();
1365+
1366+
String uniqueId = serviceBusWithNewCall(caller, receiver);
1367+
1368+
// create a call
1369+
List<CommunicationIdentifier> targets = Collections.singletonList(receiver);
1370+
CreateGroupCallOptions createCallOptions
1371+
= new CreateGroupCallOptions(targets, DISPATCHER_CALLBACK + String.format("?q=%s", uniqueId));
1372+
Response<CreateCallResult> createCallResultResponse
1373+
= callerAsyncClient.createGroupCallWithResponse(createCallOptions).block();
1374+
assertNotNull(createCallResultResponse);
1375+
CreateCallResult createCallResult = createCallResultResponse.getValue();
1376+
assertNotNull(createCallResult);
1377+
assertNotNull(createCallResult.getCallConnectionProperties());
1378+
String callerConnectionId = createCallResult.getCallConnectionProperties().getCallConnectionId();
1379+
assertNotNull(callerConnectionId);
1380+
1381+
// wait for the incomingCallContext
1382+
String incomingCallContext = waitForIncomingCallContext(uniqueId, Duration.ofSeconds(10));
1383+
assertNotNull(incomingCallContext);
1384+
1385+
// answer the call
1386+
AnswerCallOptions answerCallOptions
1387+
= new AnswerCallOptions(incomingCallContext, DISPATCHER_CALLBACK + String.format("?q=%s", uniqueId));
1388+
AnswerCallResult answerCallResult
1389+
= Objects.requireNonNull(receiverAsyncClient.answerCallWithResponse(answerCallOptions).block())
1390+
.getValue();
1391+
assertNotNull(answerCallResult);
1392+
assertNotNull(answerCallResult.getCallConnectionAsync());
1393+
assertNotNull(answerCallResult.getCallConnectionProperties());
1394+
callDestructors.add(answerCallResult.getCallConnectionAsync());
1395+
1396+
// wait for callConnected
1397+
CallConnected callConnected = waitForEvent(CallConnected.class, callerConnectionId, Duration.ofSeconds(10));
1398+
assertNotNull(callConnected);
1399+
1400+
// hold the participant
1401+
CallMediaAsync callMediaAsync = createCallResult.getCallConnectionAsync().getCallMediaAsync();
1402+
PlaySource holdPlaySource = new FileSource().setUrl(MEDIA_SOURCE);
1403+
callMediaAsync.hold(receiver, holdPlaySource).block();
1404+
sleepIfRunningAgainstService(3000);
1405+
HoldAudioStarted holdAudioStarted
1406+
= waitForEvent(HoldAudioStarted.class, callerConnectionId, Duration.ofSeconds(20));
1407+
assertNotNull(holdAudioStarted);
1408+
1409+
CallConnectionAsync callConnectionAsync = callerAsyncClient.getCallConnectionAsync(callerConnectionId);
1410+
CallParticipant participantResult = callConnectionAsync.getParticipant(receiver).block();
1411+
assertNotNull(participantResult);
1412+
assertTrue(participantResult.isOnHold());
1413+
1414+
// Assert multiple File Sources
1415+
List<PlaySource> playFileSources = new ArrayList<PlaySource>();
1416+
playFileSources.add(new FileSource().setUrl(MEDIA_SOURCE));
1417+
playFileSources.add(new FileSource().setUrl(MEDIA_SOURCE));
1418+
PlayOptions playOptions = new PlayOptions(playFileSources, targets);
1419+
playOptions.setInterruptHoldAudio(true);
1420+
// Play multiple files sources
1421+
callMediaAsync.playWithResponse(playOptions).block();
1422+
HoldAudioPaused holdAudioPaused
1423+
= waitForEvent(HoldAudioPaused.class, callerConnectionId, Duration.ofSeconds(20));
1424+
assertNotNull(holdAudioPaused);
1425+
1426+
PlayStarted playStarted = waitForEvent(PlayStarted.class, callerConnectionId, Duration.ofSeconds(20));
1427+
assertNotNull(playStarted);
1428+
1429+
PlayCompleted playCompleted = waitForEvent(PlayCompleted.class, callerConnectionId, Duration.ofSeconds(20));
1430+
assertNotNull(playCompleted);
1431+
1432+
HoldAudioResumed holdAudioResumed
1433+
= waitForEvent(HoldAudioResumed.class, callerConnectionId, Duration.ofSeconds(20));
1434+
assertNotNull(holdAudioResumed);
1435+
1436+
// unhold the participant
1437+
callMediaAsync.unhold(receiver).block();
1438+
HoldAudioCompleted holdAudioCompleted
1439+
= waitForEvent(HoldAudioCompleted.class, callerConnectionId, Duration.ofSeconds(20));
1440+
assertNotNull(holdAudioCompleted);
1441+
1442+
sleepIfRunningAgainstService(3000);
1443+
participantResult = callConnectionAsync.getParticipant(receiver).block();
1444+
assertNotNull(participantResult);
1445+
assertFalse(participantResult.isOnHold());
1446+
} catch (Exception ex) {
1447+
fail("Unexpected exception received", ex);
1448+
} finally {
1449+
if (!callDestructors.isEmpty()) {
1450+
try {
1451+
callDestructors.forEach(callConnection -> callConnection.hangUpWithResponse(true).block());
1452+
} catch (Exception ignored) {
1453+
// Some call might have been terminated during the test, and it will cause exceptions here.
1454+
// Do nothing and iterate to next call connection.
1455+
}
1456+
}
1457+
}
1458+
}
13191459
}

0 commit comments

Comments
 (0)