Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
395c717
UI Library quickstarts
ddematheu2 Nov 12, 2021
9c625f5
UI Library Quickstart Code
ddematheu2 Nov 12, 2021
3c5a4db
UI Library quickstart Readme
ddematheu2 Nov 12, 2021
e0445f6
additional files
ddematheu2 Nov 12, 2021
9ee489d
Update README.md
ddematheu2 Nov 12, 2021
fab1dff
Update README.md
ddematheu2 Nov 12, 2021
0353317
Add Quickstart for NetworkTraversal for JS
AriZavala2 Nov 19, 2021
4b1a5c7
Update PR
AriZavala2 Nov 23, 2021
2f39828
Update PR
AriZavala2 Nov 24, 2021
91a2096
Update PR
AriZavala2 Nov 24, 2021
c509066
Merge pull request #31 from AriZavala2/main
chriswhilar Nov 29, 2021
00325d0
Update README.md
ddematheu2 Dec 17, 2021
5d3dad4
updating app.tsx to work with the latest ui library version (#36)
alkwa-msft Dec 17, 2021
b4b0066
Typo "Javascript"→"JavaScript" (#24)
hyoshioka0128 Dec 17, 2021
4f4b57d
pushing fixes so the quickstart works without any additional code cha…
alkwa-msft Dec 17, 2021
5799db9
Typo "Javascript"→"JavaScript" (#25)
hyoshioka0128 Dec 17, 2021
21b6792
Typo "Javascript"→"JavaScript" (#32)
hyoshioka0128 Dec 17, 2021
45c6da9
Typo Javascript→JavaScript (#26)
JunaidbhaiAk Dec 17, 2021
15f2108
Typo "Javascript"→"JavaScript" (#27)
hyoshioka0128 Dec 17, 2021
ffebbc2
Typo "Javascript"→"JavaScript" (#30)
hyoshioka0128 Dec 17, 2021
ebc6ea7
Typo "Javascript"→"JavaScript" (#28)
hyoshioka0128 Dec 17, 2021
95c2eb8
Remove credentials from chat quickstart
communication-ui-bot Dec 22, 2021
90ad058
initial boilerplate for the sample app
richardcho-msft Dec 30, 2021
a51a198
add controllers
richardcho-msft Dec 30, 2021
251d74a
handle event grid subscription validation
richardcho-msft Dec 31, 2021
ee7487c
handle callback from ACS
richardcho-msft Jan 4, 2022
9dc5843
Merge pull request #37 from Azure-Samples/jinan/remove-credentials
prprabhu-ms Jan 4, 2022
d2007ae
Update client.js (#38)
akania Jan 6, 2022
67b444b
incoming call sample
richardcho-msft Jan 17, 2022
ac15d77
Merge branch 'main' of https://github.com/richardcho-msft/communicati…
richardcho-msft Jan 18, 2022
872b014
add readme and cleanup
richardcho-msft Jan 18, 2022
9ba879b
update license type
richardcho-msft Jan 18, 2022
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
8 changes: 8 additions & 0 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{
"markdownlint.config": {
"MD028": false,
"MD025": {
"front_matter_title": ""
}
}
}
10 changes: 9 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,4 +26,12 @@ Azure Communication Services enable developers to add communication capabilities

8. [Call To Phone](https://docs.microsoft.com/azure/communication-services/quickstarts/voice-video-calling/pstn-call?pivots=platform-web)

9. [Use managed identities](https://docs.microsoft.com/azure/communication-services/quickstarts/managed-identity?pivots=programming-language-javascript)
9. [Use managed identities](https://docs.microsoft.com/azure/communication-services/quickstarts/managed-identity?pivots=programming-language-javascript)

10. [Get Started with UI Components](https://azure.github.io/communication-ui-library/?path=/story/quickstarts-uicomponents--page)

11. [Get Started with Composites](https://azure.github.io/communication-ui-library/?path=/story/quickstarts-composites--page)

12. [Get Started with Chat Stateful Client](https://azure.github.io/communication-ui-library/?path=/story/quickstarts-statefulclient--page)

13. [Get Started with Call Stateful Client](https://azure.github.io/communication-ui-library/?path=/story/quickstarts-statefulclient--page)
2 changes: 1 addition & 1 deletion add-1-on-1-phone-calling/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ products:

# Add 1 on 1 phone calling to your application

This code sample walks through the process of integration Azure Communication Services phone calling into your Javascript application.
This code sample walks through the process of integration Azure Communication Services phone calling into your JavaScript application.

This quickstart sample includes the code that is explained as part of [this document](https://docs.microsoft.com/azure/communication-services/quickstarts/voice-video-calling/pstn-call?pivots=platform-web). See that document for additional details on how this sample works.

Expand Down
5 changes: 3 additions & 2 deletions add-1-on-1-video-calling/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ products:

# Add 1 on 1 video calling to your application

This code sample walks through the process of integration Azure Communication Services video calling into your Javascript application.
This code sample walks through the process of integration Azure Communication Services video calling into your JavaScript application.

This quickstart sample includes the code that is explained as part of [this document](https://docs.microsoft.com/azure/communication-services/quickstarts/voice-video-calling/get-started-with-video-calling). See that document for additional details on how this sample works.

Expand All @@ -22,7 +22,8 @@ This quickstart sample includes the code that is explained as part of [this docu

## Run the code
1. Run `npm i` on the directory of the project to install dependencies
2. Use the webpack-dev-server to build and run your app. Run the following command to bundle application host in on a local webserver:
2. Add a [user access token](https://docs.microsoft.com/azure/communication-services/quickstarts/access-tokens?pivots=programming-language-javascript) in line 54 of the `client.js`.
3. Use the webpack-dev-server to build and run your app. Run the following command to bundle application host in on a local webserver:

npx webpack-dev-server --entry ./client.js --output bundle.js --debug --devtool inline-source-map

Expand Down
2 changes: 1 addition & 1 deletion add-1-on-1-voice-calling/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ products:

# Add 1 on 1 voice calling to your application

This code sample walks through the process of integration Azure Communication Services voice calling into your Javascript application.
This code sample walks through the process of integration Azure Communication Services voice calling into your JavaScript application.

This quickstart sample includes the code that is explained as part of [this document](https://docs.microsoft.com/azure/communication-services/quickstarts/voice-video-calling/getting-started-with-calling?pivots=platform-web). See that document for additional details on how this sample works.

Expand Down
2 changes: 1 addition & 1 deletion add-chat/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ products:

# Add chat to your application

This code sample walks through the process of integration Azure Communication Services real time chat into your Javascript application.
This code sample walks through the process of integration Azure Communication Services real time chat into your JavaScript application.

This quickstart sample includes the code that is explained as part of [this document](https://docs.microsoft.com/azure/communication-services/quickstarts/chat/get-started?pivots=programming-language-javascript). See that document for additional details on how this sample works.

Expand Down
3 changes: 3 additions & 0 deletions incoming-call-routing/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
bin/*
node_modules
.vscode
41 changes: 41 additions & 0 deletions incoming-call-routing/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
How to run
1. Create ACS resource from Azure Portal

2. Create 3 ACS User Identities(MRI)
Example
```
User 1: 8:acs:<ACS resource id>-<guid>
User 2: 8:acs:<ACS resource id>-<guid>
User 3: 8:acs:<ACS resource id>-<guid>
```

3. Put User2 MRI into the config AllowedRecipientList

4. Put User3 MRI into the config TargetParticipant

5. Start ngrok
```
ngrok http 3000
```

6. Update config with ngrok endpoint. Example
```
"appCallbackBaseUri": "https://4087-75-155-234-140.ngrok.io"
```

7. Start sample app locally
```
npm run start
```

or to hot reload
```
npm run dev
```

8. Register webhook to your ACS resource
```
armclient put "/subscriptions/<subscription id>/resourceGroups/<rg>/providers/Microsoft.Communication/CommunicationServices/<acs name>/providers/Microsoft.EventGrid/eventSubscriptions/IncomingCallEventSub?api-version=2020-06-01" "{'properties':{'destination':{'properties':{'endpointUrl':'https://<ngrok url>/OnIncomingCall'},'endpointType':'WebHook'},'filter':{'includedEventTypes': ['Microsoft.Communication.IncomingCall']}}}" -verbose
```

9. Make a call from User1 to User2
7 changes: 7 additions & 0 deletions incoming-call-routing/appsettings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"resourceConnectionString": "<ACS connection string>",
"appCallbackBaseUri": "<callback api uri>",
"audioFileUri": "<audio file path>",
"targetParticipant": "<transfer ACS mri>",
"allowedRecipientList": ["<allowed ACS mris>"]
}
4 changes: 4 additions & 0 deletions incoming-call-routing/clients/callingServerClient.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
import { CallingServerClient } from "@azure/communication-calling-server";
import config from "../appsettings.json";

export const getCallingServerClient = () => new CallingServerClient(config.resourceConnectionString);
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import { CloudEvent, EventGridDeserializer } from "@azure/eventgrid";
import { Router } from "express";
import { authorize } from "../eventHandlers/eventAuthHandler";
import { processNotification } from "../eventHandlers/notificationHandler";
import { IncomingCallEvent } from "../incomingCallEvent";

const callingServerCallbackRoute = "/CallingServerAPICallbacks";
const router = Router();
const deserializer = new EventGridDeserializer();

router.post(callingServerCallbackRoute, async (req, res) => {
try {
const secret = req.query["secret"]?.toString();

if (authorize(secret)) {
const events = await deserializer.deserializeCloudEvents(req.body[0]);

for (const event of events) {
console.log(`Incoming call event: ${event.type}`);
console.log(`incoming call data: ${JSON.stringify(event.data)}`);

processNotification(event as CloudEvent<IncomingCallEvent>);
}

return res.sendStatus(200);
} else {
return res.sendStatus(401);
}
} catch (e) {
return res.status(500).send(e);
}
});

export {
router as callingServerCallbackHandler,
callingServerCallbackRoute
};
46 changes: 46 additions & 0 deletions incoming-call-routing/controllers/incomingCallController.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
import config from "../appsettings.json";
import { EventGridDeserializer, SubscriptionValidationEventData } from "@azure/eventgrid";
import { Router } from "express";
import { report } from "../incomingCallHandler";

const incomingCallRoute = "/OnIncomingCall";
const router = Router();
const { deserializeEventGridEvents } = new EventGridDeserializer();

router.post(incomingCallRoute, async (req, res) => {
try {
const events = await deserializeEventGridEvents(req.body[0]);

for (const { eventType, data } of events) {
console.log(`Incoming call event: ${eventType}`);
console.log(`incoming call data: ${JSON.stringify(data)}`);

if (eventType === "Microsoft.EventGrid.SubscriptionValidationEvent") {
const validationEventData = data as SubscriptionValidationEventData;

if (!validationEventData?.validationCode) {
throw new Error("Unable to validate Event Grid subscription");
}

return res.status(200).send({ validationResponse: validationEventData.validationCode });
}

if (eventType === "Microsoft.Communication.IncomingCall") {
const { incomingCallContext, to } = data as any;

if (config.allowedRecipientList.includes(to?.communicationUser?.id)) {
report(incomingCallContext);
}
}
}

return res.sendStatus(200);
} catch (e) {
return res.status(500).send(e);
}
});

export {
router as incomingCallHandler,
incomingCallRoute
};
34 changes: 34 additions & 0 deletions incoming-call-routing/eventHandlers/callConnectionHandler.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import { CallingServerEventTypeValue } from "@azure/communication-calling-server";
import { CallConnectionStateChangedEvent, KnownCallConnectionState } from "@azure/communication-calling-server/src/generated/src/models";
import { IncomingCallEvent } from "../incomingCallEvent";
import { subscribe, unsubscribeAll } from "./notificationHandler";

function registerCallConnectionDisconnectedEvent(callConnectionId: string) {
subscribe(callConnectionId, CallingServerEventTypeValue.CallConnectionStateChangedEvent, async (eventData: IncomingCallEvent) => {
const { callConnectionState } = eventData as CallConnectionStateChangedEvent;

if (callConnectionState === KnownCallConnectionState.Disconnected) {
unsubscribeAll(callConnectionId);
}
});
}

function registerCallConnectionConnectedEvent(callConnecionId: string, notifyConnectionState: (value :boolean) => void) {
subscribe(callConnecionId, CallingServerEventTypeValue.CallConnectionStateChangedEvent, async (eventData: IncomingCallEvent) => {
const { callConnectionState } = eventData as CallConnectionStateChangedEvent;

if (callConnectionState === KnownCallConnectionState.Connected) {
notifyConnectionState(true);
}
});
}

function establishConnection(callConnecionId: string) {
return new Promise<boolean>(resolver => registerCallConnectionConnectedEvent(callConnecionId, resolver));
}

export {
registerCallConnectionDisconnectedEvent,
registerCallConnectionConnectedEvent,
establishConnection
}
22 changes: 22 additions & 0 deletions incoming-call-routing/eventHandlers/dtmfEventHandler.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import { CallingServerEventTypeValue } from "@azure/communication-calling-server";
import { KnownToneValue, ToneReceivedEvent } from "@azure/communication-calling-server/src/generated/src/models";
import { IncomingCallEvent, InternalEventTypeValue } from "../incomingCallEvent";
import { buildEventKey, subscribe, unsubscribe } from "./notificationHandler";
import { completePlayAudioEvent } from "./playAudioHandler";
import { transferCall } from "./transferParticipantHandler";

function registerDtmfToneEvent(callConnectionId: string) {
subscribe(callConnectionId, CallingServerEventTypeValue.ToneReceivedEvent, async (eventData: IncomingCallEvent) => {
const toneReceivedEvent = eventData as ToneReceivedEvent;

if (toneReceivedEvent?.toneInfo?.tone === KnownToneValue.Tone1) {
await completePlayAudioEvent(callConnectionId);

unsubscribe(buildEventKey(callConnectionId, InternalEventTypeValue.InternalPlayAudioRunningEvent));

await transferCall(callConnectionId);
}
});
}

export { registerDtmfToneEvent }
12 changes: 12 additions & 0 deletions incoming-call-routing/eventHandlers/eventAuthHandler.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@

const secretKey = "secret";
const secretValue = "h3lloW0rld";

const getSecretQueryString = () => `${secretKey}=${encodeURIComponent(secretValue)}`;

const authorize = (query: string | undefined) => query === secretValue;

export {
getSecretQueryString,
authorize
};
71 changes: 71 additions & 0 deletions incoming-call-routing/eventHandlers/notificationHandler.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
import { CloudEvent } from "@azure/eventgrid";
import {
PlayAudioResultEvent,
AddParticipantResultEvent,
} from "@azure/communication-calling-server";
import { IncomingCallEvent } from "../incomingCallEvent";

interface NotificationEvent {
eventKey: string;
eventData: IncomingCallEvent;
};

const notificationCallbacks: Map<string, (eventData: IncomingCallEvent) => void> = new Map();

async function processNotification(event: CloudEvent<IncomingCallEvent>) {
const { eventData, eventKey } = extractEvent(event);
const notificationCallback = notificationCallbacks.get(eventKey);

if (notificationCallback !== undefined) {
await notificationCallback(eventData);

return true;
}

return false;
}

function subscribe(
eventContext: string,
eventType: string,
notificationCallback: (event: IncomingCallEvent) => Promise<void>) {
notificationCallbacks.set(buildEventKey(eventContext, eventType), notificationCallback);
}

function unsubscribe(eventKey: string) {
notificationCallbacks.delete(eventKey);
}

function unsubscribeAll(eventKeyPrefix: string) {
notificationCallbacks.forEach((_, key, map) => {
if (key.includes(eventKeyPrefix)) {
map.delete(key);
}
});
}

function buildEventKey(eventContext: string, eventType: string) {
return `${eventContext}-${eventType}`;
}

function extractEvent(event: CloudEvent<IncomingCallEvent>): NotificationEvent {
const { type: eventType, data: eventData } = event;
const eventKeyPrefix = (hasOperationContext(eventData) ? eventData.operationContext : eventData?.callConnectionId) || "";

return {
eventKey: buildEventKey(eventKeyPrefix, eventType),
eventData
};
}

function hasOperationContext(eventData: IncomingCallEvent): eventData is AddParticipantResultEvent | PlayAudioResultEvent {
return (eventData as AddParticipantResultEvent || eventData as PlayAudioResultEvent)?.operationContext !== undefined;
}

export {
subscribe,
unsubscribe,
unsubscribeAll,
processNotification,
buildEventKey,
};
Loading