Handling an Incoming MS Teams Call within your Application
Introduction
Integrating with Microsoft Teams can be a daunting task. Especially for things that aren't really covered using MS Graph or for which no easy to use SDK is made available. One of those things is handling an incoming Teams call (PSTN) for which you want to show caller information in your own application(s).
In such a case MS Graph isn't an option as it can take up to 15 minutes for you to be notified of an incoming call. By that time you probably already handled the call and got yourself a coffee..
Note: this article assumes you're interested in the "connected" -state of an incoming call (= picked up). If you're more interested in the "ringing" -state, you'll probably need to take the alternative approach as described at the end of the article.
After reading this post, you should have an understanding of how you can leverage incoming calls from Microsoft Teams and integrate with your own applications. Additionally, you should have all the fundamentals to handle different use-cases (e.g. redirect further to multiple different applications).
Flow
This is more or less what the flow would look like:
Someone dials a user having a Teams phone-number
At pickup/connect, Teams will start the conversation between the two parties. Additionally, it will open the URL specified as a Calling Policy.
A website is opened in a new browser-tab and immediately redirects to our protocol passing in the phone-number as the argument. This is how we pass the information to our client application for further handling. The user will receive a popup asking whether to accept sending the request to the custom protocol.
- After a certain delay, the website closes the opened browser-tab.
Windows will lookup the protocol-handler in the Windows Registry. The registered application will start and the argument passed along.
An application handles the argument(s) passed in according to your needs. Some use-cases might include:
Retrieve some information and display it on-screen
Decide on one-or-more parameters what application to trigger
The Components
So, let's build a fully working example based on the information mentioned above. We'll need:
To already have Microsoft Teams Phone functionality enabled
A website page we use from Microsoft Teams whenever a call comes in
- A redirect from this website page to trigger a custom-protocol
To have set some Microsoft Teams -settings
An application having registered this custom-protocol, handling the information passed along.
Enable Microsoft Teams Calling Functionality
Setting up Teams Phone within your organization is outside the scope of this blog post as it is too specific to each company's needs. More information can be found here: https://learn.microsoft.com/en-us/microsoftteams/setting-up-your-phone-system
A Redirect Website
This is a very simple static website having a single index.html
file to handle the redirect. The HTML for this page could look like the following:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Sample redirect page</title>
<base href="/" />
<script type="text/javascript">
function delay(time) {
return new Promise(resolve => setTimeout(resolve, time));
}
function redirectToApp() {
const urlParams = new URLSearchParams(window.location.search);
const callingNumber = urlParams.get('number');
window.location.href = `myapp:${callingNumber}`;
delay(30000).then(() => window.close());
}
</script>
</head>
<body onload="redirectToApp()">
<p>If you are not redirected, <a href="javascript:redirectToApp()">click here</a> to open the application.</p>
</body>
</html>
You can host this application as you like. In this blog I've used an Azure Storage Account to host the index.html
file. But feel free to use whatever suits your needs.
Additional Settings - MS Teams - Admin
Within MS Teams Admin Center we'll first configure the URL to open whenever an incoming call occurs. To manage this, go to your Teams Admin Center > Voice > Calling Policy and do the following:
Enable the "Open apps in browser for incoming PSTN calls" -checkbox
Provide the URL of the previously created "Redirect Website"
Link: https://learn.microsoft.com/en-us/microsoftteams/teams-calling-policy
Additional Settings - MS Teams - User
Additionally, we'll need to enable this for ourselves as well. Meaning, every user must also indicate in its settings whether or not to allow opening a website on pickup of an incoming call.
Go to Teams > Settings > Calls and make sure "Open apps in browser" is turned on.
Note: this option is only available if your logged-in user is registered as a Teams Phone User.
A demo-application handling the protocol
We'll create a simple demo application capable of
Registering the custom-protocol with Windows
Handling the incoming call by displaying the number of the caller
First we create a blank solution, create a new Console Application which we'll call "WindowsProtocol.Client" and attach it to the solution.
mkdir WindowsProtocol
cd WindowsProtocol
dotnet new sln -n WindowsProtocol
dotnet new console -n WindowsProtocol.Client
dotnet sln WindowsProtocol.sln add .\WindowsProtocol.Client\WindowsProtocol.csproj
Next, we'll host the application as an MSIX package.
In case you're wondering what it is and why we should use it: MSIX is a packaging format created by Microsoft that's used for distributing applications on Windows platforms. It's designed to be a modern replacement for traditional Windows Installer (MSI) and ClickOnce deployment methods, offering various improvements, features and extensions.
One of these is tnhe ability to register a windows.protocol. An example of such a protocol could be the tel
-protocol. But since this is typically already registered with Microsoft Teams, we don't want to mess that up. So let's use our own protocol called myapp
instead.
Once the application is installed and the protocol registered, we can easily trigger it from our web-browser by calling for example: myapp:12345
.
For this part we'll require a bit of Visual Studio 2022 to create the Windows Application Packaging Project as doing that from the command-line would take us a bit too far.
Open up the Solution file and search for the project template called "Windows Application Packaging Project".
Select "Next" and specify a name for the project. (eg. WindowsProtocol.Client.Package). Click <Create> to create the Package project.
Additionally, it will ask us what version of Windows we intend to target. Leave the default values for now and click <OK>.
Next, we need to link the Package Project with the actual application we intend to host within our MSIX package. Right-click on the (package) project dependencies and select "Add Project Reference".
Select our WindowsProtocol.Client
project from the list and make sure the checkbox is ticked.
Moving on we'll register the windows protocol we want to use with our app when we install the MSIX package.
First, right-click the Package.appxmanifest
file and select "View Code". Since we'll need to use an argument for passing in our caller's number, we'll need to add an additional XML namespace mapping at the top of the package.
Next, we add an extension to handle the registration of the windows protocol.
Alright, almost there. We only need to capture the argument in our Console application. You're program.cs
file should look something like the following.
internal class Program
{
static void Main(string[] args)
{
if (args.Length == 0)
Console.WriteLine("Hello, World!");
// Argument 0 = /inbound, Argument 1 = number passed in
if (args.Length > 0)
Console.WriteLine($"The world is calling from number {args[1]}!");
Console.WriteLine("Press <ANY> key to continue.");
Console.ReadLine();
}
}
Argument 0 : '/inbound' as specified in our application manifest
Argument 1 : the calling-number value
Final Touch - Microsoft Edge
Since we are asking Teams to open a URL on our behalf, which in turn tries to open a protocol-handler, Microsoft Edge (or other Chromium -based browser) will ask if this is really an action we want to perform and require a user-gesture in order to execute the action.
This is a bit annoying as it disrupts our automated flow, but luckily there is a way around this (well at least for Edge). By adding an additional policy to Edge we can specify which protocols to auto-accept and execute.
To add a Policy to Microsoft Edge you can either use the Group Policy Editor, or directly in the registry. It should look something like this:
Testing the Solution
Make sure you have been assigned a Microsoft Teams phone-number
Start your application (MSIX) to register the application protocol
Call the phone-number assigned to you
Your Microsoft Edge browser should open asking you permission to use the application protocol
Click <Open>
Your application should start and display the caller number
Remarks
Within MS Teams, the URL will only be opened for an actual phone number. An internal number (e.g. between colleagues), or an anonymous number will not trigger the action.
Alternative
If the above approach is for some reason not usable, say, for example, you want to trigger some action on the "ringing" -state of an incoming call, then you could consider using Teams Wizard from LyncWizard. Teams Wizard is a free tool that extends Microsoft Teams with an additional feature called "Execute actions".
Whenever an incoming call occurs the application could execute a command or open an URL with the phone number as argument. It supports two events:
Incoming call: triggered on an incoming call
On-the-phone: triggered by presence state "On-the-phone", occurs for incoming or outgoing calls.
Subscribe to my newsletter
Read articles from Kristof Van Hees directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by