Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Tested Beta4 Changes #252

Draft
wants to merge 8 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all 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
33 changes: 26 additions & 7 deletions CallAutomation_OutboundCalling/src/app.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,8 @@ import {
CallInvite,
CreateCallOptions,
CallMedia,
DtmfTone } from "@azure/communication-call-automation";
DtmfTone,
PlayToAllOptions} from "@azure/communication-call-automation";
import path from 'path';

config();
Expand All @@ -26,6 +27,7 @@ app.use(express.json());
let callConnectionId: string;
let callConnection: CallConnection;
let serverCallId: string;
let correlationId: string;
let callee: PhoneNumberIdentifier;
let acsClient: CallAutomationClient;

Expand Down Expand Up @@ -57,12 +59,18 @@ async function createOutboundCall() {

const options: CreateCallOptions ={ callIntelligenceOptions: { cognitiveServicesEndpoint: process.env.COGNITIVE_SERVICES_ENDPOINT } };
console.log("Placing outbound call...");
acsClient.createCall(callInvite, process.env.CALLBACK_URI + "/api/callbacks", options);
const result = await acsClient.createCall(callInvite, process.env.CALLBACK_URI + "/api/callbacks", options);
console.log("answered by", result.callConnectionProperties.answeredby);

}

async function handlePlay(callConnectionMedia:CallMedia, textContent:string){
const play : TextSource = { text:textContent , voiceName: "en-US-NancyNeural", kind: "textSource"}
await callConnectionMedia.playToAll([play]);
const playInterrupt : TextSource = { text:"Interrupt prompt message" , voiceName: "en-US-NancyNeural", kind: "textSource"}
const playInterruptT : PlayToAllOptions = { interruptCallMediaOperation: false }
const playInterruptF : PlayToAllOptions = { interruptCallMediaOperation: false }
await callConnectionMedia.playToAll([play], playInterruptF);
await callConnectionMedia.playToAll([playInterrupt], playInterruptT);
}

async function getChoices(){
Expand All @@ -84,12 +92,17 @@ async function getChoices(){

async function startRecognizing(callMedia: CallMedia, textToPlay: string, context: string){
const playSource: TextSource = { text: textToPlay, voiceName: "en-US-NancyNeural", kind: "textSource" };

const playSources: (TextSource )[] = [
{ voiceName: "en-US-NancyNeural", kind: "textSource", text: "Recognize Prompt One" },
{ voiceName: "en-US-NancyNeural", kind: "textSource", text: "Recognize Prompt Two" },
{ voiceName: "en-US-NancyNeural", kind: "textSource", text: "Hi, Please confirm or cancel." },
];
const recognizeOptions: CallMediaRecognizeChoiceOptions = {
choices: await getChoices(),
interruptPrompt: false,
initialSilenceTimeoutInSeconds: 10,
playPrompt: playSource,
// playPrompt: playSource,
playPrompts:playSources,
operationContext: context,
kind: "callMediaRecognizeChoiceOptions"
};
Expand All @@ -107,7 +120,9 @@ app.post("/api/callbacks", async (req: any, res: any) => {
const eventData = event.data;
callConnectionId = eventData.callConnectionId;
serverCallId = eventData.serverCallId;
console.log("Call back event received, callConnectionId=%s, serverCallId=%s, eventType=%s", callConnectionId, serverCallId, event.type);
correlationId = eventData.correlationId;
console.log("Call back event received, callConnectionId=%s, serverCallId=%s, correlationId=%s, eventType=%s", callConnectionId, serverCallId, correlationId, event.type);
console.log("Call back event received", eventData);
callConnection = acsClient.getCallConnection(callConnectionId);
const callMedia = callConnection.getCallMedia();
if (event.type === "Microsoft.Communication.CallConnected") {
Expand Down Expand Up @@ -151,9 +166,13 @@ app.post("/api/callbacks", async (req: any, res: any) => {
await startRecognizing(callMedia, replyText, retryContext);
}
}
else if (event.type === "Microsoft.Communication.PlayStarted") {
console.log("Play Started Event Triggerd.");
// hangUpCall();
}
else if (event.type === "Microsoft.Communication.PlayCompleted" || event.type === "Microsoft.Communication.playFailed") {
console.log("Terminating call.");
hangUpCall();
// hangUpCall();
}

res.sendStatus(200);
Expand Down
20 changes: 20 additions & 0 deletions incoming-call-recording/.env
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
PORT=8080
BASE_MEDIA_PATH="./src/resources/media_prompts/"
ACS_CONNECTION_STRING=""
CALLBACK_HOST_URI=""
COGNITIVE_SERVICE_ENDPOINT=""
COMMUNICATION_USR_ID = ""
COMMUNICATION_USR_ID2 = ""
# Pause on start either true or false
PAUSE_ON_START ="false"
# Teams user AAD object id or empty.
TEAMS_USER_ID=""
ACS_PHONE_NUMBER=""
TARGET_PHONE_NUMBER=""
TARGET_PHONE_NUMBER2=""
ACS_CALLER_PHONE_NUMBER=""
REJECT_CALL="false"
REDIRECT_CALL="false"
TRANSFER_CALL="false"
IS_BYOS = "true"
BRING_YOUR_OWN_STORAGE_URL=""
30 changes: 30 additions & 0 deletions incoming-call-recording/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
# Ignore node_modules directory
node_modules/

# Ignore environment variables file
.env

# Ignore build output directory
dist/
build/
public/assets/

# Ignore IDE/Editor-specific files
.vscode/
.vs
.idea/

# Ignore user-specific configuration files
.npmrc
.gitconfig

# Ignore log files
*.log

# Ignore OS-generated files
.DS_Store
Thumbs.db

# Ignore package lock files
package-lock.json
yarn.lock
68 changes: 68 additions & 0 deletions incoming-call-recording/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
|page_type|languages|products
|---|---|---|
|sample|<table><tr><td>Typescript</tr></td></table>|<table><tr><td>azure</td><td>azure-communication-services</td></tr></table>|

# Call Automation - Quick Start Sample

This sample application shows how the Azure Communication Services - Call Automation SDK can be used accept incoming call and record it with pause on start feature. It can start, pause, resume and stop recording.
Adds microsoft teams user as participant in active call.

## Prerequisites

- Create an Azure account with an active subscription. For details, see [Create an account for free](https://azure.microsoft.com/free/)
- [Visual Studio Code](https://code.visualstudio.com/download) installed
- [Node.js](https://nodejs.org/en/download) installed
- Create an Azure Communication Services resource. For details, see [Create an Azure Communication Resource](https://docs.microsoft.com/azure/communication-services/quickstarts/create-communication-resource). You will need to record your resource **connection string** for this sample.
- Get a phone number for your new Azure Communication Services resource. For details, see [Get a phone number](https://learn.microsoft.com/en-us/azure/communication-services/quickstarts/telephony/get-phone-number?tabs=windows&pivots=programming-language-csharp)
- Create Azure AI Multi Service resource. For details, see [Create an Azure AI Multi service](https://learn.microsoft.com/en-us/azure/cognitive-services/cognitive-services-apis-create-account).
- Install ngrok. Instructions [here](https://ngrok.com/)

## Before running the sample for the first time

1. Open an instance of PowerShell, Windows Terminal, Command Prompt or equivalent and navigate to the directory that you would like to clone the sample to.
2. git clone `https://github.com/Azure-Samples/communication-services-javascript-quickstarts.git`.
3. cd into the `incoming_call_recording` folder.
4. From the root of the above folder, and with node installed, run `npm install`

### Setup and host ngrok

You can run multiple tunnels on ngrok by changing ngrok.yml file as follows:

1. Open the ngrok.yml file from a powershell using the command ngrok config edit
2. Update the ngrok.yml file as follows:
authtoken: xxxxxxxxxxxxxxxxxxxxxxxxxx
version: "2"
region: us
tunnels:
first:
addr: 8080
proto: http
host_header: localhost:8080
second:
proto: http
addr: 5001
host_header: localhost:5001
NOTE: Make sure the "addr:" field has only the port number, not the localhost url.
3. Start all ngrok tunnels configured using the following command on a powershell - ngrok start --all

### Add a Managed Identity to the ACS Resource that connects to the Cognitive Services Resource

Follow the instructions in the [documentation](https://learn.microsoft.com/en-us/azure/communication-services/concepts/call-automation/azure-communication-services-azure-cognitive-services-integration).

### Configuring application

Open the `.env` file to configure the following settings

1. `CALLBACK_HOST_URI`: Base url of the app. (For local development replace the above ngrok url from the above for the port 8080).
2. `COGNITIVE_SERVICE_ENDPOINT`: Azure Multi Service endpoint.
3. `ACS_CONNECTION_STRING`: Azure Communication Service resource's connection string.
4. `COMMUNICATION_USR_ID` : Communication user id.
5. `PAUSE_ON_START` : Pause on start attribute for recording either true or false.
6. `TEAMS_USER_ID` : Microsoft teams user AAD object id.

### Run app locally

1. Open a new Powershell window, cd into the `incoming_call_recording` folder and run `npm run dev`
2. Browser should pop up with the below page. If not navigate it to `http://localhost:8080/`
3. Register an EventGrid Webhook for the IncomingCall Event that points to your DevTunnel URI endpoint ex `{CALLBACK_HOST_URI}/api/incomingCall` and register Recording File Status Updated event to you recordingstatus api endpoint ex. `{CALLBACK_HOST_URI}/api/recordingFileStatus`. Instructions [here](https://learn.microsoft.com/en-us/azure/communication-services/concepts/call-automation/incoming-call-notification).
4. Create call, Download recording and metadata from browser.
29 changes: 29 additions & 0 deletions incoming-call-recording/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
{
"name": "incoming_call_recording",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"build": "tsc",
"dev": "nodemon ./src/app.ts"
},
"keywords": [],
"author": "",
"license": "ISC",
"dependencies": {
"@azure/communication-call-automation": "^1.1.0",
"@azure/communication-common": "^2.2.0",
"@azure/eventgrid": "^4.12.0",
"@azure/openai": "^1.0.0-beta.7",
"@types/express": "^4.17.17",
"@types/node": "^20.2.1",
"dotenv": "^16.3.1",
"express": "^4.18.2",
"uuid": "^9.0.1"
},
"devDependencies": {
"nodemon": "^3.0.2",
"ts-node": "^10.9.1",
"typescript": "^5.0.4"
}
}
Loading