/// <summary>
        /// Generates streaming locator using Azure Front Door URL
        /// This implementation is based on https://github.com/Azure-Samples/media-services-v3-dotnet-core-tutorials/tree/master/NETCore/EncodeHTTPAndPublishAESEncrypted
        /// </summary>
        /// <param name="client">Azure Media Services instance client</param>
        /// <param name="config">Azure Media Services instance configuration</param>
        /// <param name="locatorName">locator name</param>
        /// <param name="keyIdentifier">key identifier</param>
        /// <returns></returns>
        private async Task <string> GenerateStreamingUrl(IAzureMediaServicesClient client, MediaServiceConfigurationModel config, string locatorName, string keyIdentifier)
        {
            // Get token to access content
            var token = MediaServicesHelper.GetToken(this.configService.TokenIssuer, this.configService.TokenAudience, keyIdentifier, this.configService.GetClearKeyStreamingKey());

            // Get list of all paths associated with specific locator
            var paths = await client.StreamingLocators.ListPathsAsync(config.ResourceGroup, config.AccountName, locatorName).ConfigureAwait(false);

            // Create Dash URL
            for (var i = 0; i < paths.StreamingPaths.Count; i++)
            {
                var uriBuilder = new UriBuilder();
                uriBuilder.Scheme = "https";
                uriBuilder.Host   = this.configService.FrontDoorHostName;
                if (paths.StreamingPaths[i].Paths.Count > 0)
                {
                    if (paths.StreamingPaths[i].StreamingProtocol == StreamingPolicyStreamingProtocol.Dash)
                    {
                        uriBuilder.Path = paths.StreamingPaths[i].Paths[0];
                        var dashPath = uriBuilder.ToString();
                        return($"https://ampdemo.azureedge.net/?url={dashPath}&aes=true&aestoken=Bearer%3D{token}");
                    }
                }
            }

            return(null);
        }
Beispiel #2
0
        /// <summary>
        /// Provisions created locator to specific Azure Media Services instance
        /// </summary>
        /// <param name="client">Azure Media Services instance client</param>
        /// <param name="config">Azure Media Services instance config</param>
        /// <param name="assetName">Asset name associated with locator</param>
        /// <param name="locatorName">Locator name</param>
        /// <param name="locatorToProvision">Locator object</param>
        /// <param name="logger">Logger to log data</param>
        /// <returns></returns>
        protected static async Task <StreamingLocator> ProvisionLocatorAsync(IAzureMediaServicesClient client, MediaServiceConfigurationModel config, string assetName, string locatorName, StreamingLocator locatorToProvision, ILogger logger)
        {
            logger.LogInformation($"StreamingProvisioningService::ProvisionLocatorAsync started: instanceName={config.AccountName} assetName={assetName} locatorName={locatorName}");

            // Check if locator already exists
            var locator = await client.StreamingLocators.GetAsync(config.ResourceGroup, config.AccountName, locatorName).ConfigureAwait(false);

            // if locator exists, but associated with different asset, throw. This should only happen if locators are created outside from this automated process
            if (locator != null && !locator.AssetName.Equals(assetName, StringComparison.InvariantCultureIgnoreCase))
            {
                throw new Exception($"Locator already exists with incorrect asset name, accountName={config.AccountName} locatorName={locator.Name} existingAssetName={locator.AssetName} requestedAssetName={assetName}");
            }

            // locator does not exists, need to create new one
            if (locator == null)
            {
                locator = await client.StreamingLocators.CreateAsync(
                    config.ResourceGroup,
                    config.AccountName,
                    locatorName,
                    locatorToProvision).ConfigureAwait(false);

                logger.LogInformation($"StreamingProvisioningService::ProvisionLocatorAsync new locator provisioned: locator={LogHelper.FormatObjectForLog(locator)}");
            }

            logger.LogInformation($"StreamingProvisioningService::ProvisionLocatorAsync completed: instanceName={config.AccountName} assetName={assetName} locatorName={locatorName} locator={LogHelper.FormatObjectForLog(locator)}");

            return(locator);
        }
        /// <summary>
        /// Copies asset data from source Azure Media Services instance to target using Azure Blob Copy
        /// </summary>
        /// <param name="sourceClient">Source Azure Media Services instance client</param>
        /// <param name="sourceConfig">Source Azure Media Services instance configuration</param>
        /// <param name="targetClient">Target Azure Media Services instance client</param>
        /// <param name="targetConfig">Target Azure Media Services instance configuration</param>
        /// <param name="provisioningRequest">Provisioning request data</param>
        /// <param name="logger">Logger to log data</param>
        /// <returns>Target asset</returns>
        private async Task <Asset> CopyAssetAsync(IAzureMediaServicesClient sourceClient, MediaServiceConfigurationModel sourceConfig,
                                                  IAzureMediaServicesClient targetClient, MediaServiceConfigurationModel targetConfig,
                                                  ProvisioningRequestModel provisioningRequest, ILogger logger)
        {
            logger.LogInformation($"AssetDataProvisioningService::CopyAssetAsync started: provisioningRequest={LogHelper.FormatObjectForLog(provisioningRequest)} sourceInstanceName={sourceConfig.AccountName} targetInstanceName={targetConfig.AccountName}");

            // Need to ensure that target asset exits
            var targetAsset = await targetClient.Assets.GetAsync(targetConfig.ResourceGroup, targetConfig.AccountName, provisioningRequest.ProcessedAssetName).ConfigureAwait(false);

            // if there is no target asset, need to provision one
            if (targetAsset == null)
            {
                // create new target asset
                targetAsset = await targetClient.Assets.CreateOrUpdateAsync(targetConfig.ResourceGroup, targetConfig.AccountName, provisioningRequest.ProcessedAssetName, new Asset()).ConfigureAwait(false);

                // need to reload asset to get Container value populated, otherwise Container is null after asset creation
                targetAsset = await targetClient.Assets.GetAsync(targetConfig.ResourceGroup, targetConfig.AccountName, provisioningRequest.ProcessedAssetName).ConfigureAwait(false);
            }

            // Get SAS token associated with source asset. SAS token is required to initiate StartCopyFromUri
            var sourceAssetContainerSas = await sourceClient.Assets.ListContainerSasAsync(
                sourceConfig.ResourceGroup,
                sourceConfig.AccountName,
                provisioningRequest.ProcessedAssetName,
                permissions : AssetContainerPermission.Read,
                expiryTime : DateTime.UtcNow.AddHours(1).ToUniversalTime()).ConfigureAwait(false);

            var sourceContainerSasUrl = new Uri(sourceAssetContainerSas.AssetContainerSasUrls.FirstOrDefault());

            var sourceBlobClient = new BlobContainerClient(sourceContainerSasUrl);

            var copyTasks = new List <Task>();

            // Get a list of all blobs to copy
            await foreach (var blobItem in sourceBlobClient.GetBlobsAsync())
            {
                // All blobs can be copies in parallel
                copyTasks.Add(Task.Run(() =>
                {
                    // Get target blob
                    var targetBlob = new BlobBaseClient(this.configService.MediaServiceInstanceStorageAccountConnectionStrings[targetConfig.AccountName], targetAsset.Container, blobItem.Name);
                    // Get source blob
                    var sourceBlob = sourceBlobClient.GetBlobClient(blobItem.Name);
                    // Start copy operation, see more data about it https://docs.microsoft.com/en-us/dotnet/api/azure.storage.blobs.specialized.blobbaseclient.startcopyfromuriasync?view=azure-dotnet
                    var copyOperation = targetBlob.StartCopyFromUri(sourceBlob.Uri);
                    // Wait for copy to complete, since this is running on separate thread, no need to do async
                    var copyResult = copyOperation.WaitForCompletionAsync().GetAwaiter().GetResult();
                    // Check copy operation status
                    if (copyResult.GetRawResponse().Status != 200)
                    {
                        throw new Exception($"Copy operation failed, sourceAccount={sourceConfig.AccountName} targetAccount={targetConfig.AccountName} assetName={provisioningRequest.ProcessedAssetName} blobName={blobItem.Name} httpStatus={copyResult.GetRawResponse().Status}");
                    }
                }));
            }

            // Wait for all copy tasks to finish
            await Task.WhenAll(copyTasks).ConfigureAwait(false);

            logger.LogInformation($"AssetDataProvisioningService::CopyAssetAsync completed: provisioningRequest={LogHelper.FormatObjectForLog(provisioningRequest)} sourceInstanceName={sourceConfig.AccountName} targetInstanceName={targetConfig.AccountName} numberOfFiles={copyTasks.Count}");

            return(targetAsset);
        }