-
Notifications
You must be signed in to change notification settings - Fork 18
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Check in OfflinePlayReadyAndWidevine (#28)
- Loading branch information
Showing
12 changed files
with
1,433 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,89 @@ | ||
--- | ||
topic: sample | ||
languages: | ||
- java | ||
products: | ||
- azure-media-services | ||
--- | ||
|
||
# Offline playback with PlayReady and Widevine DRM | ||
|
||
This sample demonstrates how to dynamically encrypt your content with PlayReady and Widevine DRM and play the content without requesting a license from license service. It shows how to perform the following tasks: | ||
|
||
1. Creates a transform with built-in AdaptiveStreaming preset | ||
1. Submits a job | ||
1. Creates a ContentKeyPolicy with open restriction and PlayReady/Widevine persistent configuration | ||
1. Associates the ContentKeyPolicy with a StreamingLocator | ||
1. Prints a url for playback | ||
|
||
When a user requests PlayReady or Widevine protected content for the first time, the player application requests a license from the Media Services license service. If the player application is authorized, the Media Services license service issues a license to the player and the license is persisted. Because the license is persisted, subsequent playback won't send a request to Media Services license service again. | ||
|
||
> [!TIP] | ||
> The `OfflinePlayReadyAndWidevine.java` file has extensive comments. | ||
## Prerequisites | ||
|
||
* Java JDK 1.8 or newer installed | ||
* Maven installed | ||
* An Azure Media Services account. See the steps described in [Create a Media Services account](https://docs.microsoft.com/azure/media-services/latest/create-account-cli-quickstart). | ||
|
||
## Running the example | ||
|
||
### Configure `appsettings.json` with appropriate access values | ||
|
||
Get credentials needed to use Media Services APIs by following [Access APIs](https://docs.microsoft.com/azure/media-services/latest/access-api-cli-how-to). Open the `src/main/resources/conf/appsettings.json` configuration file and paste the values in the file. | ||
|
||
### Clean and build the project | ||
|
||
Open a terminal window, go to the root folder of this project, run `mvn clean compile`. | ||
|
||
### Run this project | ||
|
||
Execute `mvn exec:java`, then follow the instructions in the output console. | ||
|
||
### Optional, do the following steps if you want to use Event Grid for job monitoring | ||
|
||
Please note, there are costs for using Event Hub. For more details, refer [Event Hubs pricing](https://azure.microsoft.com/en-in/pricing/details/event-hubs/) and [FAQ](https://docs.microsoft.com/en-us/azure/event-hubs/event-hubs-faq#pricing) | ||
|
||
* Enable Event Grid resource provider | ||
|
||
`az provider register --namespace Microsoft.EventGrid` | ||
|
||
* To check if registered, run the next command. You should see "Registered" | ||
|
||
`az provider show --namespace Microsoft.EventGrid --query "registrationState"` | ||
|
||
* Create an Event Hub | ||
|
||
`namespace=<unique-namespace-name>`\ | ||
`hubname=<event-hub-name>`\ | ||
`az eventhubs namespace create --name $namespace --resource-group <resource-group>`\ | ||
`az eventhubs eventhub create --name $hubname --namespace-name $namespace --resource-group <resource-group>` | ||
|
||
* Subscribe to Media Services events | ||
|
||
`hubid=$(az eventhubs eventhub show --name $hubname --namespace-name $namespace --resource-group <resource-group> --query id --output tsv)`\ | ||
`amsResourceId=$(az ams account show --name <ams-account> --resource-group <resource-group> --query id --output tsv)`\ | ||
`az eventgrid event-subscription create --resource-id $amsResourceId --name <event-subscription-name> --endpoint-type eventhub --endpoint $hubid` | ||
|
||
* Create a storage account and container for Event Processor Host if you don't have one | ||
[Create a storage account for Event Processor Host | ||
](https://docs.microsoft.com/en-us/azure/event-hubs/event-hubs-dotnet-standard-getstarted-send#create-a-storage-account-for-event-processor-host) | ||
|
||
* Update appsettings.json with your Event Hub and Storage information | ||
StorageAccountName: The name of your storage account.\ | ||
StorageAccountKey: The access key for your storage account. Navigate to Azure portal, "All resources", search your storage account, then "Access keys", copy key1.\ | ||
StorageContainerName: The name of your container. Click Blobs in your storage account, find you container and copy the name.\ | ||
EventHubConnectionString: The Event Hub connection string. search your namespace you just created. <your namespace> -> Shared access policies -> RootManageSharedAccessKey -> Connection string-primary key.\ | ||
EventHubName: The Event Hub name. <your namespace> -> Event Hubs. | ||
|
||
## Key concepts | ||
|
||
* [Dynamic packaging](https://docs.microsoft.com/azure/media-services/latest/dynamic-packaging-overview) | ||
* [Content protection with dynamic encryption](https://docs.microsoft.com/azure/media-services/latest/content-protection-overview) | ||
* [Streaming Policies](https://docs.microsoft.com/azure/media-services/latest/streaming-policy-concept) | ||
|
||
## Next steps | ||
|
||
* [Azure Media Services pricing](https://azure.microsoft.com/pricing/details/media-services/) | ||
* [Azure Media Services v3 Documentation](https://docs.microsoft.com/azure/media-services/latest/) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,108 @@ | ||
<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/maven-v4_0_0.xsd"> | ||
<modelVersion>4.0.0</modelVersion> | ||
<groupId>sample</groupId> | ||
<artifactId>OfflinePlayReadyAndWidevine</artifactId> | ||
<packaging>jar</packaging> | ||
<version>1.0-SNAPSHOT</version> | ||
<name>OfflinePlayReadyAndWidevine</name> | ||
<url>http://maven.apache.org</url> | ||
<dependencies> | ||
<dependency> | ||
<groupId>com.googlecode.json-simple</groupId> | ||
<artifactId>json-simple</artifactId> | ||
<version>1.1.1</version> | ||
</dependency> | ||
<dependency> | ||
<groupId>com.microsoft.azure.mediaservices.v2018_07_01</groupId> | ||
<artifactId>azure-mgmt-media</artifactId> | ||
<version>1.0.0-beta-4</version> | ||
</dependency> | ||
<dependency> | ||
<groupId>com.microsoft.rest</groupId> | ||
<artifactId>client-runtime</artifactId> | ||
<version>1.6.8</version> | ||
</dependency> | ||
<dependency> | ||
<groupId>com.microsoft.azure</groupId> | ||
<artifactId>azure-client-authentication</artifactId> | ||
<version>1.6.8</version> | ||
</dependency> | ||
<dependency> | ||
<groupId>com.microsoft.azure</groupId> | ||
<artifactId>azure-arm-client-runtime</artifactId> | ||
<version>1.6.8</version> | ||
</dependency> | ||
<dependency> | ||
<groupId>com.microsoft.azure</groupId> | ||
<artifactId>azure-client-runtime</artifactId> | ||
<version>1.6.8</version> | ||
</dependency> | ||
<dependency> | ||
<groupId>com.fasterxml.jackson.core</groupId> | ||
<artifactId>jackson-core</artifactId> | ||
<version>2.9.4</version> | ||
</dependency> | ||
<dependency> | ||
<groupId>com.fasterxml.jackson.core</groupId> | ||
<artifactId>jackson-annotations</artifactId> | ||
<version>2.9.0</version> | ||
</dependency> | ||
<dependency> | ||
<groupId>io.jsonwebtoken</groupId> | ||
<artifactId>jjwt-api</artifactId> | ||
<version>0.10.5</version> | ||
</dependency> | ||
<dependency> | ||
<groupId>com.microsoft.azure</groupId> | ||
<artifactId>azure-storage-blob</artifactId> | ||
<version>11.0.1</version> | ||
</dependency> | ||
<dependency> | ||
<groupId>com.microsoft.azure</groupId> | ||
<artifactId>azure-eventhubs</artifactId> | ||
<version>2.3.2</version> | ||
</dependency> | ||
<dependency> | ||
<groupId>com.microsoft.azure</groupId> | ||
<artifactId>azure-eventhubs-eph</artifactId> | ||
<version>2.5.2</version> | ||
</dependency> | ||
<dependency> | ||
<groupId>org.slf4j</groupId> | ||
<artifactId>slf4j-api</artifactId> | ||
<version>1.7.5</version> | ||
</dependency> | ||
<dependency> | ||
<groupId>org.slf4j</groupId> | ||
<artifactId>slf4j-log4j12</artifactId> | ||
<version>1.7.5</version> | ||
</dependency> | ||
<dependency> | ||
<groupId>com.fasterxml.jackson.core</groupId> | ||
<artifactId>jackson-databind</artifactId> | ||
<version>2.9.9.3</version> | ||
</dependency> | ||
</dependencies> | ||
<build> | ||
<plugins> | ||
<plugin> | ||
<groupId>org.apache.maven.plugins</groupId> | ||
<artifactId>maven-compiler-plugin</artifactId> | ||
<version>3.8.1</version> | ||
<configuration> | ||
<source>1.8</source> | ||
<target>1.8</target> | ||
</configuration> | ||
</plugin> | ||
<plugin> | ||
<groupId>org.codehaus.mojo</groupId> | ||
<artifactId>exec-maven-plugin</artifactId> | ||
<version>1.4.0</version> | ||
<configuration> | ||
<mainClass>sample.OfflinePlayReadyAndWidevine</mainClass> | ||
</configuration> | ||
</plugin> | ||
</plugins> | ||
</build> | ||
</project> |
133 changes: 133 additions & 0 deletions
133
ContentProtection/OfflinePlayReadyAndWidevine/src/main/java/sample/ConfigWrapper.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,133 @@ | ||
// Copyright (c) Microsoft Corporation. All rights reserved. | ||
// Licensed under the MIT License. | ||
|
||
package sample; | ||
|
||
import java.io.IOException; | ||
import java.io.InputStream; | ||
import java.io.InputStreamReader; | ||
import org.json.simple.JSONObject; | ||
import org.json.simple.parser.JSONParser; | ||
|
||
/** | ||
* This class reads values from local configuration file resources/conf/appsettings.json | ||
* Please change the configuration using your account information. For more information, see | ||
* https://docs.microsoft.com/azure/media-services/latest/access-api-cli-how-to. For security | ||
* reasons, do not check in the configuration file to source control. | ||
*/ | ||
public class ConfigWrapper { | ||
private static final String AAD_CLIENT_ID = "AadClientId"; | ||
private static final String AAD_ENDPOINT = "AadEndpoint"; | ||
private static final String AAD_SECRET = "AadSecret"; | ||
private static final String AAD_TENANT_ID = "AadTenantId"; | ||
private static final String ACCOUNT_NAME = "AccountName"; | ||
private static final String ARM_AAD_AUDIENCE = "ArmAadAudience"; | ||
private static final String ARM_ENDPOINT = "ArmEndpoint"; | ||
private static final String REGION = "Region"; | ||
private static final String RESOURCE_GROUP = "ResourceGroup"; | ||
private static final String SUBSCRIPTION_ID = "SubscriptionId"; | ||
private static final String SYMMETRIC_KEY = "SymmetricKey"; | ||
private static final String NAMESPACE_NAME = "NamespaceName"; | ||
private static final String EVENT_HUB_CONNECTION_STRING = "EventHubConnectionString"; | ||
private static final String EVENT_HUB_NAME = "EventHubName"; | ||
private static final String STORAGE_CONTAINER_NAME = "StorageContainerName"; | ||
private static final String STORAGE_ACCOUNT_NAME = "StorageAccountName"; | ||
private static final String STORAGE_ACCOUNT_KEY = "StorageAccountKey"; | ||
private static final String CONF_JSON = "conf/appsettings.json"; | ||
private final JSONObject jsonObject; | ||
private final InputStreamReader isReader; | ||
|
||
public ConfigWrapper() { | ||
InputStream inStream = ConfigWrapper.class.getClassLoader().getResourceAsStream(CONF_JSON); | ||
isReader = new InputStreamReader(inStream); | ||
|
||
JSONParser parser = new JSONParser(); | ||
Object obj = null; | ||
try { | ||
obj = parser.parse(isReader); | ||
} catch (Exception ioe) { | ||
System.err.println(ioe); | ||
System.exit(1); | ||
} | ||
|
||
jsonObject = (JSONObject) obj; | ||
} | ||
|
||
public void close() { | ||
try { | ||
if (isReader != null) { | ||
isReader.close(); | ||
} | ||
} catch (IOException e) { | ||
e.printStackTrace(); | ||
} | ||
} | ||
|
||
public String getAadClientId() { | ||
return (String)jsonObject.get(AAD_CLIENT_ID); | ||
} | ||
|
||
public String getAadEndpoint() { | ||
return (String)jsonObject.get(AAD_ENDPOINT); | ||
} | ||
|
||
public String getAadSecret() { | ||
return (String)jsonObject.get(AAD_SECRET); | ||
} | ||
|
||
public String getAadTenantId() { | ||
return (String)jsonObject.get(AAD_TENANT_ID); | ||
} | ||
|
||
public String getAccountName() { | ||
return (String)jsonObject.get(ACCOUNT_NAME); | ||
} | ||
|
||
public String getArmAadAudience() { | ||
return (String)jsonObject.get(ARM_AAD_AUDIENCE); | ||
} | ||
|
||
public String getArmEndpoint() { | ||
return (String)jsonObject.get(ARM_ENDPOINT); | ||
} | ||
|
||
public String getRegion() { | ||
return (String)jsonObject.get(REGION); | ||
} | ||
|
||
public String getResourceGroup() { | ||
return (String)jsonObject.get(RESOURCE_GROUP); | ||
} | ||
|
||
public String getSubscriptionId() { | ||
return (String)jsonObject.get(SUBSCRIPTION_ID); | ||
} | ||
|
||
public String getSymmetricKey() { | ||
return (String)jsonObject.get(SYMMETRIC_KEY); | ||
} | ||
|
||
public String getNamespaceName() { | ||
return (String)jsonObject.get(NAMESPACE_NAME); | ||
} | ||
|
||
public String getEventHubConnectionString() { | ||
return (String)jsonObject.get(EVENT_HUB_CONNECTION_STRING); | ||
} | ||
|
||
public String getEventHubName() { | ||
return (String)jsonObject.get(EVENT_HUB_NAME); | ||
} | ||
|
||
public String getStorageContainerName() { | ||
return (String)jsonObject.get(STORAGE_CONTAINER_NAME); | ||
} | ||
|
||
public String getStorageAccountName() { | ||
return (String)jsonObject.get(STORAGE_ACCOUNT_NAME); | ||
} | ||
|
||
public String getStorageAccountKey() { | ||
return (String)jsonObject.get(STORAGE_ACCOUNT_KEY); | ||
} | ||
} |
41 changes: 41 additions & 0 deletions
41
ContentProtection/OfflinePlayReadyAndWidevine/src/main/java/sample/ContentKeySpec.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,41 @@ | ||
// Copyright (c) Microsoft Corporation. All rights reserved. | ||
// Licensed under the MIT License. | ||
|
||
package sample; | ||
|
||
import com.fasterxml.jackson.annotation.JsonProperty; | ||
|
||
public class ContentKeySpec { | ||
@JsonProperty("TrackType") | ||
private String trackType; | ||
|
||
@JsonProperty("SecurityLevel") | ||
private int securityLevel; | ||
|
||
@JsonProperty("RequiredOutputProtection") | ||
private OutputProtection requiredOutputProtection; | ||
|
||
public String getTrackType() { | ||
return trackType; | ||
} | ||
|
||
public void setTrackType(String trackType) { | ||
this.trackType = trackType; | ||
} | ||
|
||
public int getSecurityLevel() { | ||
return securityLevel; | ||
} | ||
|
||
public void setSecurityLevel(int securityLevel) { | ||
this.securityLevel = securityLevel; | ||
} | ||
|
||
public OutputProtection getRequiredOutputProtection() { | ||
return requiredOutputProtection; | ||
} | ||
|
||
public void setRequiredOutputProtection(OutputProtection requiredOutputProtection) { | ||
this.requiredOutputProtection = requiredOutputProtection; | ||
} | ||
} |
Oops, something went wrong.