Skip to content

Commit 8e0dd24

Browse files
authored
Merge pull request #259953 from fangchen0601/patch-1
Add custom-context.md
2 parents da05aba + 85874f5 commit 8e0dd24

File tree

3 files changed

+282
-0
lines changed

3 files changed

+282
-0
lines changed
Lines changed: 275 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,275 @@
1+
---
2+
title: Azure Communication Services Call Automation how-to for passing call contextual data in Call Automation
3+
titleSuffix: An Azure Communication Services how-to document
4+
description: Provides a how-to guide for passing contextual information with Call Automation.
5+
author: juta
6+
ms.topic: how-to
7+
ms.service: azure-communication-services
8+
ms.subservice: call-automation
9+
ms.date: 11/28/2023
10+
ms.author: jutav
11+
manager: visho
12+
services: azure-communication-services
13+
---
14+
15+
# How to pass contextual data between calls
16+
17+
Call Automation allows developers to pass along custom contextual information when routing calls. Developers can pass metadata about the call, callee or any other information that is relevant to their application or business logic. This allows businesses to manage, and route calls across networks without having to worry about losing context.
18+
19+
Passing context is supported by specifying custom headers. These are an optional list of key-value pairs that can be included as part of `AddParticipant` or `Transfer` actions. The context can be later retrieved as part of the `IncomingCall` event payload.
20+
21+
Custom call context is also forwarded to the SIP protocol, this includes both the freeform custom headers as well as the standard User-to-User Information (UUI) SIP header. When routing an inbound call from your telephony network, the data set from your SBC in the custom headers and UUI is similarly included in the `IncomingCall` event payload.
22+
23+
All custom context data is opaque to Call Automation or SIP protocols and its content is unrelated to any basic functions.
24+
25+
Below are samples on how to get started using custom context headers in Call Automation.
26+
27+
As a prerequisite, we recommend you to read these articles to make the most of this guide:
28+
29+
- Call Automation [concepts guide](../../concepts/call-automation/call-automation.md#call-actions) that describes the action-event programming model and event callbacks.
30+
- Learn about [user identifiers](../../concepts/identifiers.md#the-communicationidentifier-type) like CommunicationUserIdentifier and PhoneNumberIdentifier used in this guide.
31+
32+
For all the code samples, `client` is CallAutomationClient object that can be created as shown and `callConnection` is the CallConnection object obtained from Answer or CreateCall response. You can also obtain it from callback events received by your application.
33+
34+
## Technical parameters
35+
Call Automation supports up to 5 custom SIP headers and 1000 custom VOIP headers. Additionally, developers can include a dedicated User-To-User header as part of SIP headers list.
36+
37+
The custom SIP header key must start with a mandatory ‘X-MS-Custom-’ prefix. The maximum length of a SIP header key is 64 chars, including the X-MS-Custom prefix. The maximum length of SIP header value is 256 chars. The same limitations apply when configuring the SIP headers on your SBC.
38+
39+
The maximum length of a VOIP header key is 64 chars. These headers can be sent without ‘x-MS-Custom’ prefix. The maximum length of VOIP header value is 1024 chars.
40+
41+
## Adding custom context when inviting a participant
42+
43+
### [csharp](#tab/csharp)
44+
45+
```csharp
46+
// Invite a communication services user and include one VOIP header
47+
var addThisPerson = new CallInvite(new CommunicationUserIdentifier("<user_id>"));
48+
addThisPerson.CustomCallingContext.AddVoip("myHeader", "myValue");
49+
AddParticipantsResult result = await callConnection.AddParticipantAsync(addThisPerson);
50+
// Invite a PSTN user and set UUI and custom SIP headers
51+
var callerIdNumber = new PhoneNumberIdentifier("+16044561234");
52+
var addThisPerson = new CallInvite(new PhoneNumberIdentifier("+16041234567"), callerIdNumber);
53+
54+
// Set custom UUI header. This key is sent on SIP protocol as User-to-User
55+
addThisPerson.CustomCallingContext.AddSipUui("value");
56+
57+
// This provided key will be automatically prefixed with X-MS-Custom on SIP protocol, such as 'X-MS-Custom-{key}'
58+
addThisPerson.CustomCallingContext.AddSipX("header1", "customSipHeaderValue1");
59+
AddParticipantsResult result = await callConnection.AddParticipantAsync(addThisPerson);
60+
```
61+
### [Java](#tab/java)
62+
```java
63+
// Invite a communication services user and include one VOIP header
64+
CallInvite callInvite = new CallInvite(new CommunicationUserIdentifier("<user_id>"));
65+
callInvite.getCustomCallingContext().addVoip("voipHeaderName", "voipHeaderValue");
66+
AddParticipantOptions addParticipantOptions = new AddParticipantOptions(callInvite);
67+
Response<AddParticipantResult> addParticipantResultResponse = callConnectionAsync.addParticipantWithResponse(addParticipantOptions).block();
68+
69+
// Invite a PSTN user and set UUI and custom SIP headers
70+
PhoneNumberIdentifier callerIdNumber = new PhoneNumberIdentifier("+16044561234");
71+
CallInvite callInvite = new CallInvite(new PhoneNumberIdentifier("+16041234567"), callerIdNumber);
72+
callInvite.getCustomCallingContext().addSipUui("value");
73+
callInvite.getCustomCallingContext().addSipX("header1", "customSipHeaderValue1");
74+
AddParticipantOptions addParticipantOptions = new AddParticipantOptions(callInvite);
75+
Response<AddParticipantResult> addParticipantResultResponse = callConnectionAsync.addParticipantWithResponse(addParticipantOptions).block();
76+
```
77+
78+
### [JavaScript](#tab/javascript)
79+
```javascript
80+
// Invite a communication services user and include one VOIP header
81+
const customCallingContext: CustomCallingContext = [];
82+
customCallingContext.push({ kind: "voip", key: "voipHeaderName", value: "voipHeaderValue" })
83+
const addThisPerson = {
84+
targetParticipant: { communicationUserId: "<acs_user_id>" },
85+
customCallingContext: customCallingContext,
86+
};
87+
const addParticipantResult = await callConnection.addParticipant(addThisPerson);
88+
89+
// Invite a PSTN user and set UUI and custom SIP headers
90+
const callerIdNumber = { phoneNumber: "+16044561234" };
91+
const customCallingContext: CustomCallingContext = [];
92+
customCallingContext.push({ kind: "sipuui", key: "", value: "value" });
93+
customCallingContext.push({ kind: "sipx", key: "headerName", value: "headerValue" })
94+
const addThisPerson = {
95+
targetParticipant: { phoneNumber: "+16041234567" },
96+
sourceCallIdNumber: callerIdNumber,
97+
customCallingContext: customCallingContext,
98+
};
99+
const addParticipantResult = await callConnection.addParticipant(addThisPerson);
100+
```
101+
102+
### [Python](#tab/python)
103+
```python
104+
#Invite a communication services user and include one VOIP header
105+
voip_headers = {"voipHeaderName", "voipHeaderValue"}
106+
target = CommunicationUserIdentifier("<acs_user_id>")
107+
result = call_connection_client.add_participant(
108+
target,
109+
voip_headers=voip_headers
110+
)
111+
112+
#Invite a PSTN user and set UUI and custom SIP headers
113+
caller_id_number = PhoneNumberIdentifier("+16044561234")
114+
sip_headers = {}
115+
sip_headers.add("User-To-User", "value")
116+
sip_headers.add("X-MS-Custom-headerName", "headerValue")
117+
target = PhoneNumberIdentifier("+16041234567")
118+
result = call_connection_client.add_participant(
119+
target,
120+
sip_headers=sip_headers,
121+
source_caller_id_number=caller_id_number
122+
)
123+
```
124+
125+
-----
126+
## Adding custom context during call transfer
127+
128+
### [csharp](#tab/csharp)
129+
130+
```csharp
131+
//Transfer to communication services user and include one VOIP header
132+
var transferDestination = new CommunicationUserIdentifier("<user_id>");
133+
var transferOption = new TransferToParticipantOptions(transferDestination);
134+
var transferOption = new TransferToParticipantOptions(transferDestination) {
135+
OperationContext = "<Your_context>",
136+
OperationCallbackUri = new Uri("<uri_endpoint>") // Sending event to a non-default endpoint.
137+
};
138+
transferOption.CustomCallingContext.AddVoip("customVoipHeader1", "customVoipHeaderValue1");
139+
TransferCallToParticipantResult result = await callConnection.TransferCallToParticipantAsync(transferOption);
140+
141+
//Transfer a PSTN call to phone number and set UUI and custom SIP headers
142+
var transferDestination = new PhoneNumberIdentifier("<target_phoneNumber>");
143+
var transferOption = new TransferToParticipantOptions(transferDestination);
144+
transferOption.CustomCallingContext.AddSipUui("uuivalue");
145+
transferOption.CustomCallingContext.AddSipX("header1", "headerValue");
146+
TransferCallToParticipantResult result = await callConnection.TransferCallToParticipantAsync(transferOption)
147+
```
148+
149+
### [Java](#tab/java)
150+
```java
151+
//Transfer to communication services user and include one VOIP header
152+
CommunicationIdentifier transferDestination = new CommunicationUserIdentifier("<user_id>");
153+
TransferCallToParticipantOptions options = new TransferCallToParticipantOptions(transferDestination);
154+
options.getCustomCallingContext().addVoip("voipHeaderName", "voipHeaderValue");
155+
Response<TransferCallResult> transferResponse = callConnectionAsync.transferToParticipantCallWithResponse(options).block();
156+
157+
//Transfer a PSTN call to phone number and set UUI and custom SIP headers
158+
CommunicationIdentifier transferDestination = new PhoneNumberIdentifier("<taget_phoneNumber>");
159+
TransferCallToParticipantOptions options = new TransferCallToParticipantOptions(transferDestination);
160+
options.getCustomCallingContext().addSipUui("UUIvalue");
161+
options.getCustomCallingContext().addSipX("sipHeaderName", "value");
162+
Response<TransferCallResult> transferResponse = callConnectionAsync.transferToParticipantCallWithResponse(options).block();
163+
```
164+
165+
### [JavaScript](#tab/javascript)
166+
```javascript
167+
//Transfer to communication services user and include one VOIP header
168+
const transferDestination = { communicationUserId: "<user_id>" };
169+
const transferee = { communicationUserId: "<transferee_user_id>" };
170+
const options = { transferee: transferee, operationContext: "<Your_context>", operationCallbackUrl: "<url_endpoint>" };
171+
const customCallingContext: CustomCallingContext = [];
172+
customCallingContext.push({ kind: "voip", key: "customVoipHeader1", value: "customVoipHeaderValue1" })
173+
options.customCallingContext = customCallingContext;
174+
const result = await callConnection.transferCallToParticipant(transferDestination, options);
175+
176+
//Transfer a PSTN call to phone number and set UUI and custom SIP headers
177+
const transferDestination = { phoneNumber: "<taget_phoneNumber>" };
178+
const transferee = { phoneNumber: "<transferee_phoneNumber>" };
179+
const options = { transferee: transferee, operationContext: "<Your_context>", operationCallbackUrl: "<url_endpoint>" };
180+
const customCallingContext: CustomCallingContext = [];
181+
customCallingContext.push({ kind: "sipuui", key: "", value: "uuivalue" });
182+
customCallingContext.push({ kind: "sipx", key: "headerName", value: "headerValue" })
183+
options.customCallingContext = customCallingContext;
184+
const result = await callConnection.transferCallToParticipant(transferDestination, options);
185+
```
186+
187+
### [Python](#tab/python)
188+
```python
189+
#Transfer to communication services user and include one VOIP header
190+
transfer_destination = CommunicationUserIdentifier("<user_id>")
191+
transferee = CommnunicationUserIdentifer("transferee_user_id")
192+
voip_headers = {"customVoipHeader1", "customVoipHeaderValue1"}
193+
result = call_connection_client.transfer_call_to_participant(
194+
target_participant=transfer_destination,
195+
transferee=transferee,
196+
voip_headers=voip_headers,
197+
opration_context="Your context",
198+
operationCallbackUrl="<url_endpoint>"
199+
)
200+
201+
#Transfer a PSTN call to phone number and set UUI and custom SIP headers
202+
transfer_destination = PhoneNumberIdentifer("<target_phoneNumber>")
203+
transferee = PhoneNumberIdentifer("transferee_phoneNumber")
204+
sip_headers={}
205+
sip_headers.add("X-MS-Custom-headerName", "headerValue")
206+
sip_headers.add("User-To-User","uuivale")
207+
result = call_connection_client.transfer_call_to_participant(
208+
target_participant=transfer_destination,
209+
transferee=transferee,
210+
sip_headers=sip_headers,
211+
opration_context="Your context",
212+
operationCallbackUrl="<url_endpoint>"
213+
)
214+
```
215+
216+
Transfer of a VoIP call to a phone number is currently not supported.
217+
218+
-----
219+
## Reading custom context from an incoming call event
220+
221+
### [csharp](#tab/csharp)
222+
223+
```csharp
224+
AcsIncomingCallEventData incomingEvent = <incoming call event from Event Grid>;
225+
// Retrieve incoming call custom context
226+
AcsIncomingCallCustomContext callCustomContext = incomingEvent.CustomContext;
227+
228+
// Inspect dictionary with key/value pairs
229+
var voipHeaders = callCustomContext.VoipHeaders;
230+
var sipHeaders = callCustomContext.SipHeaders;
231+
232+
// Proceed to answer or reject call as usual
233+
```
234+
235+
### [Java](#tab/java)
236+
```java
237+
AcsIncomingCallEventData incomingEvent = <incoming call event from Event Grid>;
238+
// Retrieve incoming call custom context
239+
AcsIncomingCallCustomContext callCustomContext = incomingEvent.getCustomContext();
240+
241+
// Inspect dictionary with key/value pairs
242+
Map<String, String> voipHeaders = callCustomContext.getVoipHeaders();
243+
Map<String, String> sipHeaders = callCustomContext.getSipHeaders();
244+
245+
// Proceed to answer or reject call as usual
246+
```
247+
248+
### [JavaScript](#tab/javascript)
249+
```javascript
250+
// Retrieve incoming call custom context
251+
const callCustomContext = incomingEvent.customContext;
252+
253+
// Inspect dictionary with key/value pairs
254+
const voipHeaders = callCustomContext.voipHeaders;
255+
const sipHeaders = callCustomContext.sipHeaders;
256+
257+
// Proceed to answer or reject call as usual
258+
```
259+
260+
### [Python](#tab/python)
261+
```python
262+
# Retrieve incoming call custom context
263+
callCustomContext = incomingEvent.customContext
264+
265+
# Inspect dictionary with key/value pairs
266+
voipHeaders = callCustomContext.voipHeaders
267+
sipHeaders = callCustomContext.sipHeaders
268+
```
269+
270+
-----
271+
## Additional resources
272+
273+
- For a sample payload of the incoming call, refer to this [guide](../../../event-grid/communication-services-voice-video-events.md#microsoftcommunicationincomingcall).
274+
275+
- Learn more about [SIP protocol details for direct routing](../../concepts/telephony/direct-routing-sip-specification.md).

articles/communication-services/toc.yml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -478,6 +478,8 @@ items:
478478
href: how-tos/call-automation/secure-webhook-endpoint.md
479479
- name: Handling Call Automation Events with EventProcessor
480480
href: how-tos/call-automation/handle-events-with-event-processor.md
481+
- name: How to pass call contextual data in Call Automation
482+
href: how-tos/call-automation/custom-context.md
481483
- name: Call recording
482484
items:
483485
- name: Record a call

articles/event-grid/communication-services-voice-video-events.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -263,6 +263,11 @@ This section contains an example of what that data would look like for each even
263263
},
264264
"serverCallId": "tob2JIV0wzOHdab3dWcGVWZmsrL2QxYVZnQ2U1bVVLQTh1T056YmpvdXdnQjNzZTlnTEhjNFlYem5BVU9nRGY5dUFQ",
265265
"callerDisplayName": "John Doe",
266+
"customContext": {
267+
"voipHeaders": {
268+
"voipHeaderName": "value"
269+
}
270+
},
266271
"incomingCallContext": "eyJhbGciOiJub25lIiwidHliSldUIn0.eyJjYyI6Ikg0c0lBQi9iT0JiOUs0SVhtQS9UMGhJbFVaUUlHQVBIc1J1M1RlbzgyNW4xcmtHJNa2hCNVVTQkNUbjFKTVo1NCt3ZDk1WFY0ZnNENUg0VDV2dk5VQ001NWxpRkpJb0pDUWlXS0F3OTJRSEVwUWo4aFFleDl4ZmxjRi9lMTlaODNEUmN6QUpvMVRWVXoxK1dWYm1lNW5zNmF5cFRyVGJ1KzMxU3FMY3E1SFhHWHZpc3FWd2kwcUJWSEhta0xjVFJEQ0hlSjNhdzA5MHE2T0pOaFNqS0pFdXpCcVdidzRoSmJGMGtxUkNaOFA4T3VUMTF0MzVHN0kvS0w3aVQyc09aS2F0NHQ2cFV5d0UwSUlEYm4wQStjcGtiVjlUK0E4SUhLZ2JKUjc1Vm8vZ0hFZGtRT3RCYXl1akc4cUt2U1dITFFCR3JFYjJNY3RuRVF0TEZQV1JEUzJHMDk3TGU5VnhhTktob2JIV0wzOHdab3dWcGVWZmsrL2QxYVZnQ2U1bVVLQTh1T056YmpvdXdnQjNzZTlnTEhjNFlYem5BVU9nRGY5dUFQMndsMXA0WU5nK1cySVRxSEtZUzJDV25IcEUySkhVZzd2UnVHOTBsZ081cU81MngvekR0OElYWHBFSi9peUxtNkdibmR1eEdZREozRXNWWXh4ZzZPd1hqc0pCUjZvR1U3NDIrYTR4M1RpQXFaV245UVIrMHNaVDg3YXpRQzbDNUR3BuZFhST1FTMVRTRzVVTkRGeU5UVjNORTFHU2kxck1UTk9VMUF0TWtWNVNreFRUVVI0YlMxRk1VdEVabnBRTjFsQ1EwWkVlVTQxZURCc1IyaHljVTVYTFROeWVTMVJNVjgyVFhrdGRFNUJZV3hrZW5SSVUwMTFVVE5GWkRKUkluMTlmUS5hMTZ0eXdzTDhuVHNPY1RWa2JnV3FPbTRncktHZmVMaC1KNjZUZXoza0JWQVJmYWYwOTRDWDFJSE5tUXRJeDN1TWk2aXZ3QXFFQWV1UlNGTjhlS3gzWV8yZXppZUN5WDlaSHp6Q1ZKemdZUVprc0RjYnprMGJoR09laWkydkpEMnlBMFdyUW1SeGFxOGZUM25EOUQ1Z1ZSUVczMGRheGQ5V001X1ZuNFNENmxtLVR5TUSVEifQ.",
267272
"correlationId": "d732db64-4803-462d-be9c-518943ea2b7a"
268273
},

0 commit comments

Comments
 (0)