Skip to content
Open
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
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
157 changes: 157 additions & 0 deletions CallAutomation_MediaStreaming/pom.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,157 @@
<?xml version="1.0" encoding="UTF-8"?>

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>

<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.4.4</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>

<groupId>com.communication.MediaStreaming</groupId>
<artifactId>MediaStreaming</artifactId>
<version>1.0-SNAPSHOT</version>

<name>MediaStreaming</name>
<!-- FIXME change it to the project's website -->
<url>http://www.example.com</url>

<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>11</maven.compiler.source>
<maven.compiler.target>11</maven.compiler.target>
</properties>

<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.11</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
<version>4.5.13</version>
</dependency>
<dependency>
<groupId>com.azure</groupId>
<artifactId>azure-core</artifactId>
<version>1.31.0</version>
</dependency>
<dependency>
<groupId>com.azure</groupId>
<artifactId>azure-identity</artifactId>
<version>1.5.4</version>
</dependency>
<dependency>
<groupId>com.azure</groupId>
<artifactId>azure-communication-identity</artifactId>
<version>1.3.0</version>
</dependency>
<dependency>
<groupId>com.azure</groupId>
<artifactId>azure-communication-callautomation</artifactId>
<version>1.0.0-alpha.20221007.2</version>
</dependency>
<dependency>
<groupId>com.microsoft.cognitiveservices.speech</groupId>
<artifactId>client-sdk</artifactId>
<version>1.23.0</version>
</dependency>
<dependency>
<groupId>com.azure</groupId>
<artifactId>azure-messaging-eventgrid</artifactId>
<version>4.12.1</version>
</dependency>
<dependency>
<groupId>com.azure</groupId>
<artifactId>azure-cosmos</artifactId>
<version>4.34.0</version>
</dependency>
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
<version>2.10</version>
</dependency>
</dependencies>

<repositories>
<repository>
<id>azure-sdk-for-java</id>
<url>https://pkgs.dev.azure.com/azure-sdk/public/_packaging/azure-sdk-for-java/maven/v1</url>
<releases>
<enabled>true</enabled>
</releases>
<snapshots>
<enabled>true</enabled>
</snapshots>
</repository>
</repositories>

<build>
<pluginManagement>
<plugins>
<plugin>
<artifactId>maven-clean-plugin</artifactId>
<version>3.1.0</version>
</plugin>
<plugin>
<artifactId>maven-resources-plugin</artifactId>
<version>3.0.2</version>
</plugin>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.0</version>
</plugin>
<plugin>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.22.1</version>
</plugin>
<plugin>
<artifactId>maven-jar-plugin</artifactId>
<version>3.0.2</version>
</plugin>
<plugin>
<artifactId>maven-deploy-plugin</artifactId>
<version>2.8.2</version>
</plugin>
<plugin>
<artifactId>maven-site-plugin</artifactId>
<version>3.7.1</version>
</plugin>
<plugin>
<artifactId>maven-project-info-reports-plugin</artifactId>
<version>3.0.0</version>
</plugin>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>exec-maven-plugin</artifactId>
<version>3.0.0</version>
<executions>
<execution>
<goals>
<goal>java</goal>
</goals>
</execution>
</executions>
<configuration>
<mainClass>com.communication.MediaStreaming.App</mainClass>
</configuration>
</plugin>
</plugins>
</pluginManagement>
</build>
</project>
79 changes: 79 additions & 0 deletions CallAutomation_MediaStreaming/readme.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
---
page_type: sample
languages:
- java
products:
- azure
- azure-communication-services
---

# Incoming call Media Streaming Sample

Get started with audio media streaming, through Azure Communication Services Call Automation SDK.
This QuickStart assumes you’ve already used the calling automation APIs to build an automated call routing solution, please refer [Call Automation IVR Sample](https://github.com/Azure-Samples/communication-services-java-quickstarts/tree/main/CallAutomation_SimpleIvr).

In this sample a WebApp receives an incoming call request whenever a call is made to a Communication Service acquired phone number or a communication identifier.
API first answers the call with Media Streaming options settings. Once call connected, external PSTN user say something.
The audio is streamed to WebSocket server and generates log events to show media streaming is happening on the server.
It supports Audio streaming only (mixed/unmixed format).

This sample has 3 parts:

1. ACS Resource IncomingCall Hook Settings, and ACS acquired Phone Number.
2. IncomingCall WebApp - for accepting the incoming call with Media Options settings.
3. WebSocketListener – Listen to media stream on websocket.

The application is a console-based application build on Java development kit(JDK) 11.

## Getting started

### Prerequisites

- Create an Azure account with an active subscription. For details, see [Create an account for free](https://azure.microsoft.com/free/)
- [Java Development Kit (JDK) version 11 or above](https://docs.microsoft.com/azure/developer/java/fundamentals/java-jdk-install)
- [Apache Maven](https://maven.apache.org/download.cgi)
- 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'll need to record your resource **connection string** for this sample.
- [Configuring the webhook](https://docs.microsoft.com/en-us/azure/devops/service-hooks/services/webhooks?view=azure-devops) for **Microsoft.Communication.IncomingCall** event.
- Download and install [Ngrok](https://www.ngrok.com/download). As the sample is run locally, Ngrok will enable the receiving of all the events.

## 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'd like to clone the sample to.
2. git clone https://github.com/Azure-Samples/Communication-Services-java-quickstarts.git.

### Locally running the media streaming WebSocket app
and update below configurations.
1. Navigate to IncomingCallMediaStreaming, look for the file at /src/main/java/com/communication/IncomingCallMediaStreaming/WebSocket/App.java
2. Run the `WebSocket/App.java` for listening media stream on websocket.
3. Run ngrok using command `ngrok http 8080 --host-header="localhost:8080"`
3. Use the ngrok-URL, as a websocket URL needed for `MediaStreamingTransportURI` configuration.

### Publish the Incoming call media streaming to Azure WebApp
1.
2.
3. After publishing, add the following configurations on azure portal (under app service's configuration section).

- Connectionstring: Azure Communication Service resource's connection string.
- AppCallBackUri: URI of the deployed app service.
- SecretPlaceholder: Query string for callback URL.
- MediaStreamingTransportURI: websocket URL got from `WebSocketListener`, format "wss://{ngrokr-url}",(Notice the url, it should wss:// and not https://).

### Create Webhook for incoming call event

IncomingCall is an Azure Event Grid event for notifying incoming calls to your Communication Services resource. To learn more about it, see [this guide](https://learn.microsoft.com/en-us/azure/communication-services/concepts/call-automation/incoming-call-notification).
1. Navigate to your resource on Azure portal and select `Events` from the left side menu.

2. Select `+ Event Subscription` to create a new subscription.
3. Filter for Incoming Call event.
4. Choose endpoint type as web hook and provide the public url generated for your application by ngrok. Make sure to provide the exact api route that you programmed to receive the event previously. In this case, it would be <ngrok_url>/api/incomingCall.

![Screenshot of portal page to create a new event subscription.](./media/EventgridSubscription-IncomingCall.png)

5. Select create to start the creation of subscription and validation of your endpoint as mentioned previously. The subscription is ready when the provisioning status is marked as succeeded.

### Run the Application

- Navigate to the directory containing the pom.xml file and use the following mvn commands:
- Compile the application: mvn compile
- Build the package: mvn package
- Execute the app: mvn exec:java
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.

package com.communication.MediaStreaming;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class App {

public static void main(String[] args) {
SpringApplication.run(App.class, args);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
package com.communication.MediaStreaming;

import com.communication.MediaStreaming.EventHandler.EventAuthHandler;

public class CallConfiguration {

public String connectionString;
public String appBaseUrl;
public String appCallbackUrl;
public String acceptCallsFrom;
public String mediaStreamingTransportURI;

public CallConfiguration(
String connectionString,
String appBaseUrl,
String acceptCallsFrom,
String mediaStreamingTransportURI
) {
this.connectionString = connectionString;
this.appBaseUrl = appBaseUrl;
EventAuthHandler eventhandler = EventAuthHandler.getInstance();
this.appCallbackUrl =
appBaseUrl +
"/api/IncomingCallMediaStreaming/callback?" +
eventhandler.getSecretQuerystring();
this.acceptCallsFrom = acceptCallsFrom;
this.mediaStreamingTransportURI = mediaStreamingTransportURI;
}

public static CallConfiguration initiateConfiguration() {
ConfigurationManager configurationManager = ConfigurationManager.getInstance();
configurationManager.loadAppSettings();
String connectionString = configurationManager.getAppSettings(
"Connectionstring"
);
String acceptCallsFrom = configurationManager.getAppSettings(
"AcceptCallsFrom"
);
String mediaStreamingTransportURI = configurationManager.getAppSettings(
"MediaStreamingTransportURI"
);
String appBaseUrl = configurationManager.getAppSettings("AppCallBackUri");
return new CallConfiguration(
connectionString,
appBaseUrl,
acceptCallsFrom,
mediaStreamingTransportURI
);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
package com.communication.MediaStreaming;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.util.Properties;

public class ConfigurationManager {

private static ConfigurationManager configurationManager = null;
private final Properties appSettings = new Properties();

private ConfigurationManager() {}

// static method to create instance of ConfigurationManager class
public static ConfigurationManager getInstance() {
if (configurationManager == null) {
configurationManager = new ConfigurationManager();
}
return configurationManager;
}

public void loadAppSettings() {
try {
File configFile = new File(
"src/main/java/com/communication/MediaStreaming/config.properties"
);
FileReader reader = new FileReader(configFile);
appSettings.load(reader);
reader.close();
} catch (FileNotFoundException ex) {
Logger.logMessage(
Logger.MessageType.INFORMATION,
"Loading app settings failed with error -- > " + ex.getMessage()
);
} catch (IOException ex) {
Logger.logMessage(
Logger.MessageType.ERROR,
"Loading app settings failed with error -- > " + ex.getMessage()
);
}
}

public String getAppSettings(String key) {
if (!key.isEmpty()) {
return appSettings.getProperty(key);
}
return "";
}
}
Loading