Example #1
0
        public static async Task <IActionResult> Run(
            [HttpTrigger(AuthorizationLevel.Function, "get", "post", Route = null)]
            HttpRequest req, ILogger log)
        {
            MediaServicesHelpers.LogInformation(log, "C# HTTP trigger function processed a request.");

            dynamic data;

            try
            {
                data = JsonConvert.DeserializeObject(new StreamReader(req.Body).ReadToEnd());
            }
            catch (Exception ex)
            {
                return(IrdetoHelpers.ReturnErrorException(log, ex));
            }

            var generalOutputInfos = new List <GeneralOutputInfo>();

            var liveEventName = (string)data.liveEventName;

            if (liveEventName == null)
            {
                return(IrdetoHelpers.ReturnErrorException(log, "Error - please pass liveEventName in the JSON"));
            }

            // default settings
            var eventInfoFromCosmos = new LiveEventSettingsInfo
            {
                LiveEventName = liveEventName
            };

            // Load config from Cosmos
            try
            {
                var setting = await CosmosHelpers.ReadSettingsDocument(liveEventName);

                eventInfoFromCosmos = setting ?? eventInfoFromCosmos;

                if (setting == null)
                {
                    log.LogWarning("Settings not read from Cosmos.");
                }
            }
            catch (Exception ex)
            {
                return(IrdetoHelpers.ReturnErrorException(log, ex));
            }

            // Azure region management
            var azureRegions = new List <string>();

            if ((string)data.azureRegion != null)
            {
                azureRegions = ((string)data.azureRegion).Split(',').ToList();
            }
            else
            {
                azureRegions.Add((string)null);
            }

            // init default
            var deleteAsset = (data.deleteAsset != null) ? (bool)data.deleteAsset : true;

            var uniquenessAssets = Guid.NewGuid().ToString().Substring(0, 13);

            string uniquenessPolicyName = Guid.NewGuid().ToString().Substring(0, 13);

            var manifestName = liveEventName.ToLower();

            if (data.archiveWindowLength != null)
            {
                eventInfoFromCosmos.ArchiveWindowLength = (int)data.archiveWindowLength;
            }

            var cencKey = new StreamingLocatorContentKey();
            var cbcsKey = new StreamingLocatorContentKey();

            if (!deleteAsset) // we need to regenerate the keys if the user wants to keep the asset as keys cannot be reused for more than one asset
            {
                try
                {
                    ConfigWrapper config = new ConfigWrapper(new ConfigurationBuilder()
                                                             .SetBasePath(Directory.GetCurrentDirectory())
                                                             .AddEnvironmentVariables()
                                                             .Build(),
                                                             null);

                    MediaServicesHelpers.LogInformation(log, "Irdeto call...");

                    cencKey = await IrdetoHelpers.GenerateAndRegisterCENCKeyToIrdeto(liveEventName, config);

                    cbcsKey = await IrdetoHelpers.GenerateAndRegisterCBCSKeyToIrdeto(liveEventName, config);

                    MediaServicesHelpers.LogInformation(log, "Irdeto call done.");
                }
                catch (Exception ex)
                {
                    return(IrdetoHelpers.ReturnErrorException(log, ex, "Irdeto response error"));
                }
            }

            var clientTasks = new List <Task <LiveEventEntry> >();

            // list of locators guid for the new locators
            var locatorGuids = new List <Guid>();

            for (int i = 0; i < 10; i++)
            {
                locatorGuids.Add(Guid.NewGuid());
            }

            foreach (var region in azureRegions)
            {
                var task = Task <LiveEventEntry> .Run(async() =>
                {
                    Asset asset           = null;
                    LiveEvent liveEvent   = null;
                    LiveOutput liveOutput = null;

                    bool reuseKeys                = false;
                    string storageAccountName     = null;
                    var streamingLocatorsPolicies = new Dictionary <string, string>(); // locator name, policy name


                    ConfigWrapper config = new ConfigWrapper(new ConfigurationBuilder()
                                                             .SetBasePath(Directory.GetCurrentDirectory())
                                                             .AddEnvironmentVariables()
                                                             .Build(),
                                                             region
                                                             );

                    MediaServicesHelpers.LogInformation(log, "config loaded.", region);
                    MediaServicesHelpers.LogInformation(log, "connecting to AMS account : " + config.AccountName, region);

                    var client = await MediaServicesHelpers.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;

                    // let's check that the channel exists
                    liveEvent = await client.LiveEvents.GetAsync(config.ResourceGroup, config.AccountName, liveEventName);
                    if (liveEvent == null)
                    {
                        throw new Exception("Error : live event does not exist !");
                    }

                    if (liveEvent.ResourceState != LiveEventResourceState.Running && liveEvent.ResourceState != LiveEventResourceState.Stopped)
                    {
                        throw new Exception("Error : live event should be in Running or Stopped state !");
                    }

                    // get live output(s) - it should be one
                    var myLiveOutputs = client.LiveOutputs.List(config.ResourceGroup, config.AccountName, liveEventName);

                    // get the names of the streaming policies. If not possible, recreate it
                    if (myLiveOutputs.FirstOrDefault() != null)
                    {
                        asset = client.Assets.Get(config.ResourceGroup, config.AccountName,
                                                  myLiveOutputs.First().AssetName);

                        var streamingLocatorsNames = client.Assets.ListStreamingLocators(config.ResourceGroup, config.AccountName, asset.Name).StreamingLocators.Select(l => l.Name);
                        foreach (var locatorName in streamingLocatorsNames)
                        {
                            var locator =
                                client.StreamingLocators.Get(config.ResourceGroup, config.AccountName, locatorName);
                            if (locator != null)
                            {
                                streamingLocatorsPolicies.Add(locatorName, locator.StreamingPolicyName);
                                if (locator.StreamingPolicyName != PredefinedStreamingPolicy.ClearStreamingOnly) // let's backup the keys to reuse them
                                {
                                    if (deleteAsset)                                                             // we reuse the keys. Only possible if the previous asset is deleted
                                    {
                                        reuseKeys = true;
                                        var keys  = client.StreamingLocators.ListContentKeys(config.ResourceGroup, config.AccountName, locatorName).ContentKeys;
                                        cencKey   = keys.Where(k => k.LabelReferenceInStreamingPolicy == IrdetoHelpers.labelCenc).FirstOrDefault();
                                        cbcsKey   = keys.Where(k => k.LabelReferenceInStreamingPolicy == IrdetoHelpers.labelCbcs).FirstOrDefault();
                                    }
                                }
                            }
                        }

                        if (streamingLocatorsPolicies.Count == 0) // no way to get the streaming policy, let's read Cosmos or create a new one
                        {
                            MediaServicesHelpers.LogInformation(log, "Trying to read streaming policy from Cosmos.", region);
                            string streamingPolicyName = null;
                            // Load streaming policy info from Cosmos
                            try
                            {
                                var info = await CosmosHelpers.ReadStreamingPolicyDocument(new StreamingPolicyInfo(false)
                                {
                                    AMSAccountName = config.AccountName
                                });

                                if (info == null)
                                {
                                    log.LogWarning("Streaming policy not read from Cosmos.");
                                }
                                else
                                {
                                    streamingPolicyName = info.StreamingPolicyName;
                                }
                            }
                            catch (Exception ex)
                            {
                                throw new Exception("Error reading Cosmos DB", ex);
                            }


                            // STREAMING POLICY CREATION
                            if (streamingPolicyName == null) // not found in Cosmos let's create a new one
                            {
                                StreamingPolicy streamingPolicy;
                                MediaServicesHelpers.LogInformation(log, "Creating streaming policy.", region);
                                try
                                {
                                    streamingPolicy = await IrdetoHelpers.CreateStreamingPolicyIrdeto(config, client, uniquenessPolicyName);
                                    streamingLocatorsPolicies.Add("", streamingPolicy.Name);
                                }
                                catch (Exception ex)
                                {
                                    throw new Exception("Streaming policy creation error", ex);
                                }

                                try
                                {
                                    if (!await CosmosHelpers.CreateOrUpdatePolicyDocument(new StreamingPolicyInfo(false)
                                    {
                                        AMSAccountName = config.AccountName,
                                        StreamingPolicyName = streamingPolicy.Name
                                    }))
                                    {
                                        log.LogWarning("Cosmos access not configured or error.");
                                    }
                                }
                                catch (Exception ex)
                                {
                                    throw new Exception("Streaming policy write error to Cosmos", ex);
                                }
                            }
                            else
                            {
                                streamingLocatorsPolicies.Add("", streamingPolicyName);
                            }
                        }
                    }

                    // let's purge all live output for now
                    foreach (var p in myLiveOutputs)
                    {
                        var assetName = p.AssetName;

                        var thisAsset = client.Assets.Get(config.ResourceGroup, config.AccountName, p.AssetName);
                        if (thisAsset != null)
                        {
                            storageAccountName = thisAsset.StorageAccountName; // let's backup storage account name to create the new asset here
                        }
                        MediaServicesHelpers.LogInformation(log, "deleting live output : " + p.Name, region);
                        await client.LiveOutputs.DeleteAsync(config.ResourceGroup, config.AccountName, liveEvent.Name, p.Name);
                        if (deleteAsset)
                        {
                            MediaServicesHelpers.LogInformation(log, "deleting asset : " + assetName, region);
                            await client.Assets.DeleteAsync(config.ResourceGroup, config.AccountName, assetName);
                        }
                    }

                    if (liveEvent.ResourceState == LiveEventResourceState.Running)
                    {
                        MediaServicesHelpers.LogInformation(log, "reseting live event : " + liveEvent.Name, region);
                        await client.LiveEvents.ResetAsync(config.ResourceGroup, config.AccountName, liveEvent.Name);
                    }
                    else
                    {
                        MediaServicesHelpers.LogInformation(log, "Skipping the reset of live event " + liveEvent.Name + " as it is stopped.", region);
                    }

                    // LIVE OUTPUT CREATION
                    MediaServicesHelpers.LogInformation(log, "Live output creation...", region);

                    try
                    {
                        MediaServicesHelpers.LogInformation(log, "Asset creation...", region);
                        asset = await client.Assets.CreateOrUpdateAsync(config.ResourceGroup, config.AccountName,
                                                                        "asset-" + uniquenessAssets, new Asset(storageAccountName: storageAccountName));

                        Hls hlsParam = null;
                        liveOutput   = new LiveOutput(asset.Name, TimeSpan.FromMinutes(eventInfoFromCosmos.ArchiveWindowLength),
                                                      null, "output-" + uniquenessAssets, null, null, manifestName,
                                                      hlsParam);

                        MediaServicesHelpers.LogInformation(log, "create live output...", region);
                        await client.LiveOutputs.CreateAsync(config.ResourceGroup, config.AccountName, liveEventName, liveOutput.Name, liveOutput);
                    }
                    catch (Exception ex)
                    {
                        throw new Exception("live output creation error", ex);
                    }

                    try
                    {
                        // streaming locator(s) creation
                        MediaServicesHelpers.LogInformation(log, "Locator creation...", region);
                        int i = 0;
                        foreach (var entryLocPol in streamingLocatorsPolicies)
                        {
                            StreamingLocator locator = null;
                            var streamingLocatorGuid = locatorGuids[i]; // same locator for the two ouputs if 2 live event namle created
                            var uniquenessLocator    = streamingLocatorGuid.ToString().Substring(0, 13);
                            var streamingLocatorName = "locator-" + uniquenessLocator;

                            if (entryLocPol.Value == PredefinedStreamingPolicy.ClearStreamingOnly)
                            {
                                locator = await IrdetoHelpers.CreateClearLocator(config, streamingLocatorName, client, asset, streamingLocatorGuid);
                            }
                            else // DRM content
                            {
                                MediaServicesHelpers.LogInformation(log, "creating DRM locator : " + streamingLocatorName, region);

                                if (!reuseKeys)
                                {
                                    MediaServicesHelpers.LogInformation(log, "using new keys.", region);

                                    locator = await IrdetoHelpers.SetupDRMAndCreateLocatorWithNewKeys(
                                        config, entryLocPol.Value, streamingLocatorName, client, asset, cencKey, cbcsKey, streamingLocatorGuid);
                                }
                                else // no need to create new keys, let's use the exiting one
                                {
                                    MediaServicesHelpers.LogInformation(log, "using existing keys.", region);

                                    locator = await IrdetoHelpers.SetupDRMAndCreateLocatorWithExistingKeys(
                                        config, entryLocPol.Value, streamingLocatorName, client, asset, cencKey, cbcsKey, streamingLocatorGuid);
                                }
                            }
                            MediaServicesHelpers.LogInformation(log, "locator : " + streamingLocatorName, region);
                            i++;
                        }

                        await client.Assets.UpdateAsync(config.ResourceGroup, config.AccountName, asset.Name, asset);
                    }
                    catch (Exception ex)
                    {
                        throw new Exception("locator creation error", ex);
                    }

                    var generalOutputInfo =
                        GenerateInfoHelpers.GenerateOutputInformation(config, client, new List <LiveEvent> {
                        liveEvent
                    });

                    if (!await CosmosHelpers.CreateOrUpdateGeneralInfoDocument(generalOutputInfo.LiveEvents[0]))
                    {
                        MediaServicesHelpers.LogWarning(log, "Cosmos access not configured.", region);
                    }

                    return(generalOutputInfo.LiveEvents[0]);
                });

                clientTasks.Add(task);
            }

            try
            {
                Task.WaitAll(clientTasks.ToArray());
            }
            catch (Exception ex)
            {
                return(IrdetoHelpers.ReturnErrorException(log, ex));
            }

            return(new OkObjectResult(
                       JsonConvert.SerializeObject(new GeneralOutputInfo {
                Success = true, LiveEvents = clientTasks.Select(i => i.Result).ToList()
            }, Formatting.Indented)
                       ));
        }