diff --git a/NETCore/Live/MediaV3LiveApp/Program.cs b/NETCore/Live/MediaV3LiveApp/Program.cs
index f6f2a9e..d478eb0 100644
--- a/NETCore/Live/MediaV3LiveApp/Program.cs
+++ b/NETCore/Live/MediaV3LiveApp/Program.cs
@@ -17,8 +17,6 @@ namespace LiveSample
{
class Program
{
- private static string liveEventName;
-
public static async Task Main(string[] args)
{
ConfigWrapper config = new ConfigWrapper(new ConfigurationBuilder()
@@ -57,11 +55,9 @@ public static async Task Main(string[] args)
/// Run the sample async.
///
/// The parm is of type ConfigWrapper. This class reads values from local configuration file.
- ///
- //
+ /// an async Task
private static async Task RunAsync(ConfigWrapper config)
{
-
IAzureMediaServicesClient client = await CreateMediaServicesClientAsync(config);
// Creating a unique suffix so that we don't have name collisions if you run the sample
@@ -284,261 +280,17 @@ private static async Task RunAsync(ConfigWrapper config)
await CleanupLiveEventAndOutputAsync(client, config.ResourceGroup, config.AccountName, liveEventName);
await CleanupLocatorandAssetAsync(client, config.ResourceGroup, config.AccountName, streamingLocatorName, assetName);
- }
- }
-
- private static async Task CreateLiveEventAsync(IAzureMediaServicesClient client, string resourceGroup, string accountName, string liveEventName)
- {
- // Getting the mediaServices account so that we can use the location to create the
- // LiveEvent and StreamingEndpoint
- MediaService mediaService = await client.Mediaservices.GetAsync(resourceGroup, 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 transcoding LiveEvent, and None to enable a pass-through LiveEvent
- encodingType: LiveEventEncodingType.None,
- presetName: null
- ),
- input: new LiveEventInput(LiveEventInputProtocol.RTMP, liveEventInputAccess),
- preview: liveEventPreview,
- streamOptions: new List()
- {
- // Set this to Default or Low Latency
- // When using Low Latency mode, you must configure the Azure Media Player to use the
- // quick start hueristic 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.
- return await client.LiveEvents.CreateAsync(resourceGroup, accountName, liveEventName, liveEvent, autoStart: true);
- }
-
- private static async Task CreateAssetAndLocatorAsync(IAzureMediaServicesClient client, string resourceGroup, string accountName, string assetName, string streamingLocatorName)
- {
- // Create an Asset for the LiveOutput to use
- Console.WriteLine($"Creating an asset named {assetName}");
- Console.WriteLine();
- Asset asset = await client.Assets.CreateOrUpdateAsync(resourceGroup, accountName, assetName, new Asset());
-
- // Create the StreamingLocator
- Console.WriteLine($"Creating a streaming locator named {streamingLocatorName}");
- Console.WriteLine();
-
- StreamingLocator locator = new StreamingLocator(assetName: asset.Name, streamingPolicyName: PredefinedStreamingPolicy.ClearStreamingOnly);
- return await client.StreamingLocators.CreateAsync(resourceGroup, accountName, streamingLocatorName, locator);
- }
-
- private static async Task StartStreamingEndpointAsync(IAzureMediaServicesClient client, string resourceGroup, string accountName, string assetName, string streamingEndpointName)
- {
- // Get the default Streaming Endpoint on the account
- StreamingEndpoint streamingEndpoint = await client.StreamingEndpoints.GetAsync(resourceGroup, accountName, streamingEndpointName);
-
- // If it's not running, Start it.
- if (streamingEndpoint.ResourceState != StreamingEndpointResourceState.Running)
- {
- Console.WriteLine("Streaming Endpoint was Stopped, restarting now..");
- await client.StreamingEndpoints.StartAsync(resourceGroup, accountName, streamingEndpointName);
-
- streamingEndpoint = await client.StreamingEndpoints.GetAsync(resourceGroup, accountName, streamingEndpointName);
- }
-
- return streamingEndpoint;
- }
-
- private static async Task RunAsync2(ConfigWrapper config)
- {
- IAzureMediaServicesClient client = await CreateMediaServicesClientAsync(config);
-
- // 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 streamingLocatorName = "streamingLocator" + uniqueness;
- string streamingEndpointName = "default";
-
- try
- {
- Task liveEventTask = CreateLiveEventAsync(client, config.ResourceGroup, config.AccountName, liveEventName);
- Task streamingLocatorTask = CreateAssetAndLocatorAsync(client, config.ResourceGroup, config.AccountName, assetName, streamingLocatorName);
- Task startStreamingEndpointTask = StartStreamingEndpointAsync(client, config.ResourceGroup, config.AccountName, assetName, streamingEndpointName);
-
- Task[] tasks = new Task[]
- {
- liveEventTask,
- streamingLocatorTask,
- startStreamingEndpointTask
- };
-
- Task.WaitAll(tasks);
-
- LiveEvent liveEvent = liveEventTask.Result;
- StreamingEndpoint streamingEndpoint = startStreamingEndpointTask.Result;
-
- // 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("Press enter to continue...");
- Console.Out.Flush();
- var ignoredInput = Console.ReadLine();
-
- // Create the LiveOutput
- string manifestName = "output";
- Console.WriteLine($"Creating a live output named {liveOutputName}");
- Console.WriteLine();
-
- LiveOutput liveOutput = new LiveOutput(assetName: assetName, manifestName: manifestName, archiveWindowLength: TimeSpan.FromMinutes(10));
- liveOutput = await client.LiveOutputs.CreateAsync(config.ResourceGroup, config.AccountName, liveEventName, liveOutputName, liveOutput);
-
- // Get the url to stream the output
- var paths = await client.StreamingLocators.ListPathsAsync(config.ResourceGroup, config.AccountName, streamingLocatorName);
-
- Console.WriteLine("The urls to stream the output from a client:");
- Console.WriteLine();
- StringBuilder stringBuilder = new StringBuilder();
- string playerPath = string.Empty;
-
- 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];
- stringBuilder.AppendLine($"\t{paths.StreamingPaths[i].StreamingProtocol}-{paths.StreamingPaths[i].EncryptionScheme}");
- stringBuilder.AppendLine($"\t\t{uriBuilder.ToString()}");
- stringBuilder.AppendLine();
-
- if (paths.StreamingPaths[i].StreamingProtocol == StreamingPolicyStreamingProtocol.Dash)
- {
- playerPath = uriBuilder.ToString();
- }
- }
- }
-
- if (stringBuilder.Length > 0)
- {
- Console.WriteLine(stringBuilder.ToString());
- Console.WriteLine("Open the following URL to playback the published,recording LiveOutput in the Azure Media Player");
- Console.WriteLine($"\t https://ampdemo.azureedge.net/?url={playerPath}&heuristicprofile=lowlatency");
- Console.WriteLine();
-
- Console.WriteLine("Continue experimenting with the stream until you are ready to finish.");
- Console.WriteLine("Press enter to stop the LiveOutput...");
- Console.Out.Flush();
- ignoredInput = Console.ReadLine();
-
- 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.");
- Console.WriteLine("Press enter to finish cleanup...");
- Console.Out.Flush();
- ignoredInput = Console.ReadLine();
- }
- else
- {
- Console.WriteLine("No Streaming Paths were detected. Has the Stream been started?");
- Console.WriteLine("Cleaning up and Exiting...");
- }
- }
- 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 CleanupLocatorandAssetAsync(client, config.ResourceGroup, config.AccountName, streamingLocatorName, assetName);
+ await CleanupStreamingEndpointAsync(client, config.ResourceGroup, config.AccountName, streamingEndpointName, deleteEndpoint: false);
}
}
-
///
/// Create the ServiceClientCredentials object based on the credentials
/// supplied in local configuration file.
///
/// The parm is of type ConfigWrapper. This class reads values from local configuration file.
- ///
- //
+ /// ServiceCredentials that can be used to create an Azure Media Services client instance.
private static async Task GetCredentialsAsync(ConfigWrapper config)
{
// Use UserTokenProvider.LoginWithPromptAsync or UserTokenProvider.LoginSilentAsync to get a token using user authentication
@@ -553,15 +305,13 @@ private static async Task GetCredentialsAsync(ConfigWr
ClientCredential clientCredential = new ClientCredential(config.AadClientId, config.AadSecret);
return await ApplicationTokenProvider.LoginSilentAsync(config.AadTenantId, clientCredential, ActiveDirectoryServiceSettings.Azure);
}
- //
///
/// Creates the AzureMediaServicesClient object based on the credentials
/// supplied in local configuration file.
///
/// The parm is of type ConfigWrapper. This class reads values from local configuration file.
- ///
- //
+ /// an Azure Media Services client instance
private static async Task CreateMediaServicesClientAsync(ConfigWrapper config)
{
var credentials = await GetCredentialsAsync(config);
@@ -571,9 +321,17 @@ private static async Task CreateMediaServicesClientAs
SubscriptionId = config.SubscriptionId,
};
}
- //
- //
+ ///
+ /// Checks to see if the LiveEvent exists and if so it stops it (if running) and then deletes the LiveEvent. The removeOutputsOnStop parameter
+ /// is set to true so that any LiveOutputs associated with the LiveEvent will also be deleted as part of the cleanup. The method will log any
+ /// caught exceptions to console output but won't rethrow them.
+ ///
+ /// Azure Media Services client instance to use
+ /// The Resource Group containing the Azure Media Services account.
+ /// The name of the Azure Media Services account.
+ /// The name of the LiveEvent to delete.
+ /// Async task
private static async Task CleanupLiveEventAndOutputAsync(IAzureMediaServicesClient client, string resourceGroup, string accountName, string liveEventName)
{
try
@@ -586,10 +344,15 @@ private static async Task CleanupLiveEventAndOutputAsync(IAzureMediaServicesClie
{
// If the LiveEvent is running, stop it and have it remove any LiveOutputs
await client.LiveEvents.StopAsync(resourceGroup, accountName, liveEventName, removeOutputsOnStop: true);
+
+ Console.WriteLine($"LiveEvent {liveEventName} is stopped.");
}
// Delete the LiveEvent
await client.LiveEvents.DeleteAsync(resourceGroup, accountName, liveEventName);
+
+ Console.WriteLine($"LiveEvent {liveEventName} is deleted.");
+ Console.WriteLine();
}
}
catch (ApiErrorException e)
@@ -600,9 +363,18 @@ private static async Task CleanupLiveEventAndOutputAsync(IAzureMediaServicesClie
Console.WriteLine();
}
}
- //
-
- //
+
+
+ ///
+ /// Deletes the StreamingLocator and Asset matching the names provided as parameters. The method will log any
+ /// caught exceptions to console output but won't rethrow them.
+ ///
+ /// Azure Media Services client instance to use
+ /// The Resource Group containing the Azure Media Services account.
+ /// The name of the Azure Media Services account.
+ /// The name of the StreamingLocator to delete.
+ /// The name of the Asset to delete.
+ /// Async task
private static async Task CleanupLocatorandAssetAsync(IAzureMediaServicesClient client, string resourceGroup, string accountName, string streamingLocatorName, string assetName)
{
try
@@ -610,8 +382,13 @@ private static async Task CleanupLocatorandAssetAsync(IAzureMediaServicesClient
// Delete the Streaming Locator
await client.StreamingLocators.DeleteAsync(resourceGroup, accountName, streamingLocatorName);
+ Console.WriteLine($"StreamingLocator {streamingLocatorName} is deleted.");
+
// Delete the Archive Asset
await client.Assets.DeleteAsync(resourceGroup, accountName, assetName);
+
+ Console.WriteLine($"Asset {assetName} is deleted.");
+ Console.WriteLine();
}
catch (ApiErrorException e)
{
@@ -621,27 +398,39 @@ private static async Task CleanupLocatorandAssetAsync(IAzureMediaServicesClient
Console.WriteLine();
}
}
- //
- private static async Task CleanupStreamingEndpointAsync(IAzureMediaServicesClient client, string resourceGroup, string accountName, string streamingEndpointName, bool stopEndpoint, bool deleteEndpoint)
+ ///
+ /// Stops the StreamingEndpoint with the specified name. If the deleteEndpoint parameter is true, then the StreamingEndpoint
+ /// will be deleted after it is stopped.
+ ///
+ /// Azure Media Services client instance to use
+ /// The Resource Group containing the Azure Media Services account.
+ /// The name of the Azure Media Services account.
+ /// The name of the StreamingEndpoint to stop or delete.
+ /// A value specifying whether the StreamingEndpoint should be deleted after it is stopped.
+ /// Async task
+ private static async Task CleanupStreamingEndpointAsync(IAzureMediaServicesClient client, string resourceGroup, string accountName, string streamingEndpointName, bool deleteEndpoint)
{
try
{
- if (stopEndpoint || deleteEndpoint)
+ StreamingEndpoint s = await client.StreamingEndpoints.GetAsync(resourceGroup, accountName, streamingEndpointName);
+
+ if (s != null && s.ResourceState == StreamingEndpointResourceState.Running)
{
- StreamingEndpoint s = await client.StreamingEndpoints.GetAsync(resourceGroup, accountName, streamingEndpointName);
+ // Stop the StreamingEndpoint
+ await client.StreamingEndpoints.StopAsync(resourceGroup, accountName, streamingEndpointName);
- if (s != null && s.ResourceState == StreamingEndpointResourceState.Running)
- {
- // Stop the StreamingEndpoint
- await client.StreamingEndpoints.StopAsync(resourceGroup, accountName, streamingEndpointName);
- }
+ Console.WriteLine($"StreamingEndpoint {streamingEndpointName} is stopped.");
+ Console.WriteLine();
+ }
- if (deleteEndpoint)
- {
- // Delete the StreamingEndpoint
- await client.StreamingEndpoints.DeleteAsync(resourceGroup, accountName, streamingEndpointName);
- }
+ if (deleteEndpoint)
+ {
+ // Delete the StreamingEndpoint
+ await client.StreamingEndpoints.DeleteAsync(resourceGroup, accountName, streamingEndpointName);
+
+ Console.WriteLine($"StreamingEndpoint {streamingEndpointName} is deleted.");
+ Console.WriteLine();
}
}
catch (ApiErrorException e)