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)); } ConfigWrapper config = null; var generalOutputInfos = new List <GeneralOutputInfo>(); // Azure region management var azureRegions = new List <string>(); if ((string)data.azureRegion != null) { azureRegions = ((string)data.azureRegion).Split(',').ToList(); } else { azureRegions.Add((string)null); } foreach (var region in azureRegions) { try { config = new ConfigWrapper(new ConfigurationBuilder() .SetBasePath(Directory.GetCurrentDirectory()) .AddEnvironmentVariables() .Build(), region ); } catch (Exception ex) { return(IrdetoHelpers.ReturnErrorException(log, ex)); } 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; var liveEvents = client.LiveEvents.List(config.ResourceGroup, config.AccountName); // object to store the output of the function var generalOutputInfo = new GeneralOutputInfo(); // let's list live events try { generalOutputInfo = GenerateInfoHelpers.GenerateOutputInformation(config, client, liveEvents.ToList()); } catch (Exception ex) { return(IrdetoHelpers.ReturnErrorException(log, ex)); } try { var success = new List <bool>(); foreach (var le in generalOutputInfo.LiveEvents) { success.Add(await CosmosHelpers.CreateOrUpdateGeneralInfoDocument(le)); } if (success.Any(b => b == false)) { log.LogWarning("Cosmos access not configured."); } } catch (Exception ex) { return(IrdetoHelpers.ReturnErrorException(log, ex)); } generalOutputInfos.Add(generalOutputInfo); } return(new OkObjectResult( JsonConvert.SerializeObject(new GeneralOutputInfo { Success = true, LiveEvents = generalOutputInfos.SelectMany(i => i.LiveEvents).ToList() }, Formatting.Indented) )); }
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 liveEventName = (string)data.liveEventName; if (liveEventName == null) { return(IrdetoHelpers.ReturnErrorException(log, "Error - please pass liveEventName in the JSON")); } // 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 uniquenessAssets = Guid.NewGuid().ToString().Substring(0, 13); var streamingLocatorGuid = Guid.NewGuid(); // same locator for the two ouputs if 2 live event namle created var uniquenessLocator = streamingLocatorGuid.ToString().Substring(0, 13); var streamingLocatorName = "locator-" + uniquenessLocator; var manifestName = liveEventName.ToLower(); var clientTasks = new List <Task <LiveEventEntry> >(); foreach (var region in azureRegions) { var task = Task <LiveEventEntry> .Run(async() => { Asset asset = null; LiveOutput liveOutput = null; 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 var liveEvent = await client.LiveEvents.GetAsync(config.ResourceGroup, config.AccountName, liveEventName); if (liveEvent == null) { throw new Exception($"Live event {liveEventName} does not exist."); } var outputs = await client.LiveOutputs.ListAsync(config.ResourceGroup, config.AccountName, liveEventName); if (outputs.FirstOrDefault() != null) { liveOutput = outputs.FirstOrDefault(); asset = await client.Assets.GetAsync(config.ResourceGroup, config.AccountName, liveOutput.AssetName); } if (asset == null) { throw new Exception("Error - asset not found"); } try { // streaming locator creation MediaServicesHelpers.LogInformation(log, "Locator creation...", region); var locator = await IrdetoHelpers.CreateClearLocator(config, streamingLocatorName, client, asset, streamingLocatorGuid); MediaServicesHelpers.LogInformation(log, "locator : " + locator.Name, region); if (liveOutput != null) { await client.Assets.UpdateAsync(config.ResourceGroup, config.AccountName, asset.Name, asset); } } catch (Exception ex) { throw new Exception("locator creation error", ex); } // object to store the output of the function var generalOutputInfo = new GeneralOutputInfo(); // let's build info for the live event and output 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) )); }
public static GeneralOutputInfo GenerateOutputInformation(ConfigWrapper config, IAzureMediaServicesClient client, List <LiveEvent> liveEvents) { var generalOutputInfo = new GeneralOutputInfo { Success = true, LiveEvents = new List <LiveEventEntry>() }; foreach (var liveEventenum in liveEvents) { var liveEvent = client.LiveEvents.Get(config.ResourceGroup, config.AccountName, liveEventenum.Name); // we refresh the object var liveOutputs = client.LiveOutputs.List(config.ResourceGroup, config.AccountName, liveEvent.Name); // let's provide DASH format for preview var previewE = liveEvent.Preview.Endpoints .Select(a => new PreviewInfo { Protocol = a.Protocol, Url = a.Url }).ToList(); /* * // Code to expose Preview DASH and not Smooth * if (previewE.Count == 1 && previewE[0].Protocol == "FragmentedMP4") * { * previewE[0].Protocol = "DashCsf"; * previewE[0].Url = previewE[0].Url + "(format=mpd-time-csf)"; * } */ // output info var liveEventInfo = new LiveEventEntry() { LiveEventName = liveEvent.Name, ResourceState = liveEvent.ResourceState.ToString(), VanityUrl = liveEvent.VanityUrl, Input = liveEvent.Input.Endpoints .Select(endPoint => new UrlEntry { Protocol = endPoint.Protocol, Url = endPoint.Url }).ToList(), InputACL = liveEvent.Input.AccessControl?.Ip.Allow .Select(ip => ip.Address + "/" + ip.SubnetPrefixLength).ToList(), Preview = previewE .Select(endPoint => new UrlEntry { Protocol = endPoint.Protocol, Url = endPoint.Url }).ToList(), PreviewACL = liveEvent.Preview.AccessControl?.Ip.Allow .Select(ip => ip.Address + "/" + ip.SubnetPrefixLength).ToList(), LiveOutputs = new List <LiveOutputEntry>(), AMSAccountName = config.AccountName, Region = config.Region, ResourceGroup = config.ResourceGroup, LowLatency = liveEvent.StreamOptions?.Contains(StreamOptionsFlag.LowLatency) }; generalOutputInfo.LiveEvents.Add(liveEventInfo); foreach (var liveOutput in liveOutputs) { var urls = new List <OutputUrl>(); string streamingPolicyName = null; StreamingPolicy streamingPolicy = null; var asset = client.Assets.Get(config.ResourceGroup, config.AccountName, liveOutput.AssetName); // output info var liveOutputInfo = new LiveOutputEntry { LiveOutputName = liveOutput.Name, ResourceState = liveOutput.ResourceState, ArchiveWindowLength = (int)liveOutput.ArchiveWindowLength.TotalMinutes, AssetName = liveOutput.AssetName, AssetStorageAccountName = asset?.StorageAccountName, StreamingLocators = new List <StreamingLocatorEntry>() }; liveEventInfo.LiveOutputs.Add(liveOutputInfo); var streamingLocatorsNames = client.Assets.ListStreamingLocators(config.ResourceGroup, config.AccountName, liveOutput.AssetName).StreamingLocators.Select(l => l.Name); foreach (var locatorName in streamingLocatorsNames) { string cenckeyId = null; string cbcskeyId = null; StreamingLocator streamingLocator = null; if (locatorName != null) { streamingLocator = client.StreamingLocators.Get(config.ResourceGroup, config.AccountName, locatorName); if (streamingLocator != null) { streamingPolicyName = streamingLocator.StreamingPolicyName; if (streamingLocator.ContentKeys .Where(k => k.LabelReferenceInStreamingPolicy == IrdetoHelpers.labelCenc) .FirstOrDefault() != null && streamingLocator.ContentKeys .Where(k => k.LabelReferenceInStreamingPolicy == IrdetoHelpers.labelCbcs) .FirstOrDefault() != null) { cenckeyId = streamingLocator.ContentKeys .Where(k => k.LabelReferenceInStreamingPolicy == IrdetoHelpers.labelCenc) .FirstOrDefault().Id.ToString(); cbcskeyId = streamingLocator.ContentKeys .Where(k => k.LabelReferenceInStreamingPolicy == IrdetoHelpers.labelCbcs) .FirstOrDefault().Id.ToString(); } urls = MediaServicesHelpers.GetUrls(config, client, streamingLocator, liveOutput.ManifestName, true, true, true, true, true); } } if (streamingPolicyName != null) { streamingPolicy = client.StreamingPolicies.Get(config.ResourceGroup, config.AccountName, streamingPolicyName); } var drmlist = new List <Drm>(); if (streamingPolicy != null) { if (streamingPolicy.CommonEncryptionCbcs != null) { var enProt = MediaServicesHelpers.ReturnOutputProtocolsListCbcs(streamingPolicy .CommonEncryptionCbcs.EnabledProtocols); drmlist.Add(new Drm { Type = "FairPlay", LicenseUrl = streamingPolicy?.CommonEncryptionCbcs?.Drm.FairPlay .CustomLicenseAcquisitionUrlTemplate.Replace("{ContentKeyId}", cbcskeyId).Replace("{AlternativeMediaId}", streamingLocator.AlternativeMediaId), Protocols = enProt, CertificateUrl = config.IrdetoFairPlayCertificateUrl }); } if (streamingPolicy.CommonEncryptionCenc != null) { var enProtW = MediaServicesHelpers.ReturnOutputProtocolsListCencWidevine(streamingPolicy .CommonEncryptionCbcs.EnabledProtocols); var enProtP = MediaServicesHelpers.ReturnOutputProtocolsListCencPlayReady(streamingPolicy .CommonEncryptionCbcs.EnabledProtocols); drmlist.Add(new Drm { Type = "PlayReady", LicenseUrl = streamingPolicy?.CommonEncryptionCenc?.Drm.PlayReady .CustomLicenseAcquisitionUrlTemplate.Replace("{AlternativeMediaId}", streamingLocator.AlternativeMediaId), Protocols = enProtP }); drmlist.Add(new Drm { Type = "Widevine", LicenseUrl = streamingPolicy?.CommonEncryptionCenc?.Drm.Widevine .CustomLicenseAcquisitionUrlTemplate.Replace("{AlternativeMediaId}", streamingLocator.AlternativeMediaId), Protocols = enProtW }); } } var StreamingLocatorInfo = new StreamingLocatorEntry { StreamingLocatorName = locatorName, StreamingPolicyName = streamingPolicyName, CencKeyId = cenckeyId, CbcsKeyId = cbcskeyId, Drm = drmlist, Urls = urls.Select(url => new UrlEntry { Protocol = url.Protocol.ToString(), Url = url.Url }) .ToList() }; liveOutputInfo.StreamingLocators.Add(StreamingLocatorInfo); } } } return(generalOutputInfo); }