Skip to content

Commit

Permalink
Added mute methods (#26372)
Browse files Browse the repository at this point in the history
### Packages impacted by this PR
communication-call-automation

### Issues associated with this PR


### Describe the problem that is addressed by this PR
Added mute API SDK methods

### What are the possible designs available to address the problem? If
there are more than one possible design, why was the one in this PR
chosen?


### Are there test cases added in this PR? _(If not, why?)_
Yes

### Provide a list of related PRs _(if any)_


### Command used to generate this PR:**_(Applicable only to SDK release
request PRs)_

### Checklists
- [x] Added impacted package name to the issue description
- [ ] Does this PR needs any fixes in the SDK Generator?** _(If so,
create an Issue in the
[Autorest/typescript](https://github.com/Azure/autorest.typescript)
repository and link it here)_
- [x] Added a changelog (if necessary)
  • Loading branch information
vivekmore-msft authored Jun 30, 2023
1 parent 38a02c4 commit 426cb44
Show file tree
Hide file tree
Showing 8 changed files with 598 additions and 0 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -17,3 +17,4 @@ Call Automation enables developers to build call workflows. Personalise customer
- Parse various events happening in the call, such as CallConnected and PlayCompleted event.
- Start/Stop continuous DTMF recognition by subscribing/unsubscribing to tones.
- Send DTMF tones to a participant in the call.
- Mute participants in the call.

Large diffs are not rendered by default.

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,7 @@ export class CallConnection {
getParticipant(targetParticipant: CommunicationIdentifier, options?: GetParticipantOptions): Promise<CallParticipant>;
hangUp(isForEveryone: boolean, options?: HangUpOptions): Promise<void>;
listParticipants(options?: GetParticipantOptions): Promise<ListParticipantsResult>;
muteParticipants(participant: CommunicationIdentifier, options?: MuteParticipantsOption): Promise<MuteParticipantsResult>;
removeParticipant(participant: CommunicationIdentifier, options?: RemoveParticipantsOption): Promise<RemoveParticipantResult>;
transferCallToParticipant(targetParticipant: CommunicationIdentifier, options?: TransferCallToParticipantOptions): Promise<TransferCallResult>;
}
Expand Down Expand Up @@ -428,6 +429,16 @@ export type MediaStreamingContentType = string;
// @public
export type MediaStreamingTransportType = string;

// @public
export interface MuteParticipantsOption extends OperationOptions {
operationContext?: string;
}

// @public
export interface MuteParticipantsResult {
operationContext?: string;
}

// @public
export function parseCallAutomationEvent(encodedEvents: string | Record<string, unknown>): CallAutomationEvent;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import {
AddParticipantRequest,
CallAutomationApiClient,
CallAutomationApiClientOptionalParams,
MuteParticipantsRequest,
RemoveParticipantRequest,
TransferToParticipantRequest,
} from "./generated/src";
Expand All @@ -20,6 +21,7 @@ import {
GetCallConnectionPropertiesOptions,
GetParticipantOptions,
HangUpOptions,
MuteParticipantsOption,
RemoveParticipantsOption,
TransferCallToParticipantOptions,
} from "./models/options";
Expand All @@ -28,6 +30,7 @@ import {
TransferCallResult,
AddParticipantResult,
RemoveParticipantResult,
MuteParticipantsResult,
} from "./models/responses";
import {
callParticipantConverter,
Expand Down Expand Up @@ -258,4 +261,33 @@ export class CallConnection {
};
return removeParticipantsResult;
}

/**
* Mute participants from the call.
*
* @param participant - Participant to be muted from the call.
*/
public async muteParticipants(
participant: CommunicationIdentifier,
options: MuteParticipantsOption = {}
): Promise<MuteParticipantsResult> {
const muteParticipantsRequest: MuteParticipantsRequest = {
targetParticipants: [communicationIdentifierModelConverter(participant)],
operationContext: options.operationContext,
};
const optionsInternal = {
...options,
repeatabilityFirstSent: new Date().toUTCString(),
repeatabilityRequestID: uuidv4(),
};
const result = await this.callConnection.mute(
this.callConnectionId,
muteParticipantsRequest,
optionsInternal
);
const muteParticipantsResult: MuteParticipantsResult = {
...result,
};
return muteParticipantsResult;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -146,6 +146,14 @@ export interface RemoveParticipantsOption extends OperationOptions {
operationContext?: string;
}

/**
* Options to mute participants.
*/
export interface MuteParticipantsOption extends OperationOptions {
/** Used by customers when calling mid-call actions to correlate the request to the response event. */
operationContext?: string;
}

/**
* Options to play audio.
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,12 @@ export interface RemoveParticipantResult {
operationContext?: string;
}

/** The response payload for muting participants from the call. */
export interface MuteParticipantsResult {
/** The operation context provided by client. */
operationContext?: string;
}

/** The response payload for starting a call recording or getting call recording state. */
export interface RecordingStateResult {
recordingId: string;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import {
AddParticipantResult,
TransferCallResult,
RemoveParticipantResult,
MuteParticipantsResult,
} from "../src";
import Sinon, { SinonStubbedInstance } from "sinon";
import { CALL_TARGET_ID } from "./utils/connectionUtils";
Expand Down Expand Up @@ -220,6 +221,28 @@ describe("CallConnection Unit Tests", () => {
})
.catch((error) => console.error(error));
});

it("MuteParticipants", async () => {
// mocks
const muteParticipantsResultMock: MuteParticipantsResult = {};
callConnection.muteParticipants.returns(
new Promise((resolve) => {
resolve(muteParticipantsResultMock);
})
);

const promiseResult = callConnection.muteParticipants(target.targetParticipant);

// asserts
promiseResult
.then((result: MuteParticipantsResult) => {
assert.isNotNull(result);
assert.isTrue(callConnection.muteParticipants.calledWith(target.targetParticipant));
assert.equal(result, muteParticipantsResultMock);
return;
})
.catch((error) => console.error(error));
});
});

describe("CallConnection Live Tests", function () {
Expand Down Expand Up @@ -366,4 +389,72 @@ describe("CallConnection Live Tests", function () {
const callEndedEvent = await waitForEvent("CallDisconnected", callConnectionId, 8000);
assert.isDefined(callEndedEvent);
}).timeout(60000);

it("Mute a participant", async function () {
testName = this.test?.fullTitle()
? this.test?.fullTitle().replace(/ /g, "_")
: "add_participant_and_get_call_props";
await loadPersistedEvents(testName);

const callInvite: CallInvite = { targetParticipant: testUser2 };
const uniqueId = await serviceBusWithNewCall(testUser, testUser2);
const callBackUrl: string = dispatcherCallback + `?q=${uniqueId}`;
const result = await callerCallAutomationClient.createCall(callInvite, callBackUrl);
const incomingCallContext = await waitForIncomingCallContext(uniqueId, 20000);
callConnectionId = result.callConnectionProperties.callConnectionId
? result.callConnectionProperties.callConnectionId
: "";
assert.isDefined(incomingCallContext);
if (incomingCallContext) {
await receiverCallAutomationClient.answerCall(incomingCallContext, callBackUrl);
}
const callConnectedEvent = await waitForEvent("CallConnected", callConnectionId, 8000);
assert.isDefined(callConnectedEvent);
callConnection = result.callConnection;
const testUser3: CommunicationUserIdentifier = await createTestUser(recorder);
const participantInvite: CallInvite = { targetParticipant: testUser3 };
const uniqueId2 = await serviceBusWithNewCall(testUser, testUser3);
const callBackUrl2: string = dispatcherCallback + `?q=${uniqueId2}`;

const addResult = await callConnection.addParticipant(participantInvite);
assert.isDefined(addResult);

// A call needs at least 3 participants to mute a participant. So adding one more participant.
const anotherReceiverCallAutomationClient: CallAutomationClient = createCallAutomationClient(
recorder,
testUser3
);
const anotherIncomingCallContext = await waitForIncomingCallContext(uniqueId2, 20000);
if (anotherIncomingCallContext) {
await anotherReceiverCallAutomationClient.answerCall(
anotherIncomingCallContext,
callBackUrl2
);
}
const participantAddedEvent = await waitForEvent(
"AddParticipantSucceeded",
callConnectionId,
8000
);
assert.isDefined(participantAddedEvent);

const muteResult = await callConnection.muteParticipants(testUser2);
assert.isDefined(muteResult);

const participantsUpdatedEvent = await waitForEvent(
"ParticipantsUpdated",
callConnectionId,
8000
);

assert.isDefined(participantsUpdatedEvent);
let isMuted = false;
const participantsUpdatedEventJson = JSON.parse(JSON.stringify(participantsUpdatedEvent));
for (const participant of participantsUpdatedEventJson["participants"]) {
if (participant["identifier"]["communicationUserId"] === testUser2.communicationUserId) {
isMuted = participant["isMuted"];
}
}
assert.isTrue(isMuted);
}).timeout(90000);
});

0 comments on commit 426cb44

Please sign in to comment.