Java tutorial
package com.microsoft.windowsazure.services.media.samples.contentprotection.playreadywidevine; import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; import com.microsoft.windowsazure.Configuration; import com.microsoft.windowsazure.core.utils.Base64; import com.microsoft.windowsazure.exception.ServiceException; import com.microsoft.windowsazure.services.media.*; import com.microsoft.windowsazure.services.media.implementation.templates.playreadylicense.*; import com.microsoft.windowsazure.services.media.implementation.templates.tokenrestriction.*; import com.microsoft.windowsazure.services.media.implementation.templates.widevine.*; import com.microsoft.windowsazure.services.media.models.*; import com.microsoft.windowsazure.services.media.models.ContentKeyAuthorizationPolicyRestriction.ContentKeyRestrictionType; import javax.xml.bind.JAXBException; import java.io.*; import java.net.URI; import java.security.NoSuchAlgorithmException; import java.security.cert.CertificateFactory; import java.security.cert.X509Certificate; import java.util.*; public final class Program { private static MediaContract mediaService; // Media Services account credentials configuration private static String mediaServiceUri = "https://media.windows.net/API/"; private static String oAuthUri = "https://wamsprodglobal001acs.accesscontrol.windows.net/v2/OAuth2-13"; private static String clientId = "%media-services-account-name%"; private static String clientSecret = "%media-services-account-key%"; private static String scope = "urn:WindowsAzureMediaServices"; // Encoder configuration private static String preferedEncoder = "Media Encoder Standard"; private static String encodingPreset = "H264 Multiple Bitrate 720p"; // Content Key Authorization Policy Token Restriction configuration private static boolean tokenRestriction = true; // true: use token restriction policy; // false: use open private static TokenType tokenType = TokenType.JWT; // Utility classes should not have a public or default constructor private Program() { } public static void main(String[] args) { try { // Set up the MediaContract object to call into the Media Services account Configuration configuration = MediaConfiguration.configureWithOAuthAuthentication(mediaServiceUri, oAuthUri, clientId, clientSecret, scope); mediaService = MediaService.create(configuration); System.out.println("Azure SDK for Java - PlayReady & Widevine Dynamic Encryption Sample"); // Upload a local file to a media asset. AssetInfo uploadAsset = uploadFileAndCreateAsset("Azure-Video.wmv"); System.out.println("Uploaded Asset Id: " + uploadAsset.getId()); // Transform the asset. AssetInfo encodedAsset = encode(uploadAsset); System.out.println("Encoded Asset Id: " + encodedAsset.getId()); // Create the ContentKey ContentKeyInfo contentKeyInfo = createCommonTypeContentKey(encodedAsset); System.out.println("Common Encryption Content Key: " + contentKeyInfo.getId()); // Create the ContentKeyAuthorizationPolicy String tokenTemplateString = null; if (tokenRestriction) { tokenTemplateString = addTokenRestrictedAuthorizationPolicy(contentKeyInfo, tokenType); } else { addOpenAuthorizationPolicy(contentKeyInfo); } // Create the AssetDeliveryPolicy createAssetDeliveryPolicy(encodedAsset, contentKeyInfo); if (tokenTemplateString != null) { // Deserializes a string containing the XML representation of the TokenRestrictionTemplate TokenRestrictionTemplate tokenTemplate = TokenRestrictionTemplateSerializer .deserialize(tokenTemplateString); // Generate a test token based on the the data in the given // TokenRestrictionTemplate. // Note: You need to pass the key id Guid because we specified // TokenClaim.ContentKeyIdentifierClaim in during the creation // of TokenRestrictionTemplate. UUID rawKey = UUID.fromString(contentKeyInfo.getId().substring("nb:kid:UUID:".length())); // Token expiration: 1-year Calendar date = Calendar.getInstance(); date.setTime(new Date()); date.add(Calendar.YEAR, 1); // Generate token String testToken = TokenRestrictionTemplateSerializer.generateTestToken(tokenTemplate, null, rawKey, date.getTime(), null); System.out.println(tokenTemplate.getTokenType().toString() + " Test Token: Bearer " + testToken); } // Create the Streaming Origin Locator String url = getStreamingOriginLocator(encodedAsset); System.out.println("Origin Locator Url: " + url); System.out.println("Sample completed!"); } catch (ServiceException se) { System.out.println("ServiceException encountered."); System.out.println(se.toString()); } catch (Exception e) { System.out.println("Exception encountered."); System.out.println(e.toString()); } } // Upload a media file to your Media Services account. // This code creates an Asset, an AccessPolicy (using Write access) and a // Locator, and uses those objects to upload a local file. private static AssetInfo uploadFileAndCreateAsset(String fileName) throws ServiceException, FileNotFoundException, NoSuchAlgorithmException { WritableBlobContainerContract uploader; AssetInfo resultAsset; AccessPolicyInfo uploadAccessPolicy; LocatorInfo uploadLocator = null; // Create an Asset resultAsset = mediaService.create(Asset.create().setName(fileName).setAlternateId("altId")); System.out.println("Created Asset " + fileName); // Create an AccessPolicy that provides Write access for 15 minutes uploadAccessPolicy = mediaService .create(AccessPolicy.create("uploadAccessPolicy", 15.0, EnumSet.of(AccessPolicyPermission.WRITE))); // Create a Locator using the AccessPolicy and Asset uploadLocator = mediaService .create(Locator.create(uploadAccessPolicy.getId(), resultAsset.getId(), LocatorType.SAS)); // Create the Blob Writer using the Locator uploader = mediaService.createBlobWriter(uploadLocator); // The local file that will be uploaded to your Media Services account InputStream input = new FileInputStream( new File(Program.class.getClassLoader().getResource("").getPath() + fileName)); System.out.println("Uploading " + fileName); // Upload the local file to the asset uploader.createBlockBlob(fileName, input); // Inform Media Services about the uploaded files mediaService.action(AssetFile.createFileInfos(resultAsset.getId())); System.out.println("Uploaded Asset File " + fileName); mediaService.delete(Locator.delete(uploadLocator.getId())); mediaService.delete(AccessPolicy.delete(uploadAccessPolicy.getId())); return resultAsset; } // Create a Job that contains a Task to transform the Asset private static AssetInfo encode(AssetInfo assetToEncode) throws ServiceException, InterruptedException { // Retrieve the list of Media Processors that match the name ListResult<MediaProcessorInfo> mediaProcessors = mediaService .list(MediaProcessor.list().set("$filter", String.format("Name eq '%s'", preferedEncoder))); // Use the latest version of the Media Processor MediaProcessorInfo mediaProcessor = null; for (MediaProcessorInfo info : mediaProcessors) { if (null == mediaProcessor || info.getVersion().compareTo(mediaProcessor.getVersion()) > 0) { mediaProcessor = info; } } System.out .println("Using Media Processor: " + mediaProcessor.getName() + " " + mediaProcessor.getVersion()); // Create a task with the specified Media Processor String outputAssetName = String.format("%s as %s", assetToEncode.getName(), encodingPreset); String taskXml = "<taskBody><inputAsset>JobInputAsset(0)</inputAsset>" + "<outputAsset assetCreationOptions=\"0\"" // AssetCreationOptions.None + " assetName=\"" + outputAssetName + "\">JobOutputAsset(0)</outputAsset></taskBody>"; Task.CreateBatchOperation task = Task.create(mediaProcessor.getId(), taskXml) .setConfiguration(encodingPreset).setName("Encoding"); /// Create the Job; this automatically schedules and runs it. Job.Creator jobCreator = Job.create() .setName(String.format("Encoding %s to %s", assetToEncode.getName(), encodingPreset)) .addInputMediaAsset(assetToEncode.getId()).setPriority(2).addTaskCreator(task); JobInfo job = mediaService.create(jobCreator); String jobId = job.getId(); System.out.println("Created Job with Id: " + jobId); // Check to see if the Job has completed checkJobStatus(jobId); // Done with the Job // Retrieve the output Asset ListResult<AssetInfo> outputAssets = mediaService.list(Asset.list(job.getOutputAssetsLink())); return outputAssets.get(0); } public static ContentKeyInfo createCommonTypeContentKey(AssetInfo asset) { try { // Get the protection key id for ContentKey String protectionKeyId = mediaService .action(ProtectionKey.getProtectionKeyId(ContentKeyType.CommonEncryption)); // Download and create the X509 certificate String protectionKey = mediaService.action(ProtectionKey.getProtectionKey(protectionKeyId)); X509Certificate certificate = (X509Certificate) CertificateFactory.getInstance("X.509") .generateCertificate(new ByteArrayInputStream(Base64.decode(protectionKey))); // Create a new ContentKey (secure random) byte[] contentKeyData = new byte[16]; EncryptionUtils.eraseKey(contentKeyData); // Encrypt ContentKey byte[] encryptedContentKey = EncryptionUtils.encryptSymmetricKeyData(certificate, contentKeyData); String encryptedContentKeyString = Base64.encode(encryptedContentKey); // Create the ContentKey Id UUID contentKeyIdUuid = UUID.randomUUID(); String contentKeyId = String.format("nb:kid:UUID:%s", contentKeyIdUuid.toString()); // Calculate the checksum String checksum = EncryptionUtils.calculateChecksum(contentKeyData, contentKeyIdUuid); // Create the ContentKey entity ContentKeyInfo contentKey = mediaService.create( ContentKey.create(contentKeyId, ContentKeyType.CommonEncryption, encryptedContentKeyString) .setChecksum(checksum).setProtectionKeyType(ProtectionKeyType.X509CertificateThumbprint) .setName("Common Encryption Content Key") .setProtectionKeyId(EncryptionUtils.getThumbPrint(certificate))); // Associate the ContentKey with the Asset mediaService.action(Asset.linkContentKey(asset.getId(), contentKeyId)); return contentKey; } catch (Exception e) { System.out.println(e.getMessage()); } return null; } public static void addOpenAuthorizationPolicy(ContentKeyInfo contentKey) throws Exception { // Create ContentKeyAuthorizationPolicyRestriction (Open) List<ContentKeyAuthorizationPolicyRestriction> restrictions = new ArrayList<ContentKeyAuthorizationPolicyRestriction>(); restrictions.add(new ContentKeyAuthorizationPolicyRestriction("Open Restriction", ContentKeyRestrictionType.Open.getValue(), null)); // Create ContentKeyAuthorizationPolicyOption (PlayReady) String playReadyLicenseTemplate = configurePlayReadyLicenceTemplate(); ContentKeyAuthorizationPolicyOptionInfo playReadyOption = mediaService .create(ContentKeyAuthorizationPolicyOption.create("PlayReady Option", ContentKeyDeliveryType.PlayReadyLicense.getCode(), playReadyLicenseTemplate, restrictions)); // Create ContentKeyAuthorizationPolicyOption (Widevine) String widevineLicenseTemplate = configureWidevineLicenceTemplate(); ContentKeyAuthorizationPolicyOptionInfo widevineOption = mediaService .create(ContentKeyAuthorizationPolicyOption.create("Widevine Option", ContentKeyDeliveryType.Widevine.getCode(), widevineLicenseTemplate, restrictions)); // Create ContentKeyAuthorizationPolicy ContentKeyAuthorizationPolicyInfo contentKeyAuthorizationPolicy = mediaService .create(ContentKeyAuthorizationPolicy.create("PlayReady Open Content Key Authorization Policy")); // Link the ContentKeyAuthorizationPolicyOptions to the ContentKeyAuthorizationPolicy mediaService.action(ContentKeyAuthorizationPolicy.linkOptions(contentKeyAuthorizationPolicy.getId(), playReadyOption.getId())); mediaService.action(ContentKeyAuthorizationPolicy.linkOptions(contentKeyAuthorizationPolicy.getId(), widevineOption.getId())); // Associate the ContentKeyAuthorizationPolicy with the ContentKey mediaService.update(ContentKey.update(contentKey.getId(), contentKeyAuthorizationPolicy.getId())); System.out.println("Added Content Key Authorization Policy: " + contentKeyAuthorizationPolicy.getName()); } public static String addTokenRestrictedAuthorizationPolicy(ContentKeyInfo contentKey, TokenType tokenType) throws Exception { // Create ContentKeyAuthorizationPolicyRestriction (Token) String tokenRestrictionString = generateTokenRequirements(tokenType); List<ContentKeyAuthorizationPolicyRestriction> restrictions = new ArrayList<ContentKeyAuthorizationPolicyRestriction>(); restrictions.add(new ContentKeyAuthorizationPolicyRestriction("Token Restriction", ContentKeyRestrictionType.TokenRestricted.getValue(), tokenRestrictionString)); // Create ContentKeyAuthorizationPolicyOptions (PlayReady) String playReadyLicenseTemplateString = configurePlayReadyLicenceTemplate(); ContentKeyAuthorizationPolicyOptionInfo playReadyOption = mediaService .create(ContentKeyAuthorizationPolicyOption.create("PlayReady Option", ContentKeyDeliveryType.PlayReadyLicense.getCode(), playReadyLicenseTemplateString, restrictions)); // Create ContentKeyAuthorizationPolicyOption (Widevine) String widevineLicenseTemplate = configureWidevineLicenceTemplate(); ContentKeyAuthorizationPolicyOptionInfo widevineOption = mediaService .create(ContentKeyAuthorizationPolicyOption.create("Widevine Option", ContentKeyDeliveryType.Widevine.getCode(), widevineLicenseTemplate, restrictions)); // Create ContentKeyAuthorizationPolicy ContentKeyAuthorizationPolicyInfo contentKeyAuthorizationPolicy = mediaService .create(ContentKeyAuthorizationPolicy.create("PlayReady Token Content Key Authorization Policy")); // Link the ContentKeyAuthorizationPolicyOptions to the ContentKeyAuthorizationPolicy mediaService.action(ContentKeyAuthorizationPolicy.linkOptions(contentKeyAuthorizationPolicy.getId(), playReadyOption.getId())); mediaService.action(ContentKeyAuthorizationPolicy.linkOptions(contentKeyAuthorizationPolicy.getId(), widevineOption.getId())); // Associate the ContentKeyAuthorizationPolicy with the ContentKey mediaService.update(ContentKey.update(contentKey.getId(), contentKeyAuthorizationPolicy.getId())); System.out.println("Added Content Key Authorization Policy: " + contentKeyAuthorizationPolicy.getName()); return tokenRestrictionString; } public static void createAssetDeliveryPolicy(AssetInfo asset, ContentKeyInfo key) throws ServiceException { String acquisitionUrl = mediaService .create(ContentKey.getKeyDeliveryUrl(key.getId(), ContentKeyDeliveryType.PlayReadyLicense)); String widevineUrl = mediaService .create(ContentKey.getKeyDeliveryUrl(key.getId(), ContentKeyDeliveryType.Widevine)); Map<AssetDeliveryPolicyConfigurationKey, String> assetDeliveryPolicyConfiguration = new HashMap<AssetDeliveryPolicyConfigurationKey, String>(); if (widevineUrl.contains("?")) { widevineUrl = widevineUrl.substring(0, widevineUrl.indexOf("?")); } assetDeliveryPolicyConfiguration.put(AssetDeliveryPolicyConfigurationKey.PlayReadyLicenseAcquisitionUrl, acquisitionUrl); assetDeliveryPolicyConfiguration.put(AssetDeliveryPolicyConfigurationKey.WidevineBaseLicenseAcquisitionUrl, widevineUrl); AssetDeliveryPolicyInfo assetDeliveryPolicy = mediaService .create(AssetDeliveryPolicy.create().setName("PlayReady & Widevine Dash Asset Delivery Policy") .setAssetDeliveryConfiguration(assetDeliveryPolicyConfiguration) .setAssetDeliveryPolicyType(AssetDeliveryPolicyType.DynamicCommonEncryption) .setAssetDeliveryProtocol(EnumSet.of(AssetDeliveryProtocol.Dash))); // Link the AssetDeliveryPolicy to the Asset mediaService.action(Asset.linkDeliveryPolicy(asset.getId(), assetDeliveryPolicy.getId())); System.out.println("Added Asset Delivery Policy: " + assetDeliveryPolicy.getName()); } public static String getStreamingOriginLocator(AssetInfo asset) throws ServiceException { // Get the .ISM AssetFile ListResult<AssetFileInfo> assetFiles = mediaService.list(AssetFile.list(asset.getAssetFilesLink())); AssetFileInfo streamingAssetFile = null; for (AssetFileInfo file : assetFiles) { if (file.getName().toLowerCase().endsWith(".ism")) { streamingAssetFile = file; break; } } AccessPolicyInfo originAccessPolicy; LocatorInfo originLocator = null; // Create a 30-day readonly AccessPolicy double durationInMinutes = 60 * 24 * 30; originAccessPolicy = mediaService.create(AccessPolicy.create("Streaming policy", durationInMinutes, EnumSet.of(AccessPolicyPermission.READ))); // Create a Locator using the AccessPolicy and Asset originLocator = mediaService .create(Locator.create(originAccessPolicy.getId(), asset.getId(), LocatorType.OnDemandOrigin)); // Create a Smooth Streaming base URL return originLocator.getPath() + streamingAssetFile.getName() + "/manifest"; } private static void checkJobStatus(String jobId) throws InterruptedException, ServiceException { boolean done = false; JobState jobState = null; while (!done) { // Sleep for 5 seconds Thread.sleep(5000); // Query the updated Job state jobState = mediaService.get(Job.get(jobId)).getState(); System.out.println("Job state: " + jobState); if (jobState == JobState.Finished || jobState == JobState.Canceled || jobState == JobState.Error) { done = true; } } } private static String configurePlayReadyLicenceTemplate() throws JAXBException { // Configure PlayReady License Template and serialize it to XML PlayReadyLicenseResponseTemplate responseTemplate = new PlayReadyLicenseResponseTemplate(); PlayReadyLicenseTemplate licenseTemplate = new PlayReadyLicenseTemplate(); responseTemplate.getLicenseTemplates().add(licenseTemplate); PlayReadyPlayRight playRight = new PlayReadyPlayRight(); licenseTemplate.setPlayRight(playRight); licenseTemplate.setContentKey(new ContentEncryptionKeyFromHeader()); return MediaServicesLicenseTemplateSerializer.serialize(responseTemplate); } private static String configureWidevineLicenceTemplate() throws JsonProcessingException { // Configure Widevine License Template and serialize it to JSON WidevineMessage message = new WidevineMessage(); message.setAllowedTrackTypes(AllowedTrackTypes.SD_HD); ContentKeySpecs ckspecs = new ContentKeySpecs(); message.setContentKeySpecs(new ContentKeySpecs[] { ckspecs }); ckspecs.setRequiredOutputProtection(new RequiredOutputProtection()); ckspecs.getRequiredOutputProtection().setHdcp(Hdcp.HDCP_NONE); ckspecs.setSecurityLevel(1); ckspecs.setTrackType("SD"); message.setPolicyOverrides(new Object() { public boolean can_play = true; public boolean can_persist = true; public boolean can_renew = false; }); ObjectMapper mapper = new ObjectMapper(); return mapper.writeValueAsString(message); } private static String generateTokenRequirements(TokenType tokenType) throws Exception { TokenRestrictionTemplate template = new TokenRestrictionTemplate(tokenType); template.setAudience(new URI("urn:contoso")); template.setIssuer(new URI("https://sts.contoso.com")); template.setPrimaryVerificationKey(new SymmetricVerificationKey()); template.getRequiredClaims().add(TokenClaim.getContentKeyIdentifierClaim()); return TokenRestrictionTemplateSerializer.serialize(template); } }