// Create the content key policy that configures how the content key is delivered to end clients private static async Task <ContentKeyPolicy> GetOrCreateContentKeyPolicyAsync( IAzureMediaServicesClient client, string resourceGroupName, string accountName, string contentKeyPolicyName, byte[] tokenSigningKey) { ContentKeyPolicy policy = await client.ContentKeyPolicies.GetAsync(resourceGroupName, accountName, contentKeyPolicyName); if (policy == null) { ContentKeyPolicySymmetricTokenKey primaryKey = new ContentKeyPolicySymmetricTokenKey(TokenSigningKey); List <ContentKeyPolicyRestrictionTokenKey> alternateKeys = null; List <ContentKeyPolicyTokenClaim> requiredClaims = new List <ContentKeyPolicyTokenClaim>() { ContentKeyPolicyTokenClaim.ContentKeyIdentifierClaim }; List <ContentKeyPolicyOption> options = new List <ContentKeyPolicyOption>() { new ContentKeyPolicyOption( new ContentKeyPolicyClearKeyConfiguration(), new ContentKeyPolicyTokenRestriction(Issuer, Audience, primaryKey, ContentKeyPolicyRestrictionTokenType.Jwt, alternateKeys, requiredClaims)) }; policy = await client.ContentKeyPolicies.CreateOrUpdateAsync(resourceGroupName, accountName, contentKeyPolicyName, options); } return(policy); }
/// <summary> /// Create the content key policy that configures how the content key is delivered to end clients /// via the Key Delivery component of Azure Media Services. /// </summary> /// <param name="client">The Media Services client.</param> /// <param name="resourceGroupName">The name of the resource group within the Azure subscription.</param> /// <param name="accountName"> The Media Services account name.</param> /// <param name="contentKeyPolicyName">The name of the content key policy resource.</param> /// <returns></returns> private static async Task <ContentKeyPolicy> GetOrCreateContentKeyPolicyAsync( IAzureMediaServicesClient client, string resourceGroupName, string accountName, string contentKeyPolicyName, byte[] tokenSigningKey) { bool createPolicy = false; ContentKeyPolicy policy = null; // Let's check if the policy exists already try { policy = await client.ContentKeyPolicies.GetAsync(resourceGroupName, accountName, contentKeyPolicyName); } catch (ErrorResponseException ex) when(ex.Response.StatusCode == System.Net.HttpStatusCode.NotFound) { // Content key policy does not exist createPolicy = true; } if (createPolicy) { ContentKeyPolicySymmetricTokenKey primaryKey = new(tokenSigningKey); List <ContentKeyPolicyTokenClaim> requiredClaims = new() { ContentKeyPolicyTokenClaim.ContentKeyIdentifierClaim }; List <ContentKeyPolicyRestrictionTokenKey> alternateKeys = null; ContentKeyPolicyTokenRestriction restriction = new(Issuer, Audience, primaryKey, ContentKeyPolicyRestrictionTokenType.Jwt, alternateKeys, requiredClaims); ContentKeyPolicyWidevineConfiguration widevineConfig = ConfigureWidevineLicenseTempate(); List <ContentKeyPolicyOption> options = new() { new ContentKeyPolicyOption() { Configuration = widevineConfig, Restriction = restriction } }; policy = await client.ContentKeyPolicies.CreateOrUpdateAsync(resourceGroupName, accountName, contentKeyPolicyName, options); } else { // Get the signing key from the existing policy. var policyProperties = await client.ContentKeyPolicies.GetPolicyPropertiesWithSecretsAsync(resourceGroupName, accountName, contentKeyPolicyName); if (policyProperties.Options[0].Restriction is ContentKeyPolicyTokenRestriction restriction) { if (restriction.PrimaryVerificationKey is ContentKeyPolicySymmetricTokenKey signingKey) { TokenSigningKey = signingKey.KeyValue; } } } return(policy); }
private static ContentKeyPolicy EnsureContentKeyPolicyExists(IAzureMediaServicesClient client, string resourceGroup, string accountName, string contentKeyPolicyName) { ContentKeyPolicySymmetricTokenKey primaryKey = new ContentKeyPolicySymmetricTokenKey(TokenSigningKey); List <ContentKeyPolicyRestrictionTokenKey> alternateKeys = null; List <ContentKeyPolicyTokenClaim> requiredClaims = new List <ContentKeyPolicyTokenClaim>() { ContentKeyPolicyTokenClaim.ContentKeyIdentifierClaim }; List <ContentKeyPolicyOption> options = new List <ContentKeyPolicyOption>() { new ContentKeyPolicyOption( new ContentKeyPolicyClearKeyConfiguration(), new ContentKeyPolicyTokenRestriction(Issuer, Audience, primaryKey, ContentKeyPolicyRestrictionTokenType.Jwt, alternateKeys, requiredClaims)) }; // since we are randomly generating the signing key each time, make sure to create or update the policy each time. // Normally you would use a long lived key so you would just check for the policies existence with Get instead of // ensuring to create or update it each time. ContentKeyPolicy policy = client.ContentKeyPolicies.CreateOrUpdate(resourceGroup, accountName, contentKeyPolicyName, options); return(policy); }
/// <summary> /// Create the content key policy that configures how the content key is delivered to end clients /// via the Key Delivery component of Azure Media Services. /// </summary> /// <param name="client">The Media Services client.</param> /// <param name="resourceGroupName">The name of the resource group within the Azure subscription.</param> /// <param name="accountName"> The Media Services account name.</param> /// <param name="contentKeyPolicyName">The name of the content key policy resource.</param> /// <returns></returns> private static async Task <ContentKeyPolicy> GetOrCreateContentKeyPolicyAsync( IAzureMediaServicesClient client, string resourceGroupName, string accountName, string contentKeyPolicyName) { ContentKeyPolicy policy = await client.ContentKeyPolicies.GetAsync(resourceGroupName, accountName, contentKeyPolicyName); if (policy == null) { ContentKeyPolicyOpenRestriction restriction = new ContentKeyPolicyOpenRestriction(); ContentKeyPolicyPlayReadyConfiguration playReadyConfig = ConfigurePlayReadyLicenseTemplate(); ContentKeyPolicyWidevineConfiguration widevineConfig = ConfigureWidevineLicenseTempate(); List <ContentKeyPolicyOption> options = new List <ContentKeyPolicyOption> { new ContentKeyPolicyOption() { Configuration = playReadyConfig, Restriction = restriction }, new ContentKeyPolicyOption() { Configuration = widevineConfig, Restriction = restriction } }; Console.WriteLine("Creating a content key policy..."); policy = await client.ContentKeyPolicies.CreateOrUpdateAsync(resourceGroupName, accountName, contentKeyPolicyName, options); } return(policy); }
/// <summary> /// Create the content key policy that configures how the content key is delivered to end clients /// via the Key Delivery component of Azure Media Services. /// </summary> /// <param name="client">The Media Services client.</param> /// <param name="resourceGroupName">The name of the resource group within the Azure subscription.</param> /// <param name="accountName"> The Media Services account name.</param> /// <param name="contentKeyPolicyName">The name of the content key policy resource.</param> /// <returns></returns> private static async Task <ContentKeyPolicy> GetOrCreateContentKeyPolicyAsync( IAzureMediaServicesClient client, ConfigWrapper config, string contentKeyPolicyName) { // Call Media Services API to create or update the policy. Console.WriteLine("Creating or updating the content key policy..."); ContentKeyPolicyOpenRestriction restriction = new(); ContentKeyPolicyFairPlayConfiguration fairPlay = ConfigureFairPlayLicenseTemplate(config.AskHex, config.FairPlayPfxPath, config.FairPlayPfxPassword); List <ContentKeyPolicyOption> options = new() { new ContentKeyPolicyOption() { Configuration = fairPlay, Restriction = restriction } }; Console.WriteLine("Creating or updating the content key policy..."); ContentKeyPolicy policy = await client.ContentKeyPolicies.CreateOrUpdateAsync(config.ResourceGroup, config.AccountName, contentKeyPolicyName, options); return(policy); }
// </CreateMediaServicesClient> /// <summary> /// Create the content key policy that configures how the content key is delivered to end clients /// via the Key Delivery component of Azure Media Services. /// </summary> /// <param name="client">The Media Services client.</param> /// <param name="resourceGroupName">The name of the resource group within the Azure subscription.</param> /// <param name="accountName"> The Media Services account name.</param> /// <param name="contentKeyPolicyName">The name of the content key policy resource.</param> /// <returns></returns> // <GetOrCreateContentKeyPolicy> private static async Task <ContentKeyPolicy> GetOrCreateContentKeyPolicyAsync( IAzureMediaServicesClient client, string resourceGroupName, string accountName, string contentKeyPolicyName, byte[] tokenSigningKey) { ContentKeyPolicy policy = await client.ContentKeyPolicies.GetAsync(resourceGroupName, accountName, contentKeyPolicyName); if (policy == null) { ContentKeyPolicySymmetricTokenKey primaryKey = new ContentKeyPolicySymmetricTokenKey(tokenSigningKey); List <ContentKeyPolicyTokenClaim> requiredClaims = new List <ContentKeyPolicyTokenClaim>() { ContentKeyPolicyTokenClaim.ContentKeyIdentifierClaim }; List <ContentKeyPolicyRestrictionTokenKey> alternateKeys = null; ContentKeyPolicyTokenRestriction restriction = new ContentKeyPolicyTokenRestriction(Issuer, Audience, primaryKey, ContentKeyPolicyRestrictionTokenType.Jwt, alternateKeys, requiredClaims); ContentKeyPolicyPlayReadyConfiguration playReadyConfig = ConfigurePlayReadyLicenseTemplate(); ContentKeyPolicyWidevineConfiguration widevineConfig = ConfigureWidevineLicenseTempate(); List <ContentKeyPolicyOption> options = new List <ContentKeyPolicyOption>(); options.Add( new ContentKeyPolicyOption() { Configuration = playReadyConfig, // If you want to set an open restriction, use // Restriction = new ContentKeyPolicyOpenRestriction() Restriction = restriction }); options.Add( new ContentKeyPolicyOption() { Configuration = widevineConfig, Restriction = restriction }); policy = await client.ContentKeyPolicies.CreateOrUpdateAsync(resourceGroupName, accountName, contentKeyPolicyName, options); } else { // Get the signing key from the existing policy. var policyProperties = await client.ContentKeyPolicies.GetPolicyPropertiesWithSecretsAsync(resourceGroupName, accountName, contentKeyPolicyName); var restriction = policyProperties.Options[0].Restriction as ContentKeyPolicyTokenRestriction; if (restriction != null) { var signingKey = restriction.PrimaryVerificationKey as ContentKeyPolicySymmetricTokenKey; if (signingKey != null) { TokenSigningKey = signingKey.KeyValue; } } } return(policy); }
internal static void ValidateContentKeyPolicy(ContentKeyPolicy contentKeyPolicy, string expectedName, string expectedDescription, ContentKeyPolicyOption[] expectedOptions) { Assert.Equal(expectedName, contentKeyPolicy.Name); Assert.NotEqual(Guid.Empty, contentKeyPolicy.PolicyId); Assert.Equal(expectedDescription, contentKeyPolicy.Description); Assert.Equal(expectedOptions.Length, contentKeyPolicy.Options.Count); for (int i = 0; i < expectedOptions.Length; i++) { Assert.Equal(expectedOptions[i].Name, contentKeyPolicy.Options[i].Name); Assert.Equal(expectedOptions[i].Configuration.GetType(), contentKeyPolicy.Options[i].Configuration.GetType()); Assert.Equal(expectedOptions[i].Restriction.GetType(), contentKeyPolicy.Options[i].Restriction.GetType()); Assert.NotEqual(Guid.Empty, contentKeyPolicy.Options[i].PolicyOptionId); if (expectedOptions[i].Restriction.GetType() == typeof(ContentKeyPolicyTokenRestriction)) { ContentKeyPolicyTokenRestriction expectedOptionRestriction = (ContentKeyPolicyTokenRestriction)expectedOptions[i].Restriction; ContentKeyPolicyTokenRestriction actualOptionRestriction = (ContentKeyPolicyTokenRestriction)contentKeyPolicy.Options[i].Restriction; Assert.Equal(expectedOptionRestriction.Audience, actualOptionRestriction.Audience); Assert.Equal(expectedOptionRestriction.Issuer, actualOptionRestriction.Issuer); Assert.Equal(expectedOptionRestriction.OpenIdConnectDiscoveryDocument, actualOptionRestriction.OpenIdConnectDiscoveryDocument); Assert.Equal(expectedOptionRestriction.RestrictionTokenType, actualOptionRestriction.RestrictionTokenType); Assert.Equal(expectedOptionRestriction.RequiredClaims.Count, actualOptionRestriction.RequiredClaims.Count); for (int x = 0; x < expectedOptionRestriction.RequiredClaims.Count; x++) { Assert.Equal(expectedOptionRestriction.RequiredClaims[x].ClaimType, actualOptionRestriction.RequiredClaims[x].ClaimType); Assert.Equal(expectedOptionRestriction.RequiredClaims[x].ClaimValue, actualOptionRestriction.RequiredClaims[x].ClaimValue); } } } }
private void CreateContentKeyPolicy(string policyName) { ContentKeyPolicyOption[] options = new ContentKeyPolicyOption[] { new ContentKeyPolicyOption(new ContentKeyPolicyClearKeyConfiguration(), new ContentKeyPolicyOpenRestriction()) }; ContentKeyPolicy policy = MediaClient.ContentKeyPolicies.CreateOrUpdate(ResourceGroup, AccountName, policyName, options); }
public static IActionResult Run([HttpTrigger(AuthorizationLevel.Function, "post", Route = null)] HttpRequest req, TraceWriter log) { log.Info($"AMS v3 Function - CreateEmptyAsset was triggered!"); string requestBody = new StreamReader(req.Body).ReadToEnd(); dynamic data = JsonConvert.DeserializeObject(requestBody); if (data.contentKeyPolicyName == null) { return(new BadRequestObjectResult("Please pass contentKeyPolicyName in the input object")); } if (data.contentKeyPolicyOptions == null) { return(new BadRequestObjectResult("Please pass contentKeyPolicyOptions in the input object")); } string contentKeyPolicyName = data.contentKeyPolicyName; string contentKeyPolicyDescription = null; if (data.contentKeyPolicyDescription == null) { contentKeyPolicyDescription = data.contentKeyPolicyDescription; } MediaServicesConfigWrapper amsconfig = new MediaServicesConfigWrapper(); ContentKeyPolicy policy = null; try { IAzureMediaServicesClient client = MediaServicesHelper.CreateMediaServicesClientAsync(amsconfig); JsonConverter[] jsonConverters = { new MediaServicesHelperJsonConverter(), new MediaServicesHelperTimeSpanJsonConverter() }; List <ContentKeyPolicyOption> options = JsonConvert.DeserializeObject <List <ContentKeyPolicyOption> >(data.contentKeyPolicyOptions.ToString(), jsonConverters); policy = client.ContentKeyPolicies.CreateOrUpdate(amsconfig.ResourceGroup, amsconfig.AccountName, contentKeyPolicyName, options, contentKeyPolicyDescription); } catch (ApiErrorException e) { log.Info($"ERROR: AMS API call failed with error code: {e.Body.Error.Code} and message: {e.Body.Error.Message}"); return(new BadRequestObjectResult("AMS API call error: " + e.Message + "\nError Code: " + e.Body.Error.Code + "\nMessage: " + e.Body.Error.Message)); } catch (Exception e) { log.Info($"ERROR: Exception with message: {e.Message}"); return(new BadRequestObjectResult("Error: " + e.Message)); } return((ActionResult) new OkObjectResult(new { policyId = policy.PolicyId })); }
private static void PublishAssetWithEnvelopeEncryption(IAzureMediaServicesClient client, string resourceGroup, string accountName, string assetName, string streamingLocatorName) { string contentKeyPolicyName = "SharedContentKeyPolicyUsedByAllAssets"; ContentKeyPolicy policy = EnsureContentKeyPolicyExists(client, resourceGroup, accountName, contentKeyPolicyName); StreamingLocator locator = new StreamingLocator( assetName: assetName, streamingPolicyName: PredefinedStreamingPolicy.ClearKey, defaultContentKeyPolicyName: contentKeyPolicyName); client.StreamingLocators.Create(resourceGroup, accountName, streamingLocatorName, locator); }
/// <summary> /// Create the content key policy that configures how the content key is delivered to end clients /// via the Key Delivery component of Azure Media Services. /// </summary> /// <param name="client">The Media Services client.</param> /// <param name="resourceGroupName">The name of the resource group within the Azure subscription.</param> /// <param name="accountName"> The Media Services account name.</param> /// <param name="contentKeyPolicyName">The name of the content key policy resource.</param> /// <returns></returns> private static async Task <ContentKeyPolicy> GetOrCreateContentKeyPolicyAsync( IAzureMediaServicesClient client, string resourceGroupName, string accountName, string contentKeyPolicyName) { bool createPolicy = false; ContentKeyPolicy policy = null; try { policy = await client.ContentKeyPolicies.GetAsync(resourceGroupName, accountName, contentKeyPolicyName); } catch (ErrorResponseException ex) when(ex.Response.StatusCode == System.Net.HttpStatusCode.NotFound) { // Content key policy does not exist createPolicy = true; } if (createPolicy) { ContentKeyPolicyOpenRestriction restriction = new(); ContentKeyPolicyPlayReadyConfiguration playReadyConfig = ConfigurePlayReadyLicenseTemplate(); ContentKeyPolicyWidevineConfiguration widevineConfig = ConfigureWidevineLicenseTempate(); List <ContentKeyPolicyOption> options = new() { new ContentKeyPolicyOption() { Configuration = playReadyConfig, Restriction = restriction }, new ContentKeyPolicyOption() { Configuration = widevineConfig, Restriction = restriction } }; Console.WriteLine("Creating a content key policy..."); policy = await client.ContentKeyPolicies.CreateOrUpdateAsync(resourceGroupName, accountName, contentKeyPolicyName, options); } return(policy); }
/// <summary> /// Create the content key policy that configures how the content key is delivered to end clients /// via the Key Delivery component of Azure Media Services. /// </summary> /// <param name="client">The Media Services client.</param> /// <param name="resourceGroupName">The name of the resource group within the Azure subscription.</param> /// <param name="accountName"> The Media Services account name.</param> /// <param name="contentKeyPolicyName">The name of the content key policy resource.</param> /// <returns></returns> private static async Task <ContentKeyPolicy> GetOrCreateContentKeyPolicyAsync( IAzureMediaServicesClient client, string resourceGroupName, string accountName, string contentKeyPolicyName) { bool createPolicy = false; ContentKeyPolicy policy = null; try { policy = await client.ContentKeyPolicies.GetAsync(resourceGroupName, accountName, contentKeyPolicyName); } catch (ErrorResponseException ex) when(ex.Response.StatusCode == System.Net.HttpStatusCode.NotFound) { // Content key policy does not exist createPolicy = true; } if (createPolicy) { ContentKeyPolicySymmetricTokenKey primaryKey = new(TokenSigningKey); List <ContentKeyPolicyRestrictionTokenKey> alternateKeys = null; List <ContentKeyPolicyTokenClaim> requiredClaims = new() { ContentKeyPolicyTokenClaim.ContentKeyIdentifierClaim }; List <ContentKeyPolicyOption> options = new() { new ContentKeyPolicyOption( new ContentKeyPolicyClearKeyConfiguration(), new ContentKeyPolicyTokenRestriction(Issuer, Audience, primaryKey, ContentKeyPolicyRestrictionTokenType.Jwt, alternateKeys, requiredClaims)) }; // Since we are randomly generating the signing key each time, make sure to create or update the policy each time. // Normally you would use a long lived key so you would just check for the policies existence with Get instead of // ensuring to create or update it each time. policy = await client.ContentKeyPolicies.CreateOrUpdateAsync(resourceGroupName, accountName, contentKeyPolicyName, options); } return(policy); }
private async Task <List <ContentKeyPolicy> > ReturnSelectedCKPoliciessAsync() { List <ContentKeyPolicy> SelectedCKPolicies = new List <ContentKeyPolicy>(); await _amsClient.RefreshTokenIfNeededAsync(); Microsoft.Rest.Azure.IPage <ContentKeyPolicy> ckPolicies = await _amsClient.AMSclient.ContentKeyPolicies.ListAsync(_amsClient.credentialsEntry.ResourceGroup, _amsClient.credentialsEntry.AccountName); foreach (DataGridViewRow Row in dataGridViewCKPolicies.SelectedRows) { string ckpolName = Row.Cells[dataGridViewFilters.Columns["Name"].Index].Value.ToString(); ContentKeyPolicy myPolicy = ckPolicies.Where(f => f.Name == ckpolName).FirstOrDefault(); if (myPolicy != null) { SelectedCKPolicies.Add(myPolicy); } } return(SelectedCKPolicies); }
public StreamProtection[] GetProtectionInfo(string authToken, MediaClient mediaClient, StreamingLocator locator) { authToken = string.Concat("Bearer=", authToken); List <StreamProtection> protectionInfo = new List <StreamProtection>(); if (locator.StreamingPolicyName == PredefinedStreamingPolicy.ClearKey) { StreamProtection streamProtection = new StreamProtection() { Type = MediaProtection.AES, AuthenticationToken = authToken }; protectionInfo.Add(streamProtection); } else if (locator.StreamingPolicyName == PredefinedStreamingPolicy.SecureStreaming) { ContentKeyPolicy contentKeyPolicy = mediaClient.GetEntity <ContentKeyPolicy>(MediaEntity.ContentKeyPolicy, locator.DefaultContentKeyPolicyName); foreach (ContentKeyPolicyOption contentKeyPolicyOption in contentKeyPolicy.Options) { if (contentKeyPolicyOption.Configuration is ContentKeyPolicyPlayReadyConfiguration) { StreamProtection streamProtection = new StreamProtection() { Type = MediaProtection.PlayReady, AuthenticationToken = authToken }; protectionInfo.Add(streamProtection); } else if (contentKeyPolicyOption.Configuration is ContentKeyPolicyWidevineConfiguration) { StreamProtection streamProtection = new StreamProtection() { Type = MediaProtection.Widevine, AuthenticationToken = authToken }; protectionInfo.Add(streamProtection); } } } return(protectionInfo.Count == 0 ? null : protectionInfo.ToArray()); }
public ContentKeyPolicy CreateContentKeyPolicy(string policyName, ContentKeyPolicyConfiguration[] policyConfigurations) { ContentKeyPolicy contentKeyPolicy = _media.ContentKeyPolicies.Get(MediaAccount.ResourceGroupName, MediaAccount.Name, policyName); if (contentKeyPolicy == null) { string settingKey = Constant.AppSettingKey.DirectoryClientId; string clientId = AppSetting.GetValue(settingKey); settingKey = Constant.AppSettingKey.DirectoryTenantId; string tenantId = AppSetting.GetValue(settingKey); settingKey = Constant.AppSettingKey.DirectoryAuthorityUrl; string authorityUrl = AppSetting.GetValue(settingKey); authorityUrl = string.Format(authorityUrl, tenantId); settingKey = Constant.AppSettingKey.DirectoryPolicyIdSignUpIn; string signUpInPolicyId = AppSetting.GetValue(settingKey); settingKey = Constant.AppSettingKey.DirectoryDiscoveryPath; string discoveryPath = AppSetting.GetValue(settingKey); discoveryPath = string.Concat(discoveryPath, "?p=", signUpInPolicyId); ContentKeyPolicyTokenRestriction policyRestriction = new ContentKeyPolicyTokenRestriction() { OpenIdConnectDiscoveryDocument = string.Concat(authorityUrl, discoveryPath), RestrictionTokenType = ContentKeyPolicyRestrictionTokenType.Jwt, Issuer = authorityUrl, Audience = clientId }; List <ContentKeyPolicyOption> policyOptions = new List <ContentKeyPolicyOption>(); foreach (ContentKeyPolicyConfiguration policyConfiguration in policyConfigurations) { ContentKeyPolicyOption policyOption = new ContentKeyPolicyOption(policyConfiguration, policyRestriction); policyOptions.Add(policyOption); } contentKeyPolicy = _media.ContentKeyPolicies.CreateOrUpdate(MediaAccount.ResourceGroupName, MediaAccount.Name, policyName, policyOptions); } return(contentKeyPolicy); }
public MediaProtection[] GetStreamProtection(string authToken, MediaClient mediaClient, StreamingLocator locator) { List <MediaProtection> streamProtection = new List <MediaProtection>(); if (locator.StreamingPolicyName == PredefinedStreamingPolicy.ClearKey) { streamProtection.Add(new MediaProtection() { Type = MediaContentProtection.AES, AuthenticationToken = authToken }); } else if (locator.StreamingPolicyName == PredefinedStreamingPolicy.MultiDrmCencStreaming || locator.StreamingPolicyName == PredefinedStreamingPolicy.MultiDrmStreaming) { ContentKeyPolicy contentKeyPolicy = mediaClient.GetEntity <ContentKeyPolicy>(MediaEntity.ContentKeyPolicy, locator.DefaultContentKeyPolicyName); foreach (ContentKeyPolicyOption contentKeyPolicyOption in contentKeyPolicy.Options) { if (contentKeyPolicyOption.Configuration is ContentKeyPolicyPlayReadyConfiguration) { streamProtection.Add(new MediaProtection() { Type = MediaContentProtection.PlayReady, AuthenticationToken = authToken }); } else if (contentKeyPolicyOption.Configuration is ContentKeyPolicyWidevineConfiguration) { streamProtection.Add(new MediaProtection() { Type = MediaContentProtection.Widevine, AuthenticationToken = authToken }); } } } return(streamProtection.ToArray()); }
private static async Task RunAsync(ConfigWrapper config) { IAzureMediaServicesClient client = await CreateMediaServicesClientAsync(config); client.LongRunningOperationRetryTimeout = 2; string uniqueness = Guid.NewGuid().ToString("N"); string jobName = $"job-{uniqueness}"; string locatorName = $"locator-{uniqueness}"; string outputAssetName = $"output-{uniqueness}"; string inputAssetName = $"input-{uniqueness}"; bool stopEndpoint = false; try { Transform transform = await GetOrCreateTransformAsync(client, config.ResourceGroup, config.AccountName, AdaptiveStreamingTransformName); await CreateInputAssetAsync(client, config.ResourceGroup, config.AccountName, inputAssetName, InputMP4FileName); Asset outputAsset = await CreateOutputAssetAsync(client, config.ResourceGroup, config.AccountName, outputAssetName); Job job = await SubmitJobAsync(client, config.ResourceGroup, config.AccountName, AdaptiveStreamingTransformName, jobName, inputAssetName, outputAsset.Name); job = await WaitForJobToFinishAsync(client, config.ResourceGroup, config.AccountName, AdaptiveStreamingTransformName, jobName); if (job.State == JobState.Finished) { Console.WriteLine("Job finished."); // Create a TokenSigningKey. // Create the content key policy ContentKeyPolicy policy = await GetOrCreateContentKeyPolicyAsync(client, config.ResourceGroup, config.AccountName, ContentKeyPolicyName, TokenSigningKey); // Sets StreamingLocator.StreamingPolicyName to use the Predefined_MultiDrmCencStreaming policy. StreamingLocator locator = await CreateStreamingLocatorAsync(client, config.ResourceGroup, config.AccountName, outputAsset.Name, locatorName, ContentKeyPolicyName); StreamingEndpoint streamingEndpoint = await client.StreamingEndpoints.GetAsync(config.ResourceGroup, config.AccountName, DefaultStreamingEndpointName); if (streamingEndpoint != null) { if (streamingEndpoint.ResourceState != StreamingEndpointResourceState.Running) { await client.StreamingEndpoints.StartAsync(config.ResourceGroup, config.AccountName, DefaultStreamingEndpointName); // Since we started the endpoint, we should stop it in cleanup. stopEndpoint = true; } } // Ge the Dash streaming URL path var dashPath = await GetStreamingUrlAsync(client, config.ResourceGroup, config.AccountName, locatorName, streamingEndpoint); // Get the key identifier of the content. string keyIdentifier = locator.ContentKeys.Where(k => k.Type == StreamingLocatorContentKeyType.CommonEncryptionCenc).First().Id.ToString(); Console.WriteLine($"KeyIdentifier = {keyIdentifier}"); // To generate our test token we must get the ContentKeyId to put in the ContentKeyIdentifierClaim claim. string token = GetTokenAsync(Issuer, Audience, keyIdentifier, TokenSigningKey); Console.WriteLine(); Console.WriteLine("Copy and paste the URL in your browser to play back the file in the Azure Media Player."); Console.WriteLine("You can use the Edge browser or IE11 for PlayReady DRM."); Console.WriteLine(); Console.WriteLine($"https://ampdemo.azureedge.net/?url={dashPath}&playready=true&token=Bearer%3D{token}"); Console.WriteLine(); Console.WriteLine("Press enter to cleanup."); Console.Out.Flush(); Console.ReadLine(); } } catch (ApiErrorException e) { Console.WriteLine("EXCEPTION"); Console.WriteLine($"\tCode: {e.Body.Error.Code}"); Console.WriteLine($"\tMessage: {e.Body.Error.Message}"); Console.WriteLine(); Console.WriteLine("Exiting, cleanup may be necessary..."); Console.ReadLine(); } finally { Console.WriteLine("Cleaning up..."); await CleanUpAsync(client, config.ResourceGroup, config.AccountName, AdaptiveStreamingTransformName, locatorName, outputAssetName, jobName, ContentKeyPolicyName, stopEndpoint, DefaultStreamingEndpointName); // to remove everything uncomment this line - use with caution as it will remove everything! // await CleanUpEverything(client, config.ResourceGroup, config.AccountName); } }
/// <summary> /// Run the sample async. /// </summary> /// <param name="config">The param is of type ConfigWrapper. This class reads values from local configuration file.</param> /// <returns></returns> private static async Task RunAsync(ConfigWrapper config) { IAzureMediaServicesClient client; try { client = await CreateMediaServicesClientAsync(config); } catch (Exception e) { Console.Error.WriteLine("TIP: Make sure that you have filled out the appsettings.json file before running this sample."); Console.Error.WriteLine($"{e.Message}"); return; } // Set the polling interval for long running operations to 2 seconds. // The default value is 30 seconds for the .NET client SDK client.LongRunningOperationRetryTimeout = 2; // Creating a unique suffix so that we don't have name collisions if you run the sample // multiple times without cleaning up. string uniqueness = Guid.NewGuid().ToString("N"); string jobName = $"job-{uniqueness}"; string locatorName = $"locator-{uniqueness}"; string outputAssetName = $"output-{uniqueness}"; bool stopEndpoint = false; EventProcessorHost eventProcessorHost = null; try { // Ensure that you have the desired encoding Transform. This is really a one time setup operation. Transform transform = await GetOrCreateTransformAsync(client, config.ResourceGroup, config.AccountName, AdaptiveStreamingTransformName); // Output from the encoding Job must be written to an Asset, so let's create one Asset outputAsset = await CreateOutputAssetAsync(client, config.ResourceGroup, config.AccountName, outputAssetName); Job job = await SubmitJobAsync(client, config.ResourceGroup, config.AccountName, AdaptiveStreamingTransformName, outputAsset.Name, jobName); try { // First we will try to process Job events through Event Hub in real-time. If this fails for any reason, // we will fall-back on polling Job status instead. // Please refer README for Event Hub and storage settings. string StorageConnectionString = string.Format("DefaultEndpointsProtocol=https;AccountName={0};AccountKey={1}", config.StorageAccountName, config.StorageAccountKey); // Create a new host to process events from an Event Hub. Console.WriteLine("Creating a new host to process events from an Event Hub..."); eventProcessorHost = new EventProcessorHost(config.EventHubName, PartitionReceiver.DefaultConsumerGroupName, config.EventHubConnectionString, StorageConnectionString, config.StorageContainerName); // Create an AutoResetEvent to wait for the job to finish and pass it to EventProcessor so that it can be set when a final state event is received. AutoResetEvent jobWaitingEvent = new AutoResetEvent(false); // Registers the Event Processor Host and starts receiving messages. Pass in jobWaitingEvent so it can be called back. await eventProcessorHost.RegisterEventProcessorFactoryAsync(new MediaServicesEventProcessorFactory(jobName, jobWaitingEvent), EventProcessorOptions.DefaultOptions); // Create a Task list, adding a job waiting task and a timer task. Other tasks can be added too. IList <Task> tasks = new List <Task>(); // Add a task to wait for the job to finish. jobWaitingEvent will be set when a final state is received by EventProcessor. Task jobTask = Task.Run(() => jobWaitingEvent.WaitOne()); tasks.Add(jobTask); // 30 minutes timeout. var tokenSource = new CancellationTokenSource(); var timeout = Task.Delay(30 * 60 * 1000, tokenSource.Token); tasks.Add(timeout); // Wait for any task to finish. if (await Task.WhenAny(tasks) == jobTask) { // Job finished. Cancel the timer. tokenSource.Cancel(); // Get the latest status of the job. job = await client.Jobs.GetAsync(config.ResourceGroup, config.AccountName, AdaptiveStreamingTransformName, jobName); } else { // Timeout happened, Something might go wrong with job events. Fall-back on polling instead. jobWaitingEvent.Set(); throw new Exception("Timeout happened."); } } catch (Exception) { Console.WriteLine("Warning: Failed to connect to Event Hub, please refer README for Event Hub and storage settings."); // Polling is not a recommended best practice for production applications because of the latency it introduces. // Overuse of this API may trigger throttling. Developers should instead use Event Grid. Console.WriteLine("Polling job status..."); job = await WaitForJobToFinishAsync(client, config.ResourceGroup, config.AccountName, AdaptiveStreamingTransformName, jobName); } if (job.State == JobState.Finished) { // Set a token signing key that you want to use TokenSigningKey = Convert.FromBase64String(config.SymmetricKey); // Create the content key policy that configures how the content key is delivered to end clients // via the Key Delivery component of Azure Media Services. // We are using the ContentKeyIdentifierClaim in the ContentKeyPolicy which means that the token presented // to the Key Delivery Component must have the identifier of the content key in it. ContentKeyPolicy policy = await GetOrCreateContentKeyPolicyAsync(client, config.ResourceGroup, config.AccountName, ContentKeyPolicyName, TokenSigningKey); // Sets StreamingLocator.StreamingPolicyName to "Predefined_MultiDrmCencStreaming" policy. StreamingLocator locator = await CreateStreamingLocatorAsync(client, config.ResourceGroup, config.AccountName, outputAsset.Name, locatorName, ContentKeyPolicyName); // In this example, we want to play the Widevine (CENC) encrypted stream. // We need to get the key identifier of the content key where its type is CommonEncryptionCenc. string keyIdentifier = locator.ContentKeys.Where(k => k.Type == StreamingLocatorContentKeyType.CommonEncryptionCenc).First().Id.ToString(); Console.WriteLine($"KeyIdentifier = {keyIdentifier}"); // In order to generate our test token we must get the ContentKeyId to put in the ContentKeyIdentifierClaim claim. string token = GetTokenAsync(Issuer, Audience, keyIdentifier, TokenSigningKey); StreamingEndpoint streamingEndpoint = await client.StreamingEndpoints.GetAsync(config.ResourceGroup, config.AccountName, DefaultStreamingEndpointName); if (streamingEndpoint != null) { if (streamingEndpoint.ResourceState != StreamingEndpointResourceState.Running) { Console.WriteLine("Streaming Endpoint was Stopped, restarting now.."); await client.StreamingEndpoints.StartAsync(config.ResourceGroup, config.AccountName, DefaultStreamingEndpointName); // Since we started the endpoint, we should stop it in cleanup. stopEndpoint = true; } } string dashPath = await GetDASHStreamingUrlAsync(client, config.ResourceGroup, config.AccountName, locator.Name, streamingEndpoint); Console.WriteLine("Copy and paste the following URL in your browser to play back the file in the Azure Media Player."); Console.WriteLine("You can use Chrome/Firefox for Widevine."); Console.WriteLine(); Console.WriteLine($"https://ampdemo.azureedge.net/?url={dashPath}&widevine=true&token=Bearer%3D{token}"); Console.WriteLine(); } Console.WriteLine("When finished testing press enter to cleanup."); Console.Out.Flush(); Console.ReadLine(); } catch (ApiErrorException e) { Console.WriteLine("Hit ApiErrorException"); Console.WriteLine($"\tCode: {e.Body.Error.Code}"); Console.WriteLine($"\tMessage: {e.Body.Error.Message}"); Console.WriteLine(); Console.WriteLine("Exiting, cleanup may be necessary..."); Console.ReadLine(); } finally { Console.WriteLine("Cleaning up..."); await CleanUpAsync(client, config.ResourceGroup, config.AccountName, AdaptiveStreamingTransformName, outputAssetName, jobName, ContentKeyPolicyName, stopEndpoint, DefaultStreamingEndpointName); if (eventProcessorHost != null) { Console.WriteLine("Unregistering event processor..."); // Disposes of the Event Processor Host. await eventProcessorHost.UnregisterEventProcessorAsync(); Console.WriteLine(); } } }
/// <summary> /// Run the sample async. /// </summary> /// <param name="config">The param is of type ConfigWrapper. This class reads values from local configuration file.</param> /// <returns></returns> private static async Task RunAsync(ConfigWrapper config) { IAzureMediaServicesClient client; try { client = await Authentication.CreateMediaServicesClientAsync(config, UseInteractiveAuth); } catch (Exception e) { Console.Error.WriteLine("TIP: Make sure that you have filled out the appsettings.json or .env file before running this sample."); Console.Error.WriteLine($"{e.Message}"); return; } // Set the polling interval for long running operations to 2 seconds. // The default value is 30 seconds for the .NET client SDK client.LongRunningOperationRetryTimeout = 2; // Creating a unique suffix so that we don't have name collisions if you run the sample // multiple times without cleaning up. string uniqueness = Guid.NewGuid().ToString("N"); string jobName = $"job-{uniqueness}"; string locatorName = $"locator-{uniqueness}"; string outputAssetName = $"output-{uniqueness}"; bool stopEndpoint = false; // In this sample, we use Event Grid to listen to the notifications through an Azure Event Hub. // If you do not provide an Event Hub config in the settings, the sample will fall back to polling the job for status. // For production ready code, it is always recommended to use Event Grid instead of polling on the Job status. EventProcessorClient processorClient = null; BlobContainerClient storageClient = null; MediaServicesEventProcessor mediaEventProcessor = null; try { // Ensure that you have the desired encoding Transform. This is really a one time setup operation. Transform transform = await GetOrCreateTransformAsync(client, config.ResourceGroup, config.AccountName, AdaptiveStreamingTransformName); // Output from the encoding Job must be written to an Asset, so let's create one Asset outputAsset = await CreateOutputAssetAsync(client, config.ResourceGroup, config.AccountName, outputAssetName); Job job = await SubmitJobAsync(client, config.ResourceGroup, config.AccountName, AdaptiveStreamingTransformName, outputAsset.Name, jobName); try { // First we will try to process Job events through Event Hub in real-time. If this fails for any reason, // we will fall-back on polling Job status instead. // Please refer README for Event Hub and storage settings. // A storage account is required to process the Event Hub events from the Event Grid subscription in this sample. // Create a new host to process events from an Event Hub. Console.WriteLine("Creating a new client to process events from an Event Hub..."); var credential = new DefaultAzureCredential(); var storageConnectionString = string.Format("DefaultEndpointsProtocol=https;AccountName={0};AccountKey={1}", config.StorageAccountName, config.StorageAccountKey); var blobContainerName = config.StorageContainerName; var eventHubsConnectionString = config.EventHubConnectionString; var eventHubName = config.EventHubName; var consumerGroup = config.EventHubConsumerGroup; storageClient = new BlobContainerClient( storageConnectionString, blobContainerName); processorClient = new EventProcessorClient( storageClient, consumerGroup, eventHubsConnectionString, eventHubName); // Create an AutoResetEvent to wait for the job to finish and pass it to EventProcessor so that it can be set when a final state event is received. AutoResetEvent jobWaitingEvent = new(false); // Create a Task list, adding a job waiting task and a timer task. Other tasks can be added too. IList <Task> tasks = new List <Task>(); // Add a task to wait for the job to finish. jobWaitingEvent will be set when a final state is received by EventProcessor. Task jobTask = Task.Run(() => jobWaitingEvent.WaitOne()); tasks.Add(jobTask); // 30 minutes timeout. var cancellationSource = new CancellationTokenSource(); var timeout = Task.Delay(30 * 60 * 1000, cancellationSource.Token); tasks.Add(timeout); mediaEventProcessor = new MediaServicesEventProcessor(jobName, jobWaitingEvent, null); processorClient.ProcessEventAsync += mediaEventProcessor.ProcessEventsAsync; processorClient.ProcessErrorAsync += mediaEventProcessor.ProcessErrorAsync; // Wait for any task to finish. if (await Task.WhenAny(tasks) == jobTask) { // Job finished. Cancel the timer. cancellationSource.Cancel(); // Get the latest status of the job. job = await client.Jobs.GetAsync(config.ResourceGroup, config.AccountName, AdaptiveStreamingTransformName, jobName); } else { // Timeout happened, Something might go wrong with job events. Fall-back on polling instead. jobWaitingEvent.Set(); throw new Exception("Timeout happened."); } } catch (Exception) { Console.WriteLine("Warning: Failed to connect to Event Hub, please refer README for Event Hub and storage settings."); // Polling is not a recommended best practice for production applications because of the latency it introduces. // Overuse of this API may trigger throttling. Developers should instead use Event Grid. Console.WriteLine("Polling job status..."); job = await WaitForJobToFinishAsync(client, config.ResourceGroup, config.AccountName, AdaptiveStreamingTransformName, jobName); } if (job.State == JobState.Finished) { // Create the content key policy that configures how the content key is delivered to end clients // via the Key Delivery component of Azure Media Services. ContentKeyPolicy policy = await GetOrCreateContentKeyPolicyAsync(client, config, ContentKeyPolicyName); StreamingLocator locator = await CreateStreamingLocatorAsync(client, config.ResourceGroup, config.AccountName, outputAsset.Name, locatorName, policy.Name); StreamingEndpoint streamingEndpoint = await client.StreamingEndpoints.GetAsync(config.ResourceGroup, config.AccountName, DefaultStreamingEndpointName); if (streamingEndpoint.ResourceState != StreamingEndpointResourceState.Running) { await client.StreamingEndpoints.StartAsync(config.ResourceGroup, config.AccountName, DefaultStreamingEndpointName); // Since we started the endpoint, we should stop it in cleanup. stopEndpoint = true; } string hlsPath = await GetHlsStreamingUrlAsync(client, config.ResourceGroup, config.AccountName, locator.Name, streamingEndpoint); Console.WriteLine(); Console.WriteLine("HLS url can be played on your Apple device:"); Console.WriteLine(hlsPath); Console.WriteLine(); } Console.WriteLine("When finished testing press enter to cleanup."); Console.Out.Flush(); Console.ReadLine(); } catch (ErrorResponseException e) { Console.WriteLine("ErrorResponseException"); Console.WriteLine($"\tCode: {e.Body.Error.Code}"); Console.WriteLine($"\tMessage: {e.Body.Error.Message}"); Console.WriteLine(); Console.WriteLine("Exiting, cleanup may be necessary..."); Console.ReadLine(); } finally { Console.WriteLine("Cleaning up..."); await CleanUpAsync(client, config.ResourceGroup, config.AccountName, AdaptiveStreamingTransformName, outputAssetName, jobName, ContentKeyPolicyName, stopEndpoint, DefaultStreamingEndpointName); if (processorClient != null) { Console.WriteLine("Job final state received, Stopping the event processor..."); await processorClient.StopProcessingAsync(); Console.WriteLine(); // It is encouraged that you unregister your handlers when you have // finished using the Event Processor to ensure proper cleanup. This // is especially important when using lambda expressions or handlers // in any form that may contain closure scopes or hold other references. processorClient.ProcessEventAsync -= mediaEventProcessor.ProcessEventsAsync; processorClient.ProcessErrorAsync -= mediaEventProcessor.ProcessErrorAsync; } } }
public async void MediaServicesV3ServiceCreateLocatorTestWithPolicyUpdate(RequestMediaServicesLocatorCreateDTO locatorCreateDTO, string updatePolicy, ContentKeyPolicy contentKeyPolicy) { var amsV3SdkWrapper = Mock.Of <IMediaServicesV3SdkWrapper>(); var storageService = Mock.Of <IStorageService>(); var settingsProvider = Mock.Of <ISettingsProvider>(); // Arrange string assetName = "myassetname"; var amsAccount = new MediaService(storageAccounts: new List <StorageAccount>() { new StorageAccount() { Id = MediaServicesV3PublicationTestData.DefaultStorageId } }); // Arrange Mocks Mock.Get(amsV3SdkWrapper) .Setup(x => x.AssetCreateOrUpdateAsync(It.IsAny <string>(), It.IsAny <Asset>(), It.IsAny <CancellationToken>())) .ReturnsAsync(new Asset(name: assetName)); Mock.Get(amsV3SdkWrapper) .Setup(x => x.MediaservicesGetAsync(It.IsAny <CancellationToken>())) .ReturnsAsync(amsAccount); Mock.Get(amsV3SdkWrapper) .Setup(x => x.StreamingEndpointsListAsync(It.IsAny <CancellationToken>())) .ReturnsAsync(MockPageSe); Mock.Get(amsV3SdkWrapper) .Setup(x => x.StreamingLocatorListPathsAsync(It.IsAny <string>(), It.IsAny <CancellationToken>())) .ReturnsAsync(Paths); Mock.Get(amsV3SdkWrapper) .Setup(x => x.StreamingLocatorCreateAsync(It.IsAny <string>(), It.IsAny <StreamingLocator>(), It.IsAny <CancellationToken>())) .ReturnsAsync(new StreamingLocator(assetName: "asset45", streamingPolicyName: locatorCreateDTO.StreamingPolicyName, defaultContentKeyPolicyName: locatorCreateDTO.ContentKeyPolicyName, contentKeys: new List <StreamingLocatorContentKey>() { new StreamingLocatorContentKey(Guid.NewGuid(), StreamingLocatorContentKeyType.CommonEncryptionCenc), new StreamingLocatorContentKey(Guid.NewGuid(), StreamingLocatorContentKeyType.CommonEncryptionCbcs) })); Mock.Get(amsV3SdkWrapper) .Setup(x => x.ContentKeyPolicyGetAsync(locatorCreateDTO.ContentKeyPolicyName, It.IsAny <CancellationToken>())) .ReturnsAsync(contentKeyPolicy); Mock.Get(amsV3SdkWrapper) .Setup(x => x.StreamingPolicyGetAsync(MediaServicesV3PublicationTestData.GoodDRMStreamingPolicy, It.IsAny <CancellationToken>())) .ReturnsAsync(new StreamingPolicy()); Mock.Get(amsV3SdkWrapper) .Setup(x => x.ContentKeyPolicyCreateOrUpdateAsync(It.IsAny <string>(), It.IsAny <IEnumerable <ContentKeyPolicyOption> >(), It.IsAny <string>(), It.IsAny <CancellationToken>())); Mock.Get(settingsProvider) .Setup(x => x.GetAppSettingsValue("AmsDrmOpenIdConnectDiscoveryDocument")) .Returns(MediaServicesV3PublicationTestData.AmsDrmOpenIdConnectDiscoveryDocument); Mock.Get(settingsProvider) .Setup(x => x.GetAppSettingsValue("AmsDrmFairPlayPfxPassword")) .Returns(MediaServicesV3PublicationTestData.AmsDrmFairPlayPfxPassword); Mock.Get(settingsProvider) .Setup(x => x.GetAppSettingsValue("AmsDrmFairPlayAskHex")) .Returns(MediaServicesV3PublicationTestData.AmsDrmFairPlayAskHex); Mock.Get(settingsProvider) .Setup(x => x.GetAppSettingsValue("AmsDrmFairPlayCertificateB64")) .Returns(MediaServicesV3PublicationTestData.AmsDrmFairPlayCertAsSecretStringStatic); Mock.Get(settingsProvider) .Setup(x => x.GetAppSettingsValue("AmsDrmEnableContentKeyPolicyUpdate")) .Returns(updatePolicy); IMediaServicesV3ContentKeyPolicyService amsContentKeyPolService2 = new MediaServicesV3ContentKeyPolicyService(settingsProvider, LogKey); IMediaServicesV3CustomStreamingPolicyService amsStreamingPolService2 = new MediaServicesV3CustomStreamingPolicyService(); // Act var amsV3PubServices = new MediaServicesV3PublicationService(amsContentKeyPolService2, amsStreamingPolService2, amsV3SdkWrapper, storageService, settingsProvider, Log); // Assert var result = await amsV3PubServices.LocatorCreateAsync( locatorCreateDTO.ContainerUri, locatorCreateDTO.StreamingPolicyName, locatorCreateDTO.ContentKeyPolicyName, locatorCreateDTO.TimeBasedFilter, locatorCreateDTO.OperationContext, locatorCreateDTO.GenerateAudioFilters).ConfigureAwait(false); result.ShouldBeOfType <ServiceOperationResultMediaServicesV3LocatorCreate>(); result.LocatorName.ShouldBeOfType <string>(); }
public async void MediaServicesV3ServiceCreateLocatorFailureTests(RequestMediaServicesLocatorCreateDTO locatorCreateDTO, bool expectedValue, Type typeException) { // Arrange var amsV3SdkWrapper = Mock.Of <IMediaServicesV3SdkWrapper>(); var storageService = Mock.Of <IStorageService>(); var amsContentKeyPolService = Mock.Of <IMediaServicesV3ContentKeyPolicyService>(); var settingsProvider = Mock.Of <ISettingsProvider>(); string assetName = "myassetname"; var amsAccount = new MediaService(storageAccounts: new List <StorageAccount>() { new StorageAccount() { Id = MediaServicesV3PublicationTestData.DefaultStorageId } }); // Arrange Mocks Mock.Get(settingsProvider) .Setup(x => x.GetAppSettingsValue(EnvironmentTypeConstants.EnvironmentTypeSettingName)) .Returns(EnvironmentTypeConstants.EnvironmentTypeDevelopment); Mock.Get(settingsProvider) .Setup(x => x.GetAppSettingsValue("AmsDrmEnableContentKeyPolicyUpdate")) .Returns("true"); Mock.Get(amsV3SdkWrapper) .Setup(x => x.AssetCreateOrUpdateAsync(It.IsAny <string>(), It.IsAny <Asset>(), It.IsAny <CancellationToken>())) .ReturnsAsync(new Asset(name: assetName)); Mock.Get(amsV3SdkWrapper) .Setup(x => x.AssetFiltersCreateOrUpdateAsync(It.IsAny <string>(), It.IsAny <string>(), TimingIsWrong(), It.IsAny <CancellationToken>())) .ThrowsAsync(new Exception()); Mock.Get(amsV3SdkWrapper) .Setup(x => x.MediaservicesGetAsync(It.IsAny <CancellationToken>())) .ReturnsAsync(amsAccount); Mock.Get(amsV3SdkWrapper) .Setup(x => x.StreamingEndpointsListAsync(It.IsAny <CancellationToken>())) .ReturnsAsync(MockPageSe); Mock.Get(amsV3SdkWrapper) .Setup(x => x.StreamingLocatorListPathsAsync(It.IsAny <string>(), It.IsAny <CancellationToken>())) .ReturnsAsync(Paths); Mock.Get(amsV3SdkWrapper) .Setup(x => x.StreamingLocatorCreateAsync(It.IsAny <string>(), It.IsAny <StreamingLocator>(), It.IsAny <CancellationToken>())) .ReturnsAsync(new StreamingLocator(assetName: "asset45", streamingPolicyName: locatorCreateDTO.StreamingPolicyName, defaultContentKeyPolicyName: locatorCreateDTO.ContentKeyPolicyName, contentKeys: new List <StreamingLocatorContentKey>())); if (locatorCreateDTO.ContentKeyPolicyName == MediaServicesV3PublicationTestData.GoodDataDtoDRM.ContentKeyPolicyName) { ContentKeyPolicy pol = null; Mock.Get(amsV3SdkWrapper) .Setup(x => x.ContentKeyPolicyGetAsync(MediaServicesV3PublicationTestData.GoodDataDtoDRM.ContentKeyPolicyName, It.IsAny <CancellationToken>())) .ReturnsAsync(pol); Mock.Get(amsV3SdkWrapper) .Setup(x => x.ContentKeyPolicyCreateOrUpdateAsync(It.IsAny <string>(), It.IsAny <List <ContentKeyPolicyOption> >(), It.IsAny <string>(), It.IsAny <CancellationToken>())) .ThrowsAsync(new Exception()); } Mock.Get(amsV3SdkWrapper) .Setup(x => x.AssetFiltersCreateOrUpdateAsync(It.IsAny <string>(), It.IsAny <string>(), It.IsAny <AssetFilter>(), It.IsAny <CancellationToken>())) .ThrowsAsync(new Exception()); Mock.Get(amsContentKeyPolService) .Setup(x => x.GetContentKeyPolicyFromMemory(It.IsAny <string>())) .Returns(new MediaServicesV3CustomContentKeyPolicyMultiDrmKey( MediaServicesV3PublicationTestData.AmsDrmOpenIdConnectDiscoveryDocument, MediaServicesV3PublicationTestData.AmsDrmFairPlayPfxPassword, MediaServicesV3PublicationTestData.AmsDrmFairPlayAskHex, MediaServicesV3PublicationTestData.AmsDrmFairPlayPfx)); IMediaServicesV3CustomStreamingPolicyService amsStreamingPolService2 = new MediaServicesV3CustomStreamingPolicyService(); // Act var amsV3PubServices = new MediaServicesV3PublicationService(amsContentKeyPolService, amsStreamingPolService2, amsV3SdkWrapper, storageService, settingsProvider, Log); // Assert if (expectedValue) { } else { _ = await Xunit.Assert.ThrowsAsync(typeException, async() => await amsV3PubServices.LocatorCreateAsync( locatorCreateDTO.ContainerUri, locatorCreateDTO.StreamingPolicyName, locatorCreateDTO.ContentKeyPolicyName, locatorCreateDTO.TimeBasedFilter, locatorCreateDTO.OperationContext, locatorCreateDTO.GenerateAudioFilters).ConfigureAwait(false)).ConfigureAwait(false); } }
public static async Task <IActionResult> Run( [HttpTrigger(AuthorizationLevel.Function, "post", Route = null)] HttpRequest req, ILogger log) { log.LogInformation($"AMS v3 Function - PublishAsset was triggered!"); string requestBody = new StreamReader(req.Body).ReadToEnd(); dynamic data = JsonConvert.DeserializeObject(requestBody); // Validate input objects if (data.assetName == null) { return(new BadRequestObjectResult("Please pass assetName in the input object")); } if (data.streamingPolicyName == null) { return(new BadRequestObjectResult("Please pass streamingPolicyName in the input object")); } string assetName = data.assetName; string streamingPolicyName = data.streamingPolicyName; string alternativeMediaId = null; if (data.alternativeMediaId != null) { alternativeMediaId = data.alternativeMediaId; } string contentKeyPolicyName = null; if (data.contentKeyPolicyName != null) { contentKeyPolicyName = data.contentKeyPolicyName; } List <StreamingLocatorContentKey> contentKeys = new List <StreamingLocatorContentKey>(); DateTime startDateTime = new DateTime(0); if (data.startDateTime != null) { startDateTime = data.startDateTime; } DateTime endDateTime = new DateTime(0); if (data.endDateTime != null) { endDateTime = data.endDateTime; } Guid streamingLocatorId = Guid.NewGuid(); if (data.streamingLocatorId != null) { streamingLocatorId = new Guid((string)(data.streamingLocatorId)); } string streamingLocatorName = "streaminglocator-" + streamingLocatorId.ToString(); MediaServicesConfigWrapper amsconfig = new MediaServicesConfigWrapper(); StreamingLocator streamingLocator = null; Asset asset = null; StreamingPolicy streamingPolicy = null; try { IAzureMediaServicesClient client = MediaServicesHelper.CreateMediaServicesClientAsync(amsconfig); asset = client.Assets.Get(amsconfig.ResourceGroup, amsconfig.AccountName, assetName); if (asset == null) { return(new BadRequestObjectResult("Asset not found")); } streamingPolicy = client.StreamingPolicies.Get(amsconfig.ResourceGroup, amsconfig.AccountName, streamingPolicyName); if (streamingPolicy == null) { return(new BadRequestObjectResult("StreamingPolicy not found")); } if (contentKeyPolicyName != null) { ContentKeyPolicy contentKeyPolicy = null; contentKeyPolicy = client.ContentKeyPolicies.Get(amsconfig.ResourceGroup, amsconfig.AccountName, contentKeyPolicyName); if (contentKeyPolicy == null) { return(new BadRequestObjectResult("ContentKeyPolicy not found")); } } if (data.contentKeys != null) { JsonConverter[] jsonConverters = { new MediaServicesHelperJsonReader() }; contentKeys = JsonConvert.DeserializeObject <List <StreamingLocatorContentKey> >(data.contentKeys.ToString(), jsonConverters); } streamingLocator = new StreamingLocator() { AssetName = assetName, StreamingPolicyName = streamingPolicyName, AlternativeMediaId = alternativeMediaId, DefaultContentKeyPolicyName = contentKeyPolicyName, StartTime = null, EndTime = null, StreamingLocatorId = streamingLocatorId, }; if (!startDateTime.Equals(new DateTime(0))) { streamingLocator.StartTime = startDateTime; } if (!endDateTime.Equals(new DateTime(0))) { streamingLocator.EndTime = endDateTime; } if (contentKeys.Count != 0) { streamingLocator.ContentKeys = contentKeys; } streamingLocator.Validate(); client.StreamingLocators.Create(amsconfig.ResourceGroup, amsconfig.AccountName, streamingLocatorName, streamingLocator); } catch (ApiErrorException e) { log.LogError($"ERROR: AMS API call failed with error code: {e.Body.Error.Code} and message: {e.Body.Error.Message}"); return(new BadRequestObjectResult("AMS API call error: " + e.Message + "\nError Code: " + e.Body.Error.Code + "\nMessage: " + e.Body.Error.Message)); } catch (Exception e) { log.LogError($"ERROR: Exception with message: {e.Message}"); return(new BadRequestObjectResult("Error: " + e.Message)); } return((ActionResult) new OkObjectResult(new { streamingLocatorName = streamingLocatorName, streamingLocatorId = streamingLocator.StreamingLocatorId.ToString() })); }
/// <summary> /// Run the sample async. /// </summary> /// <param name="config">The param is of type ConfigWrapper. This class reads values from local configuration file.</param> /// <returns></returns> private static async Task RunAsync(ConfigWrapper config) { IAzureMediaServicesClient client; try { client = await CreateMediaServicesClientAsync(config); } catch (Exception e) { Console.Error.WriteLine("TIP: Make sure that you have filled out the appsettings.json file before running this sample."); Console.Error.WriteLine($"{e.Message}"); return; } // Set the polling interval for long running operations to 2 seconds. // The default value is 30 seconds for the .NET client SDK client.LongRunningOperationRetryTimeout = 2; // Creating a unique suffix so that we don't have name collisions if you run the sample // multiple times without cleaning up. string uniqueness = Guid.NewGuid().ToString().Substring(0, 13); string liveEventName = "liveevent-" + uniqueness; string assetName = "archiveAsset" + uniqueness; string liveOutputName = "liveOutput" + uniqueness; string drvStreamingLocatorName = "streamingLocator" + uniqueness; string archiveStreamingLocatorName = "fullLocator-" + uniqueness; string drvAssetFilterName = "filter-" + uniqueness; string streamingEndpointName = "default"; // Change this to your Endpoint name. EventProcessorHost eventProcessorHost = null; bool stopEndpoint = false; try { // Getting the mediaServices account so that we can use the location to create the // LiveEvent and StreamingEndpoint MediaService mediaService = await client.Mediaservices.GetAsync(config.ResourceGroup, config.AccountName); Console.WriteLine($"Creating a live event named {liveEventName}"); Console.WriteLine(); // Note: When creating a LiveEvent, you can specify allowed IP addresses in one of the following formats: // IpV4 address with 4 numbers // CIDR address range IPRange allAllowIPRange = new IPRange( name: "AllowAll", address: "0.0.0.0", subnetPrefixLength: 0 ); // Create the LiveEvent input IP access control. LiveEventInputAccessControl liveEventInputAccess = new LiveEventInputAccessControl { Ip = new IPAccessControl( allow: new IPRange[] { allAllowIPRange } ) }; // Create the LiveEvent Preview IP access control LiveEventPreview liveEventPreview = new LiveEventPreview { AccessControl = new LiveEventPreviewAccessControl( ip: new IPAccessControl( allow: new IPRange[] { allAllowIPRange } ) ) }; // To get the same ingest URL for the same LiveEvent name: // 1. Set vanityUrl to true so you have ingest like: // rtmps://liveevent-hevc12-eventgridmediaservice-usw22.channel.media.azure.net:2935/live/522f9b27dd2d4b26aeb9ef8ab96c5c77 // 2. Set accessToken to a desired GUID string (with or without hyphen) LiveEvent liveEvent = new LiveEvent( location: mediaService.Location, description: "Sample LiveEvent for testing", vanityUrl: false, encoding: new LiveEventEncoding( // Set this to Standard to enable a trans-coding LiveEvent, and None to enable a pass-through LiveEvent encodingType: LiveEventEncodingType.Premium1080p, presetName: null ), input: new LiveEventInput(LiveEventInputProtocol.RTMP, liveEventInputAccess), preview: liveEventPreview, streamOptions: new List <StreamOptionsFlag?>() { // Set this to Default or Low Latency // When using Low Latency mode, you must configure the Azure Media Player to use the // quick start heuristic profile or you won't notice the change. // In the AMP player client side JS options, set - heuristicProfile: "Low Latency Heuristic Profile". // To use low latency optimally, you should tune your encoder settings down to 1 second GOP size instead of 2 seconds. // StreamOptionsFlag.LowLatency } ); Console.WriteLine($"Creating the LiveEvent, be patient this can take time..."); // When autostart is set to true, the Live Event will be started after creation. // That means, the billing starts as soon as the Live Event starts running. // You must explicitly call Stop on the Live Event resource to halt further billing. // The following operation can sometimes take awhile. Be patient. liveEvent = await client.LiveEvents.CreateAsync(config.ResourceGroup, config.AccountName, liveEventName, liveEvent, autoStart : true); // Start monitoring LiveEvent events. try { // Please refer README for Event Hub and storage settings. Console.WriteLine("Starting monitoring LiveEvent events..."); string StorageConnectionString = string.Format("DefaultEndpointsProtocol=https;AccountName={0};AccountKey={1}", config.StorageAccountName, config.StorageAccountKey); // Create a new host to process events from an Event Hub. Console.WriteLine("Creating a new host to process events from an Event Hub..."); eventProcessorHost = new EventProcessorHost(config.EventHubName, PartitionReceiver.DefaultConsumerGroupName, config.EventHubConnectionString, StorageConnectionString, config.StorageContainerName); // Registers the Event Processor Host and starts receiving messages. await eventProcessorHost.RegisterEventProcessorFactoryAsync(new MediaServicesEventProcessorFactory(liveEventName), EventProcessorOptions.DefaultOptions); } catch (Exception e) { Console.WriteLine("Failed to connect to Event Hub, please refer README for Event Hub and storage settings. Skipping event monitoring..."); Console.WriteLine(e.Message); } // Get the input endpoint to configure the on premise encoder with string ingestUrl = liveEvent.Input.Endpoints.First().Url; Console.WriteLine($"The ingest url to configure the on premise encoder with is:"); Console.WriteLine($"\t{ingestUrl}"); Console.WriteLine(); // Use the previewEndpoint to preview and verify // that the input from the encoder is actually being received string previewEndpoint = liveEvent.Preview.Endpoints.First().Url; Console.WriteLine($"The preview url is:"); Console.WriteLine($"\t{previewEndpoint}"); Console.WriteLine(); Console.WriteLine($"Open the live preview in your browser and use the Azure Media Player to monitor the preview playback:"); Console.WriteLine($"\thttps://ampdemo.azureedge.net/?url={previewEndpoint}"); // &heuristicprofile=lowlatency"); Console.WriteLine(); Console.WriteLine("Start the live stream now, sending the input to the ingest url and verify that it is arriving with the preview url."); Console.WriteLine("IMPORTANT TIP!: Make ABSOLUTLEY CERTAIN that the video is flowing to the Preview URL before continuing!"); Console.WriteLine("******************************"); Console.WriteLine("* Press ENTER to continue... *"); Console.WriteLine("******************************"); Console.WriteLine(); Console.Out.Flush(); var ignoredInput = Console.ReadLine(); // Create an Asset for the LiveOutput to use Console.WriteLine($"Creating an asset named {assetName}"); Console.WriteLine(); Asset asset = await client.Assets.CreateOrUpdateAsync(config.ResourceGroup, config.AccountName, assetName, new Asset()); //AssetFilter drvAssetFilter = new AssetFilter( // presentationTimeRange: new PresentationTimeRange( // forceEndTimestamp:false, // // 300 seconds sliding window // presentationWindowDuration: 3000000000L, // // This value defines the latest live position that a client can seek back to 10 seconds, must be smaller than sliding window. // liveBackoffDuration: 100000000L) //); //drvAssetFilter = await client.AssetFilters.CreateOrUpdateAsync(config.ResourceGroup, config.AccountName, // assetName, drvAssetFilterName, drvAssetFilter); // Create the LiveOutput string manifestName = "output"; Console.WriteLine($"Creating a live output named {liveOutputName}"); Console.WriteLine(); // withArchiveWindowLength: Can be set from 3 minutes to 25 hours. content that falls outside of ArchiveWindowLength // is continuously discarded from storage and is non-recoverable. For a full event archive, set to the maximum, 25 hours. LiveOutput liveOutput = new LiveOutput(assetName: asset.Name, manifestName: manifestName, archiveWindowLength: TimeSpan.FromHours(2)); liveOutput = await client.LiveOutputs.CreateAsync(config.ResourceGroup, config.AccountName, liveEventName, liveOutputName, liveOutput); // Create the StreamingLocator Console.WriteLine($"Creating a streaming locator named {drvStreamingLocatorName}"); Console.WriteLine(); //IList<string> filters = new List<string>(); ////filters.Add(drvAssetFilterName); //StreamingLocator locator = await client.StreamingLocators.CreateAsync(config.ResourceGroup, // config.AccountName, // drvStreamingLocatorName, // new StreamingLocator // { // AssetName = assetName, // StreamingPolicyName = PredefinedStreamingPolicy.ClearStreamingOnly, // Filters = filters // Associate filters with StreamingLocator. // }); // Set a token signing key that you want to use TokenSigningKey = Convert.FromBase64String(config.SymmetricKeyPR); // Create the content key policy that configures how the content key is delivered to end clients // via the Key Delivery component of Azure Media Services. // We are using the ContentKeyIdentifierClaim in the ContentKeyPolicy which means that the token presented // to the Key Delivery Component must have the identifier of the content key in it. ContentKeyPolicy policy = await GetOrCreateContentKeyPolicyAsync(client, config.ResourceGroup, config.AccountName, ContentKeyPolicyName, TokenSigningKey); // Sets StreamingLocator.StreamingPolicyName to "Predefined_MultiDrmCencStreaming" policy. StreamingLocator locator = await CreateStreamingLocatorAsync(client, config.ResourceGroup, config.AccountName, asset.Name, drvStreamingLocatorName, ContentKeyPolicyName); // In this example, we want to play the PlayReady (CENC) encrypted stream. // We need to get the key identifier of the content key where its type is CommonEncryptionCenc. string keyIdentifier = locator.ContentKeys.Where(k => k.Type == StreamingLocatorContentKeyType.CommonEncryptionCenc).First().Id.ToString(); Console.WriteLine($"KeyIdentifier = {keyIdentifier}"); // In order to generate our test token we must get the ContentKeyId to put in the ContentKeyIdentifierClaim claim. string token = GetTokenAsync(Issuer, Audience, keyIdentifier, TokenSigningKey); StreamingEndpoint streamingEndpoint = await client.StreamingEndpoints.GetAsync(config.ResourceGroup, config.AccountName, DefaultStreamingEndpointName); // If it's not running, Start it. if (streamingEndpoint.ResourceState != StreamingEndpointResourceState.Running) { Console.WriteLine("Streaming Endpoint was Stopped, restarting now.."); await client.StreamingEndpoints.StartAsync(config.ResourceGroup, config.AccountName, streamingEndpointName); // Since we started the endpoint, we should stop it in cleanup. stopEndpoint = true; } string dashPath = await GetDASHStreamingUrlAsync(client, config.ResourceGroup, config.AccountName, locator.Name, streamingEndpoint); if (dashPath.Length > 0) { Console.WriteLine("---Encrypted URL for IE or Edge---"); Console.WriteLine($"\thttps://ampdemo.azureedge.net/?url={dashPath}&playready=true&token=Bearer%3D{token}"); Console.WriteLine("---Encrypted URL for Chrome or Firefox---"); Console.WriteLine($"\thttps://ampdemo.azureedge.net/?url={dashPath}&widevine=true&token=Bearer%3D{token}"); Console.WriteLine("-------------------"); Console.WriteLine("If you see an error in Azure Media Player, wait a few moments and try again."); Console.WriteLine("Continue experimenting with the stream until you are ready to finish."); Console.WriteLine(); Console.WriteLine("***********************************************"); Console.WriteLine("* Press ENTER anytime to stop the LiveEvent. *"); Console.WriteLine("***********************************************"); Console.WriteLine(); Console.Out.Flush(); ignoredInput = Console.ReadLine(); Console.WriteLine("Cleaning up LiveEvent and output..."); await CleanupLiveEventAndOutputAsync(client, config.ResourceGroup, config.AccountName, liveEventName); Console.WriteLine("The LiveOutput and LiveEvent are now deleted. The event is available as an archive and can still be streamed."); // If we started the endpoint, we'll stop it. Otherwise, we'll keep the endpoint running and print urls // that can be played even after this sample ends. if (!stopEndpoint) { StreamingLocator archiveLocator = await client.StreamingLocators.CreateAsync(config.ResourceGroup, config.AccountName, archiveStreamingLocatorName, new StreamingLocator { AssetName = assetName, StreamingPolicyName = PredefinedStreamingPolicy.ClearStreamingOnly }); Console.WriteLine("To playback the archived files, Use the following urls:"); await PrintPaths(client, config.ResourceGroup, config.AccountName, archiveStreamingLocatorName, streamingEndpoint); } } } catch (ApiErrorException e) { Console.WriteLine("Hit ApiErrorException"); Console.WriteLine($"\tCode: {e.Body.Error.Code}"); Console.WriteLine($"\tCode: {e.Body.Error.Message}"); Console.WriteLine(); Console.WriteLine("Exiting, cleanup may be necessary..."); Console.ReadLine(); } finally { await CleanupLiveEventAndOutputAsync(client, config.ResourceGroup, config.AccountName, liveEventName); await CleanupLocatorAsync(client, config.ResourceGroup, config.AccountName, drvStreamingLocatorName); // Stop event monitoring. if (eventProcessorHost != null) { await eventProcessorHost.UnregisterEventProcessorAsync(); } if (stopEndpoint) { // Because we started the endpoint, we'll stop it. await client.StreamingEndpoints.StopAsync(config.ResourceGroup, config.AccountName, streamingEndpointName); } else { // We will keep the endpoint running because it was not started by us. There are costs to keep it running. // Please refer https://azure.microsoft.com/en-us/pricing/details/media-services/ for pricing. Console.WriteLine($"The endpoint {streamingEndpointName} is running. To halt further billing on the endpoint, please stop it in azure portal or AMS Explorer."); } } }
/// <summary> /// Run the sample async. /// </summary> /// <param name="config">The parm is of type ConfigWrapper. This class reads values from local configuration file.</param> /// <returns></returns> // <RunAsync> private static async Task RunAsync(ConfigWrapper config) { IAzureMediaServicesClient client = await CreateMediaServicesClientAsync(config); // Set the polling interval for long running operations to 2 seconds. // The default value is 30 seconds for the .NET client SDK client.LongRunningOperationRetryTimeout = 2; // Creating a unique suffix so that we don't have name collisions if you run the sample // multiple times without cleaning up. string uniqueness = Guid.NewGuid().ToString("N"); string jobName = $"job-{uniqueness}"; string locatorName = $"locator-{uniqueness}"; string outputAssetName = $"output-{uniqueness}"; // Ensure that you have the desired encoding Transform. This is really a one time setup operation. Transform transform = await GetOrCreateTransformAsync(client, config.ResourceGroup, config.AccountName, AdaptiveStreamingTransformName); // Output from the encoding Job must be written to an Asset, so let's create one Asset outputAsset = await CreateOutputAssetAsync(client, config.ResourceGroup, config.AccountName, outputAssetName); Job job = await SubmitJobAsync(client, config.ResourceGroup, config.AccountName, AdaptiveStreamingTransformName, outputAsset.Name, jobName); // In this demo code, we will poll for Job status // Polling is not a recommended best practice for production applications because of the latency it introduces. // Overuse of this API may trigger throttling. Developers should instead use Event Grid. job = await WaitForJobToFinishAsync(client, config.ResourceGroup, config.AccountName, AdaptiveStreamingTransformName, jobName); if (job.State == JobState.Finished) { Console.WriteLine("Job finished."); if (!Directory.Exists(OutputFolderName)) { Directory.CreateDirectory(OutputFolderName); } // Generate a new random token signing key to use RNGCryptoServiceProvider rng = new RNGCryptoServiceProvider(); rng.GetBytes(TokenSigningKey); //Create the content key policy that configures how the content key is delivered to end clients // via the Key Delivery component of Azure Media Services. ContentKeyPolicy policy = await GetOrCreateContentKeyPolicyAsync(client, config.ResourceGroup, config.AccountName, ContentKeyPolicyName); StreamingLocator locator = await CreateStreamingLocatorAsync(client, config.ResourceGroup, config.AccountName, outputAsset.Name, locatorName, ContentKeyPolicyName); // We are using the ContentKeyIdentifierClaim in the ContentKeyPolicy which means that the token presented // to the Key Delivery Component must have the identifier of the content key in it. Since we didn't specify // a content key when creating the StreamingLocator, the system created a random one for us. In order to // generate our test token we must get the ContentKeyId to put in the ContentKeyIdentifierClaim claim. string keyIdentifier = locator.ContentKeys.First().Id.ToString(); string token = GetTokenAsync(Issuer, Audience, keyIdentifier, TokenSigningKey); string dashPath = await GetDASHStreamingUrlAsync(client, config.ResourceGroup, config.AccountName, locator.Name); Console.WriteLine("Copy and paste the following URL in your browser to play back the file in the Azure Media Player."); Console.WriteLine("Note, the player is set to use the AES token and the Bearer token is specified. "); Console.WriteLine(); Console.WriteLine($"https://ampdemo.azureedge.net/?url={dashPath}&aes=true&aestoken=Bearer%3D{token}"); Console.WriteLine(); } Console.WriteLine("When finished press enter to cleanup."); Console.Out.Flush(); Console.ReadLine(); Console.WriteLine("Cleaning up..."); await CleanUpAsync(client, config.ResourceGroup, config.AccountName, AdaptiveStreamingTransformName, ContentKeyPolicyName); }
public static async Task <IActionResult> Run( [HttpTrigger(AuthorizationLevel.Function, "post", Route = null)] HttpRequest req, ILogger log) { log.LogInformation($"AMS v3 Function - CreateContentKeyPolicy was triggered!"); string requestBody = new StreamReader(req.Body).ReadToEnd(); dynamic data = JsonConvert.DeserializeObject(requestBody); if (data.contentKeyPolicyName == null) { return(new BadRequestObjectResult("Please pass contentKeyPolicyName in the input object")); } string contentKeyPolicyName = data.contentKeyPolicyName; string contentKeyPolicyDescription = null; if (data.contentKeyPolicyDescription == null) { contentKeyPolicyDescription = data.contentKeyPolicyDescription; } string mode = data.mode; if (mode != "simple" && mode != "advanced") { return(new BadRequestObjectResult("Please pass valid mode in the input object")); } // // Simple Mode // if (mode == "simple") { if (data.policyOptionName == null) { return(new BadRequestObjectResult("Please pass policyOptionName in the input object")); } if (data.openRestriction == null) { return(new BadRequestObjectResult("Please pass openRestriction in the input object")); } if (data.openRestriction == false) { if (data.audience == null && data.issuer == null && data.tokenType == null && data.tokenKeyType == null && data.tokenKey == null) { return(new BadRequestObjectResult("Please pass required parameters for Token Restriction in the input object")); } } } // // Advanced Mode // if (mode == "advanced") { if (data.contentKeyPolicyOptions == null) { return(new BadRequestObjectResult("Please pass contentKeyPolicyOptions in the input object")); } } MediaServicesConfigWrapper amsconfig = new MediaServicesConfigWrapper(); ContentKeyPolicy policy = null; JsonConverter[] jsonReaders = { new MediaServicesHelperJsonReader(), new MediaServicesHelperTimeSpanJsonConverter() }; try { IAzureMediaServicesClient client = MediaServicesHelper.CreateMediaServicesClientAsync(amsconfig); policy = client.ContentKeyPolicies.Get(amsconfig.ResourceGroup, amsconfig.AccountName, contentKeyPolicyName); if (policy == null) { List <ContentKeyPolicyOption> options = new List <ContentKeyPolicyOption>(); if (mode == "simple") { ContentKeyPolicyOption option = new ContentKeyPolicyOption(); option.Name = data.policyOptionName; // Restrictions if ((bool)data.openRestriction) { option.Restriction = new ContentKeyPolicyOpenRestriction(); } else { ContentKeyPolicyTokenRestriction restriction = new ContentKeyPolicyTokenRestriction(); restriction.Audience = data.audience; restriction.Issuer = data.issuer; string tokenType = data.tokenType; switch (tokenType) { case "Jwt": restriction.RestrictionTokenType = ContentKeyPolicyRestrictionTokenType.Jwt; break; case "Swt": restriction.RestrictionTokenType = ContentKeyPolicyRestrictionTokenType.Swt; break; default: return(new BadRequestObjectResult("Please pass valid tokenType in the input object")); } string tokenKeyType = data.tokenKeyType; switch (tokenKeyType) { case "Symmetric": restriction.PrimaryVerificationKey = new ContentKeyPolicySymmetricTokenKey(Convert.FromBase64String(data.tokenKey.ToString())); break; case "X509": restriction.PrimaryVerificationKey = new ContentKeyPolicyX509CertificateTokenKey(Convert.FromBase64String(data.tokenKey.ToString())); break; case "RSA": restriction.PrimaryVerificationKey = new ContentKeyPolicyRsaTokenKey(); break; default: return(new BadRequestObjectResult("Please pass valid tokenKeyType in the input object")); } if (data.tokenClaims != null) { restriction.RequiredClaims = new List <ContentKeyPolicyTokenClaim>(); String[] tokenClaims = data.tokenClaims.ToString().Split(';'); foreach (string tokenClaim in tokenClaims) { String[] tokenClaimKVP = tokenClaim.Split('='); if (tokenClaimKVP.Length == 2) { restriction.RequiredClaims.Add(new ContentKeyPolicyTokenClaim(tokenClaimKVP[0], tokenClaimKVP[1] == "null" ? null : tokenClaimKVP[1])); } else if (tokenClaimKVP.Length == 1) { restriction.RequiredClaims.Add(new ContentKeyPolicyTokenClaim(tokenClaimKVP[0])); } else { return(new BadRequestObjectResult("Please pass valid tokenClaims in the input object")); } } } if (data.openIdConnectDiscoveryDocument != null) { restriction.OpenIdConnectDiscoveryDocument = data.openIdConnectDiscoveryDocument; } option.Restriction = restriction; } // Configuration string configurationType = data.configurationType; switch (configurationType) { case "ClearKey": option.Configuration = new ContentKeyPolicyClearKeyConfiguration(); break; case "FairPlay": ContentKeyPolicyFairPlayConfiguration configFairPlay = new ContentKeyPolicyFairPlayConfiguration(); configFairPlay.Ask = Convert.FromBase64String(data.fairPlayAsk); configFairPlay.FairPlayPfx = data.fairPlayPfx; configFairPlay.FairPlayPfxPassword = data.fairPlayPfxPassword; switch (data.faiPlayRentalAndLeaseKeyType) { case "Undefined": configFairPlay.RentalAndLeaseKeyType = ContentKeyPolicyFairPlayRentalAndLeaseKeyType.Undefined; break; case "PersistentLimited": configFairPlay.RentalAndLeaseKeyType = ContentKeyPolicyFairPlayRentalAndLeaseKeyType.PersistentLimited; break; case "PersistentUnlimited": configFairPlay.RentalAndLeaseKeyType = ContentKeyPolicyFairPlayRentalAndLeaseKeyType.PersistentUnlimited; break; default: return(new BadRequestObjectResult("Please pass valid faiPlayRentalAndLeaseKeyType in the input object")); } configFairPlay.RentalDuration = data.faiPlayRentalDuration; break; case "PlayReady": ContentKeyPolicyPlayReadyConfiguration configPlayReady = new ContentKeyPolicyPlayReadyConfiguration(); configPlayReady.Licenses = JsonConvert.DeserializeObject <List <ContentKeyPolicyPlayReadyLicense> >(data.playReadyTemplates.ToString(), jsonReaders); if (data.playReadyResponseCustomData != null) { configPlayReady.ResponseCustomData = data.playReadyResponseCustomData; } option.Configuration = configPlayReady; break; case "Widevine": ContentKeyPolicyWidevineConfiguration configWideVine = JsonConvert.DeserializeObject <ContentKeyPolicyWidevineConfiguration>(data.widevineTemplate.ToString(), jsonReaders); option.Configuration = configWideVine; break; default: return(new BadRequestObjectResult("Please pass valid configurationType in the input object")); } options.Add(option); } else if (mode == "advanced") { options = JsonConvert.DeserializeObject <List <ContentKeyPolicyOption> >(data.contentKeyPolicyOptions.ToString(), jsonReaders); } foreach (ContentKeyPolicyOption o in options) { o.Validate(); } policy = client.ContentKeyPolicies.CreateOrUpdate(amsconfig.ResourceGroup, amsconfig.AccountName, contentKeyPolicyName, options, contentKeyPolicyDescription); } } catch (ApiErrorException e) { log.LogError($"ERROR: AMS API call failed with error code: {e.Body.Error.Code} and message: {e.Body.Error.Message}"); return(new BadRequestObjectResult("AMS API call error: " + e.Message + "\nError Code: " + e.Body.Error.Code + "\nMessage: " + e.Body.Error.Message)); } catch (Exception e) { log.LogError($"ERROR: Exception with message: {e.Message}"); return(new BadRequestObjectResult("Error: " + e.Message)); } return((ActionResult) new OkObjectResult(new { policyId = policy.PolicyId })); }
public void ContentKeyPolicyComboTest() { using (MockContext context = this.StartMockContextAndInitializeClients(this.GetType())) { try { CreateMediaServicesAccount(); // List ContentKeyPolicies, which should be empty var contentKeyPolicies = MediaClient.ContentKeyPolicies.List(ResourceGroup, AccountName); Assert.Empty(contentKeyPolicies); string policyName = TestUtilities.GenerateName("ContentKeyPolicy"); string policyDescription = "Test policy"; // Try to get the policy, which should not exist Assert.Equal(System.Net.HttpStatusCode.NotFound, Assert.Throws <ErrorResponseException>(() => MediaClient.ContentKeyPolicies.Get(ResourceGroup, AccountName, policyName)).Response.StatusCode); // Create the policy ContentKeyPolicyOption[] options = new ContentKeyPolicyOption[] { new ContentKeyPolicyOption(new ContentKeyPolicyClearKeyConfiguration(), new ContentKeyPolicyOpenRestriction()) }; ContentKeyPolicy createdPolicy = MediaClient.ContentKeyPolicies.CreateOrUpdate(ResourceGroup, AccountName, policyName, options, policyDescription); ValidateContentKeyPolicy(createdPolicy, policyName, policyDescription, options); // List ContentKeyPolicies and validate the created policy shows up contentKeyPolicies = MediaClient.ContentKeyPolicies.List(ResourceGroup, AccountName); Assert.Single(contentKeyPolicies); ValidateContentKeyPolicy(createdPolicy, policyName, policyDescription, options); // Get the newly created policy ContentKeyPolicy contentKeyPolicy = MediaClient.ContentKeyPolicies.Get(ResourceGroup, AccountName, policyName); Assert.NotNull(contentKeyPolicy); ValidateContentKeyPolicy(createdPolicy, policyName, policyDescription, options); // Update the policy var primaryVerificationKey = new ContentKeyPolicySymmetricTokenKey(new byte[32]); ContentKeyPolicyOption[] options2 = new ContentKeyPolicyOption[] { new ContentKeyPolicyOption(new ContentKeyPolicyClearKeyConfiguration(), new ContentKeyPolicyTokenRestriction( "issuer", "audience", primaryVerificationKey, ContentKeyPolicyRestrictionTokenType.Jwt, requiredClaims: new ContentKeyPolicyTokenClaim[] { ContentKeyPolicyTokenClaim.ContentKeyIdentifierClaim })) }; ContentKeyPolicy updatedByPutPolicy = MediaClient.ContentKeyPolicies.CreateOrUpdate(ResourceGroup, AccountName, policyName, options2, policyDescription); ValidateContentKeyPolicy(updatedByPutPolicy, policyName, policyDescription, options2); // List ContentKeyPolicies and validate the updated policy shows up as expected contentKeyPolicies = MediaClient.ContentKeyPolicies.List(ResourceGroup, AccountName); Assert.Single(contentKeyPolicies); ValidateContentKeyPolicy(contentKeyPolicies.First(), policyName, policyDescription, options2); // Get the newly updated policy contentKeyPolicy = MediaClient.ContentKeyPolicies.Get(ResourceGroup, AccountName, policyName); Assert.NotNull(contentKeyPolicy); ValidateContentKeyPolicy(contentKeyPolicy, policyName, policyDescription, options2); // Delete the policy MediaClient.ContentKeyPolicies.Delete(ResourceGroup, AccountName, policyName); // List ContentKeyPolicies, which should be empty again contentKeyPolicies = MediaClient.ContentKeyPolicies.List(ResourceGroup, AccountName); Assert.Empty(contentKeyPolicies); // Try to get the policy, which should not exist Assert.Equal(System.Net.HttpStatusCode.NotFound, Assert.Throws <ErrorResponseException>(() => MediaClient.ContentKeyPolicies.Get(ResourceGroup, AccountName, policyName)).Response.StatusCode); } finally { DeleteMediaServicesAccount(); } } }
public static async Task <HttpResponseData> Run([HttpTrigger(AuthorizationLevel.Function, "get", "post")] HttpRequestData req, FunctionContext executionContext) { var log = executionContext.GetLogger("PublishAsset"); log.LogInformation("C# HTTP trigger function processed a request."); // Get request body data. string requestBody = await new StreamReader(req.Body).ReadToEndAsync(); var data = (RequestBodyModel)JsonConvert.DeserializeObject(requestBody, typeof(RequestBodyModel)); // Return bad request if input asset name is not passed in if (data.AssetName == null) { return(HttpRequest.ResponseBadRequest(req, "Please pass assetName in the request body")); } if (data.StreamingPolicyName == null) { return(HttpRequest.ResponseBadRequest(req, "Please pass streamingPolicyName in the request body")); } ConfigWrapper config = ConfigUtils.GetConfig(); IAzureMediaServicesClient client; try { client = await Authentication.CreateMediaServicesClientAsync(config, log); log.LogInformation("AMS Client created."); } catch (Exception e) { if (e.Source.Contains("ActiveDirectory")) { log.LogError("TIP: Make sure that you have filled out the appsettings.json file before running this sample."); } log.LogError($"{e.Message}"); return(HttpRequest.ResponseBadRequest(req, e.Message)); } // Set the polling interval for long running operations to 2 seconds. // The default value is 30 seconds for the .NET client SDK client.LongRunningOperationRetryTimeout = 2; // Creating a unique suffix so that we don't have name collisions if you run the sample // multiple times without cleaning up. string uniqueness = Guid.NewGuid().ToString().Substring(0, 13); List <StreamingLocatorContentKey> contentKeys = new List <StreamingLocatorContentKey>(); Guid streamingLocatorId = Guid.NewGuid(); if (data.StreamingLocatorId != null) { streamingLocatorId = new Guid((string)(data.StreamingLocatorId)); } string streamingLocatorName = "streaminglocator-" + streamingLocatorId.ToString(); StreamingPolicy streamingPolicy; Asset asset; try { asset = await client.Assets.GetAsync(config.ResourceGroup, config.AccountName, data.AssetName); if (asset == null) { return(HttpRequest.ResponseBadRequest(req, "Asset not found")); } streamingPolicy = await client.StreamingPolicies.GetAsync(config.ResourceGroup, config.AccountName, data.StreamingPolicyName); if (streamingPolicy == null) { return(HttpRequest.ResponseBadRequest(req, "Streaming Policy not found")); } if (data.ContentKeyPolicyName != null) { ContentKeyPolicy contentKeyPolicy = null; contentKeyPolicy = await client.ContentKeyPolicies.GetAsync(config.ResourceGroup, config.AccountName, data.ContentKeyPolicyName); if (contentKeyPolicy == null) { return(HttpRequest.ResponseBadRequest(req, "Content Key Policy not found")); } } if (data.ContentKeys != null) { JsonConverter[] jsonConverters = { new MediaServicesHelperJsonReader() }; contentKeys = JsonConvert.DeserializeObject <List <StreamingLocatorContentKey> >(data.ContentKeys.ToString(), jsonConverters); } var streamingLocator = new StreamingLocator() { AssetName = data.AssetName, StreamingPolicyName = data.StreamingPolicyName, DefaultContentKeyPolicyName = data.ContentKeyPolicyName, StreamingLocatorId = streamingLocatorId, StartTime = data.StartDateTime, EndTime = data.EndDateTime }; if (contentKeys.Count != 0) { streamingLocator.ContentKeys = contentKeys; } streamingLocator.Validate(); await client.StreamingLocators.CreateAsync(config.ResourceGroup, config.AccountName, streamingLocatorName, streamingLocator); } catch (Exception e) { log.LogError("Error when publishing the asset."); log.LogError($"{e.Message}"); return(HttpRequest.ResponseBadRequest(req, e.Message)); } AnswerBodyModel dataOk = new() { StreamingLocatorName = streamingLocatorName, StreamingLocatorId = streamingLocatorId }; return(HttpRequest.ResponseOk(req, dataOk)); } }
/// <summary> /// Run the sample async. /// </summary> /// <param name="config">The parm is of type ConfigWrapper. This class reads values from local configuration file.</param> /// <returns></returns> // <RunAsync> private static async Task RunAsync(ConfigWrapper config) { IAzureMediaServicesClient client = await CreateMediaServicesClientAsync(config); // Set the polling interval for long running operations to 2 seconds. // The default value is 30 seconds for the .NET client SDK client.LongRunningOperationRetryTimeout = 2; try { // Generate a new random token signing key to use RNGCryptoServiceProvider rng = new RNGCryptoServiceProvider(); rng.GetBytes(TokenSigningKey); //Create the content key policy that configures how the content key is delivered to end clients // via the Key Delivery component of Azure Media Services. ContentKeyPolicy policy = EnsureContentKeyPolicyExists(client, config.ResourceGroup, config.AccountName, ContentKeyPolicyName); // Ensure that you have customized encoding Transform. This is really a one time setup operation. Transform adaptiveEncodeTransform = EnsureTransformExists(client, config.ResourceGroup, config.AccountName, transformName, preset: new BuiltInStandardEncoderPreset(EncoderNamedPreset.AdaptiveStreaming)); // Creating a unique suffix so that we don't have name collisions if you run the sample // multiple times without cleaning up. string uniqueness = Guid.NewGuid().ToString().Substring(0, 13); string jobName = "job-" + uniqueness; string inputAssetName = "input-" + uniqueness; string outputAssetName = "output-" + uniqueness; string streamingLocatorName = "locator-" + uniqueness; Asset asset = client.Assets.CreateOrUpdate(config.ResourceGroup, config.AccountName, inputAssetName, new Asset()); var input = new JobInputHttp( baseUri: "https://nimbuscdn-nimbuspm.streaming.mediaservices.windows.net/2b533311-b215-4409-80af-529c3e853622/", files: new List <String> { "Ignite-short.mp4" }, label: "input1" ); Asset outputAsset = CreateOutputAsset(client, config.ResourceGroup, config.AccountName, outputAssetName); Job job = SubmitJob(client, config.ResourceGroup, config.AccountName, transformName, jobName, input, outputAsset.Name); DateTime startedTime = DateTime.Now; job = WaitForJobToFinish(client, config.ResourceGroup, config.AccountName, transformName, jobName); TimeSpan elapsed = DateTime.Now - startedTime; if (job.State == JobState.Finished) { Console.WriteLine("Job finished."); // Now that the content has been encoded, publish it for Streaming by creating // a StreamingLocator. Note that we are using one of the PredefinedStreamingPolicies // which tell the Origin component of Azure Media Services how to publish the content // for streaming. In this case it applies AES Envelople encryption, which is also known // ClearKey encryption (because the key is delivered to the playback client via HTTPS and // not instead a DRM license). StreamingLocator locator = new StreamingLocator( assetName: outputAsset.Name, streamingPolicyName: PredefinedStreamingPolicy.ClearKey, defaultContentKeyPolicyName: ContentKeyPolicyName); client.StreamingLocators.Create(config.ResourceGroup, config.AccountName, streamingLocatorName, locator); // We are using the ContentKeyIdentifierClaim in the ContentKeyPolicy which means that the token presented // to the Key Delivery Component must have the identifier of the content key in it. Since we didn't specify // a content key when creating the StreamingLocator, the system created a random one for us. In order to // generate our test token we must get the ContentKeyId to put in the ContentKeyIdentifierClaim claim. var response = client.StreamingLocators.ListContentKeys(config.ResourceGroup, config.AccountName, streamingLocatorName); string keyIdentifier = response.ContentKeys.First().Id.ToString(); // We can either use the "default" StreamingEndpoint or we can create a new StreamingEndpoint. // Typically we would just ensure that the default endpoint was started but let's create one // here to illustrate how it is done. // Console.WriteLine($"Creating a streaming endpoint named {endpointName}"); // Console.WriteLine(); //StreamingEndpoint streamingEndpoint = new StreamingEndpoint(location: mediaService.Location); var streamingEndpoint = client.StreamingEndpoints.Get(config.ResourceGroup, config.AccountName, "default"); // Get the URls to stream the output var paths = client.StreamingLocators.ListPaths(config.ResourceGroup, config.AccountName, streamingLocatorName); Console.WriteLine("The urls to stream the output from a client:"); Console.WriteLine(); var token = GetToken(Issuer, Audience, keyIdentifier, TokenSigningKey); for (int i = 0; i < paths.StreamingPaths.Count; i++) { UriBuilder uriBuilder = new UriBuilder(); uriBuilder.Scheme = "https"; uriBuilder.Host = streamingEndpoint.HostName; if (paths.StreamingPaths[i].Paths.Count > 0) { //uriBuilder.Path = paths.StreamingPaths[i].Paths[0]; //Console.WriteLine($"\t{paths.StreamingPaths[i].StreamingProtocol}-{paths.StreamingPaths[i].EncryptionScheme}"); //Console.WriteLine($"\t\t{uriBuilder.ToString()}"); //Console.WriteLine(); // Look for just the DASH path and generate a URL for the Azure Media Player to playback the content with the AES token to decrypt. // Note that the JWT token is set to expire in 1 hour. if (paths.StreamingPaths[i].StreamingProtocol == StreamingPolicyStreamingProtocol.Dash) { uriBuilder.Path = paths.StreamingPaths[i].Paths[0]; var dashPath = uriBuilder.ToString(); Console.WriteLine("Open the following URL in your browser to play back the file in the Azure Media Player"); Console.WriteLine($"https://ampdemo.azureedge.net/?url={dashPath}&aes=true&aestoken=Bearer%3D{token}"); Console.WriteLine(); } } } } else if (job.State == JobState.Error) { Console.WriteLine($"ERROR: Job finished with error message: {job.Outputs[0].Error.Message}"); Console.WriteLine($"ERROR: error details: {job.Outputs[0].Error.Details[0].Message}"); } Console.WriteLine("Try Streaming the content using Azure Media Player - https://ampdemo.azureedge.net."); Console.WriteLine("Use the Advanced options to see or modify the AES Bearer token in the AMP demo page. When finished press enter to cleanup."); Console.Out.Flush(); Console.ReadLine(); Console.WriteLine("Cleaning up..."); Cleanup(client, config.ResourceGroup, config.AccountName, transformName, jobName, outputAsset.Name, input, streamingLocatorName, ContentKeyPolicyName); } catch (ApiErrorException ex) { string code = ex.Body.Error.Code; string message = ex.Body.Error.Message; Console.WriteLine("ERROR:API call failed with error code: {0} and message: {1}", code, message); } }
/// <summary> /// Run the sample async. /// </summary> /// <param name="config">The parm is of type ConfigWrapper. This class reads values from local configuration file.</param> /// <returns></returns> // <RunAsync> private static async Task RunAsync(ConfigWrapper config) { IAzureMediaServicesClient client = await CreateMediaServicesClientAsync(config); // Set the polling interval for long running operations to 2 seconds. // The default value is 30 seconds for the .NET client SDK client.LongRunningOperationRetryTimeout = 2; // Creating a unique suffix so that we don't have name collisions if you run the sample // multiple times without cleaning up. string uniqueness = Guid.NewGuid().ToString("N"); string jobName = $"job-{uniqueness}"; string locatorName = $"locator-{uniqueness}"; string outputAssetName = $"output-{uniqueness}"; // Ensure that you have the desired encoding Transform. This is really a one time setup operation. Transform transform = await GetOrCreateTransformAsync(client, config.ResourceGroup, config.AccountName, AdaptiveStreamingTransformName); // Output from the encoding Job must be written to an Asset, so let's create one Asset outputAsset = await CreateOutputAssetAsync(client, config.ResourceGroup, config.AccountName, outputAssetName); Job job = await SubmitJobAsync(client, config.ResourceGroup, config.AccountName, AdaptiveStreamingTransformName, outputAsset.Name, jobName); // In this demo code, we will poll for Job status // Polling is not a recommended best practice for production applications because of the latency it introduces. // Overuse of this API may trigger throttling. Developers should instead use Event Grid. job = await WaitForJobToFinishAsync(client, config.ResourceGroup, config.AccountName, AdaptiveStreamingTransformName, jobName); if (job.State == JobState.Finished) { // Set a token signing key that you want to use TokenSigningKey = Convert.FromBase64String(config.SymmetricKey); // Create the content key policy that configures how the content key is delivered to end clients // via the Key Delivery component of Azure Media Services. // We are using the ContentKeyIdentifierClaim in the ContentKeyPolicy which means that the token presented // to the Key Delivery Component must have the identifier of the content key in it. ContentKeyPolicy policy = await GetOrCreateContentKeyPolicyAsync(client, config.ResourceGroup, config.AccountName, ContentKeyPolicyName, TokenSigningKey); // Because this sample sets StreamingLocator.StreamingPolicyName to "Predefined_MultiDrmCencStreaming" policy, // two content keys get generated and set on the locator. StreamingLocator locator = await CreateStreamingLocatorAsync(client, config.ResourceGroup, config.AccountName, outputAsset.Name, locatorName, ContentKeyPolicyName); // In this example, we want to play the PlayReady (CENC) encrypted stream. // We need to get the key identifier of the content key where its type is CommonEncryptionCenc. string keyIdentifier = locator.ContentKeys.Where(k => k.Type == StreamingLocatorContentKeyType.CommonEncryptionCenc).First().Id.ToString(); Console.WriteLine($"KeyIdentifier = {keyIdentifier}"); // In order to generate our test token we must get the ContentKeyId to put in the ContentKeyIdentifierClaim claim. string token = GetTokenAsync(Issuer, Audience, keyIdentifier, TokenSigningKey); string dashPath = await GetDASHStreamingUrlAsync(client, config.ResourceGroup, config.AccountName, locator.Name); Console.WriteLine("Copy and paste the following URL in your browser to play back the file in the Azure Media Player."); Console.WriteLine("You can use Edge/IE11 for PlayReady and Chrome/Firefox Widevine."); Console.WriteLine(); Console.WriteLine($"https://ampdemo.azureedge.net/?url={dashPath}&playready=true&widevine=true&token=Bearer%3D{token}"); Console.WriteLine(); } Console.WriteLine("When finished testing press enter to cleanup."); Console.Out.Flush(); Console.ReadLine(); Console.WriteLine("Cleaning up..."); await CleanUpAsync(client, config.ResourceGroup, config.AccountName, AdaptiveStreamingTransformName, ContentKeyPolicyName); }
// </RunAsync> /// <summary> /// Create the content key policy that configures how the content key is delivered to end clients /// via the Key Delivery component of Azure Media Services. /// </summary> /// <param name="client">The Media Services client.</param> /// <param name="resourceGroupName">The name of the resource group within the Azure subscription.</param> /// <param name="accountName"> The Media Services account name.</param> /// <param name="contentKeyPolicyName">The name of the content key policy resource.</param> /// <returns></returns> // <GetOrCreateContentKeyPolicy> private static async Task <ContentKeyPolicy> GetOrCreateContentKeyPolicyAsync( IAzureMediaServicesClient client, string resourceGroupName, string accountName, string contentKeyPolicyName, byte[] tokenSigningKey) { bool createPolicy = false; ContentKeyPolicy policy = null; try { policy = await client.ContentKeyPolicies.GetAsync(resourceGroupName, accountName, contentKeyPolicyName); } catch (ErrorResponseException ex) when(ex.Response.StatusCode == System.Net.HttpStatusCode.NotFound) { createPolicy = true; } if (createPolicy) { ContentKeyPolicySymmetricTokenKey primaryKey = new ContentKeyPolicySymmetricTokenKey(tokenSigningKey); List <ContentKeyPolicyTokenClaim> requiredClaims = new List <ContentKeyPolicyTokenClaim>() { ContentKeyPolicyTokenClaim.ContentKeyIdentifierClaim }; List <ContentKeyPolicyRestrictionTokenKey> alternateKeys = null; ContentKeyPolicyTokenRestriction restriction = new ContentKeyPolicyTokenRestriction(Issuer, Audience, primaryKey, ContentKeyPolicyRestrictionTokenType.Jwt, alternateKeys, requiredClaims); ContentKeyPolicyPlayReadyConfiguration playReadyConfig = ConfigurePlayReadyLicenseTemplate(); ContentKeyPolicyWidevineConfiguration widevineConfig = ConfigureWidevineLicenseTemplate(); // ContentKeyPolicyFairPlayConfiguration fairplayConfig = ConfigureFairPlayPolicyOptions(); List <ContentKeyPolicyOption> options = new List <ContentKeyPolicyOption>(); options.Add( new ContentKeyPolicyOption() { Configuration = playReadyConfig, // If you want to set an open restriction, use // Restriction = new ContentKeyPolicyOpenRestriction() Restriction = restriction }); options.Add( new ContentKeyPolicyOption() { Configuration = widevineConfig, Restriction = restriction }); // add CBCS ContentKeyPolicyOption into the list // options.Add( // new ContentKeyPolicyOption() // { // Configuration = fairplayConfig, // Restriction = restriction, // Name = "ContentKeyPolicyOption_CBCS" // }); policy = await client.ContentKeyPolicies.CreateOrUpdateAsync(resourceGroupName, accountName, contentKeyPolicyName, options); } else { // Get the signing key from the existing policy. var policyProperties = await client.ContentKeyPolicies.GetPolicyPropertiesWithSecretsAsync(resourceGroupName, accountName, contentKeyPolicyName); if (policyProperties.Options[0].Restriction is ContentKeyPolicyTokenRestriction restriction) { if (restriction.PrimaryVerificationKey is ContentKeyPolicySymmetricTokenKey signingKey) { TokenSigningKey = signingKey.KeyValue; } } } return(policy); }