public static async Task <HttpResponseData> Run([HttpTrigger(AuthorizationLevel.Function, "get", "post")] HttpRequestData req, FunctionContext executionContext) { var log = executionContext.GetLogger("SubmitSubclipJob"); log.LogInformation("C# HTTP trigger function processed a request."); string triggerStart = DateTime.UtcNow.ToString("yyMMddHHmmss"); // 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.LiveEventName == null || data.LiveOutputName == null) { return(HttpRequest.ResponseBadRequest(req, "Please pass liveEventName and liveOutputName in the request body")); } data.IntervalSec ??= 60; ConfigWrapper config = ConfigUtils.GetConfig(); IAzureMediaServicesClient client; try { client = await Authentication.CreateMediaServicesClientAsync(config, log); } 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; // Ensure that you have customized encoding Transform. This is really a one time setup operation. Transform transform = await TransformUtils.CreateSubclipTransform(client, log, config.ResourceGroup, config.AccountName, SubclipTransformName); var liveOutput = await client.LiveOutputs.GetAsync(config.ResourceGroup, config.AccountName, data.LiveEventName, data.LiveOutputName); // let's analyze the client manifest and adjust times for the subclip job var doc = await LiveManifest.TryToGetClientManifestContentAsABlobAsync(client, config.ResourceGroup, config.AccountName, liveOutput.AssetName); var assetmanifestdata = LiveManifest.GetManifestTimingData(doc); if (assetmanifestdata.Error) { return(HttpRequest.ResponseBadRequest(req, "Data cannot be read from live output / asset manifest.")); } log.LogInformation("Timestamps : " + string.Join(",", assetmanifestdata.TimestampList.Select(n => n.ToString()).ToArray())); var livetime = TimeSpan.FromSeconds(assetmanifestdata.TimestampEndLastChunk / (double)assetmanifestdata.TimeScale); log.LogInformation($"Livetime : {livetime}"); var starttime = LiveManifest.ReturnTimeSpanOnGOP(assetmanifestdata, livetime.Subtract(TimeSpan.FromSeconds((int)data.IntervalSec))); log.LogInformation($"Value starttime : {starttime}"); if (data.LastSubclipEndTime != null) { var lastEndTime = (TimeSpan)data.LastSubclipEndTime; log.LogInformation($"Value lastEndTime : {lastEndTime}"); var delta = (livetime - lastEndTime - TimeSpan.FromSeconds((int)data.IntervalSec)).Duration(); log.LogInformation($"Delta: {delta}"); if (delta < (TimeSpan.FromSeconds(3 * (int)data.IntervalSec))) // less than 3 times the normal duration (3*60s) { starttime = lastEndTime; log.LogInformation($"Value new starttime : {starttime}"); } } var duration = livetime - starttime; log.LogInformation($"Value duration: {duration}"); if (duration == new TimeSpan(0)) // Duration is zero, this may happen sometimes ! { return(HttpRequest.ResponseBadRequest(req, "Stopping. Duration of subclip is zero.")); } // Output from the Job must be written to an Asset, so let's create one Asset outputAsset = await AssetUtils.CreateAssetAsync(client, log, config.ResourceGroup, config.AccountName, liveOutput.Name + "-subclip-" + triggerStart, data.OutputAssetStorageAccount); JobInput jobInput = new JobInputAsset( assetName: liveOutput.AssetName, start: new AbsoluteClipTime(starttime.Subtract(TimeSpan.FromMilliseconds(100))), end: new AbsoluteClipTime(livetime.Add(TimeSpan.FromMilliseconds(100))) ); Job job = await JobUtils.SubmitJobAsync( client, log, config.ResourceGroup, config.AccountName, SubclipTransformName, $"Subclip-{liveOutput.Name}-{triggerStart}", jobInput, outputAsset.Name ); AnswerBodyModel dataOk = new() { SubclipAssetName = outputAsset.Name, SubclipJobName = job.Name, SubclipTransformName = SubclipTransformName, SubclipEndTime = starttime + duration }; return(HttpRequest.ResponseOk(req, dataOk)); } }
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> /// Creates the AzureMediaServicesClient object based on the credentials /// supplied in local configuration file. /// </summary> /// <param name="config">The param is of type ConfigWrapper, which reads values from local configuration file.</param> /// <returns>A task.</returns> private static async Task <IAzureMediaServicesClient> CreateMediaServicesClientAsync(ConfigWrapper config) { ServiceClientCredentials credentials = await GetCredentialsAsync(config); return(new AzureMediaServicesClient(config.ArmEndpoint, credentials) { SubscriptionId = config.SubscriptionId }); }
public static async Task <HttpResponseData> Run([HttpTrigger(AuthorizationLevel.Function, "get", "post")] HttpRequestData req, FunctionContext executionContext) { var log = executionContext.GetLogger("CreateEmptyAsset"); 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.AssetNamePrefix == null) { return(HttpRequest.ResponseBadRequest(req, "Please pass asset name prefix 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); string assetName = $"{data.AssetNamePrefix}-{uniqueness}"; Asset asset; try { // let's create the asset asset = await AssetUtils.CreateAssetAsync(client, log, config.ResourceGroup, config.AccountName, assetName, data.AssetStorageAccount); log.LogInformation($"Asset '{assetName}' created."); // let's get the asset to have full metadata like container asset = await client.Assets.GetAsync(config.ResourceGroup, config.AccountName, assetName); } catch (Exception e) { log.LogError("Error when creating the asset."); log.LogError($"{e.Message}"); return(HttpRequest.ResponseBadRequest(req, e.Message)); } AnswerBodyModel dataOk = new() { AssetName = asset.Name, AssetId = asset.AssetId, Container = asset.Container }; return(HttpRequest.ResponseOk(req, dataOk)); } }