Azure Media Services just announced the public preview of its Live streaming service. This tutorial will show you how to set up live streaming with Azure Media Services .NET SDK. You can download full source code in our GitHub. Meanwhile, if you want to skip the coding part, please check out Getting Started with Live Streaming Using the Azure Management Portal.
1. Create a console application on .NET 4.0. You can get Media Services .NET SDK through Nuget, by searching windowsazure.mediaservices.
2. Please add the following code into your app.config. You can find Account Name and Account Key in Azure Management portal.
3. Connect to Azure Media Services through CloudMediaContext in program.cs.
private const string StreamingEndpointName = "streamingendpoint001"; private const string ChannelName = "channel001"; private const string AssetlName = "asset001"; private const string ProgramlName = "program001"; // Read values from the App.config file. private static readonly string _mediaServicesAccountName = ConfigurationManager.AppSettings["MediaServicesAccountName"]; private static readonly string _mediaServicesAccountKey = ConfigurationManager.AppSettings["MediaServicesAccountKey"]; // Field for service context. private static CloudMediaContext _context = null; private static MediaServicesCredentials _cachedCredentials = null; static void Main(string[] args) { // Create and cache the Media Services credentials in a static class variable. _cachedCredentials = new MediaServicesCredentials( _mediaServicesAccountName,_mediaServicesAccountKey); // Used the cached credentials to create CloudMediaContext. _context = new CloudMediaContext(_cachedCredentials); }
4. Create live channel and start the Channel. Channels are the fundamental entity in Azure Media Services that allows you to ingest a live stream. Each Channel will have an ingest URL and a preview URL, it can also have one or more Programs associated with it. It usually takes around 2 minutes to start a Channel but could take as much as 20 minutes. You don’t have to start the Channel right away, usually people set up the Channel in advance but wait to start it until their live event is about to start.
public static IChannel CreateAndStartChannel() { IChannel channel = _context.Channels.Create( new ChannelCreationOptions { Name = ChannelName, Input = CreateChannelInput(), Preview = CreateChannelPreview(), Output = CreateChannelOutput() }); channel.Start(); Console.WriteLine("Starting Channel " + ChannelName); Console.WriteLine("Channel's ingest URL " + channel.Input.Endpoints.FirstOrDefault().Url.ToString()); Console.WriteLine("Channel's preview URL " + channel.Preview.Endpoints.FirstOrDefault().Url.ToString()); return channel; }
5. We will implement each of the methods in part 4. Here is how to create a Channel. When creating a Channel you can choose the ingest protocol it supports either Fragmented Mp4 (Smooth Streaming) or RTMP. In Access Control, you will need to define IP allow list to permit Ingest point access, you can either lock it down to your specific machine or open it to a range of IP addresses. To open it to all IP addresses set it to “0.0.0.0/0”.
private static ChannelInput CreateChannelInput() { return new ChannelInput { StreamingProtocol = StreamingProtocol.FragmentedMP4, AccessControl = new ChannelAccessControl { IPAllowList = new List{ new IPRange { Name = "TestChannelInput001", Address = IPAddress.Parse("0.0.0.0"), SubnetPrefixLength = 0 } } } }; }
6. Create Channel Preview and channel output.
private static ChannelPreview CreateChannelPreview() { return new ChannelPreview { AccessControl = new ChannelAccessControl { IPAllowList = new List{ new IPRange { Name = "TestChannelPreview001", Address = IPAddress.Parse("0.0.0.0"), SubnetPrefixLength = 0 } } } }; } private static ChannelOutput CreateChannelOutput() { return new ChannelOutput { Hls = new ChannelOutputHls { FragmentsPerSegment = 1 } }; }
7. Putting the following lines into main to create Channel, and print out ingest URL and Preview URL. Ingest URL is the push destination you will give to your live encoder (please refer to Live encoder configuration blog if you want to set up encoder such as Wirecast). Once you have configured your live encoder and started it, you should be able to watch the stream from Preview URL in order to verify that your stream is being ingested properly.
IChannel channel = CreateAndStartChannel(); // Set the Live Encoder to point to the channel's input endpoint: Console.WriteLine("Channel's ingest URL " + channel.Input.Endpoints.FirstOrDefault().Url.ToString()); // Use the previewEndpoint to preview and verify // that the input from the encoder is actually reaching the Channel. Console.WriteLine("Channel's preview URL " + channel.Preview.Endpoints.FirstOrDefault().Url.ToString());
8. If you want to persist your stream and make it available to your audience you need to create a Program and Streaming Endpoint. Let’s put the following code into the Main method.
// Once you previewed your stream and verified that it is flowing into your Channel, // you can create an event by creating an Asset, Program, and Streaming Locator. IProgram program = CreateAndStartProgram(channel); ILocator locator = CreateLocatorForAsset(program.Asset, program.ArchiveWindowLength); IStreamingEndpoint streamingEndpoint = CreateAndStartStreamingEndpoint(); GetLocatorsInAllStreamingEndpoints(program.Asset); Console.ReadLine();
9. A Program enables you to control the publishing and storage of a live stream. You can run up to three Programs concurrently, this allows you to publish and archive different parts of the stream as needed.
You can specify the number of hours you want to retain the recorded content for the Program by setting the ArchiveWindowLength property. This value can be set from a minimum of 5 minutes to a maximum of 25 hours. This also dictates the maximum amount of time viewers can seek back in time from the current live position. Programs can run over the specified amount of time, but content that falls behind the window length is continuously discarded.
public static IProgram CreateAndStartProgram(IChannel channel) { IAsset asset = _context.Assets.Create(AssetlName, AssetCreationOptions.None); // Create a Program on the Channel. You can have multiple Programs that overlap or are sequential; // however each Program must have a unique name within your Media Services account. IProgram program = channel.Programs.Create(ProgramlName, TimeSpan.FromHours(3), asset.Id); program.Start(); Console.WriteLine("Starting Program " + Program.ProgramlName); return program; }
10. After that, you must create a Streaming Locator in order to access the stream. The Streaming Locator makes the Asset you associated with your Program available for streaming through your Streaming Endpoint. When creating your Streaming Locator you can set an access policy for the streaming access to the Asset.
public static ILocator CreateLocatorForAsset(IAsset asset, TimeSpan ArchiveWindowLength) { var locator = _context.Locators.CreateLocator ( LocatorType.OnDemandOrigin, asset, _context.AccessPolicies.Create ( "Live Stream Policy", ArchiveWindowLength, AccessPermissions.Read ) ); return locator; }
11. Lastly, you need to create a Streaming Endpoint and get the locator URL. A single Media Services account can have multiple Streaming Endpoints. You may want to have multiple Streaming Endpoints if you want to have different configurations for each (for example, security settings, cross site access policies, scale units, etc.) or if you want to separate your Video on Demand (VOD) and Live streaming.
public static IStreamingEndpoint CreateAndStartStreamingEndpoint() { var options = new StreamingEndpointCreationOptions { Name = StreamingEndpointName, ScaleUnits = 1, AccessControl = GetAccessControl(), CacheControl = GetCacheControl() }; IStreamingEndpoint streamingEndpoint = _context.StreamingEndpoints.Create(options); streamingEndpoint.Start(); return streamingEndpoint; } private static StreamingEndpointAccessControl GetAccessControl() { return new StreamingEndpointAccessControl { IPAllowList = new List{ new IPRange { Name = "Allow all", Address = IPAddress.Parse("0.0.0.0"), SubnetPrefixLength = 0 } }, AkamaiSignatureHeaderAuthenticationKeyList = new List { new AkamaiSignatureHeaderAuthenticationKey { Identifier = "My key", Expiration = DateTime.UtcNow + TimeSpan.FromDays(365), Base64Key = Convert.ToBase64String(GenerateRandomBytes(16)) } } }; } private static byte[] GenerateRandomBytes(int length) { var bytes = new byte[length]; using (var rng = new RNGCryptoServiceProvider()) { rng.GetBytes(bytes); } return bytes; } private static StreamingEndpointCacheControl GetCacheControl() { return new StreamingEndpointCacheControl { MaxAge = TimeSpan.FromSeconds(1000) }; } public static void GetLocatorsInAllStreamingEndpoints(IAsset asset) { var locators = asset.Locators.Where(l => l.Type == LocatorType.OnDemandOrigin); var ismFile = asset.AssetFiles.AsEnumerable().FirstOrDefault(a => a.Name.EndsWith(".ism")); var template = new UriTemplate("{contentAccessComponent}/{ismFileName}/manifest"); var urls = locators.SelectMany(l => _context .StreamingEndpoints .AsEnumerable() .Where(se => se.State == StreamingEndpointState.Running) .Select( se => template.BindByPosition(new Uri("http://" + se.HostName), l.ContentAccessComponent, ismFile.Name))) .ToArray(); foreach(var url in urls){ Console.WriteLine(url); } }
12. Now you can run the Program and enjoy the live stream. You can download full source code in our GitHub. And all these settings could be viewed through our Azure portal as well.