Introduction
No matter what kind of project you are working on, at some point you will find the need to stream videos in your website or mobile apps for many purposes. So, we will learn how we can live stream our video content over HTTP, using ASP.NET Web APIs.
This is my first ever writing on ASP.NET Web APIs, so I’ll try my best to deliver what I learned about HTTP, REST, Web Services, Web API's and as well as asynchronous programming. As the article is about how to live stream videos with ASP.NET Web APIs, I still have to introduce other terminologies listed above for the folks who don’t already know about them. At the end, we will learn how we can set up a web service using ASP.NET Web APIs to live stream the videos asynchronously over HTTP protocol.
Background
I assume that you already have experience working with C# in ASP.NET (MVC, Web APIs) and generally know about how the Web works, about HTTP, about Server and client. You don’t need to be a master of them but you must have fair knowledge to follow along.
I’m also assuming that you have basic familiarity of working with Visual Studio. I’ll be using Visual Studio 2015 with Update 2 for this demo. If you are using Visual Studio 2013, then it’s perfectly fine.
ASP.NET Web APIs and REST
ASP.NET Web API is a new framework that Microsoft included in ASP.NET family of technologies. Using ASP.NET Web APIs, we can create online Web Services or Web APIs, which client apps can consume to retrieve, update and delete data over HTTP. Web services normally serve data in form of JSON or XML.
The term API stands for Application Programming Interface, so whether someone say Web API or Web Service, it’s the same thing. Online Web Services have different names and formats like SOAP based Services and most popular of them is REST or RESTful Services.
REST stands for Representational State Transfer. REST is an architectural pattern, which is used to create online Web Services to serve data in form of JSON and XML over HTTP protocol and that’s what exactly ASP.NET Web APIs are there for. Finally, we know we can create RESTful Services with ASP.NET Web APIs.
Asynchronous Programming
In asynchronous programming, we perform multiple tasks simultaneously parallel to each other at same time and the parallel running threads notify back to calling thread after the completion of the task. In C# the best practice is to use TPL (Task Parallel Library) for parallel programming instead of using System.Threaing.Thread. Task provides you more control over threads.
If a task is not CPU bound but instead it's I/O bound or network bound where calling threads have to wait for database to respond or have to wait for a network call to respond, then we should use asynchronous pieces of code with async and await key words. If you are not already familiar with asynchronous programming with asyn and await, then click here to learn because Microsoft has made it very easy to write asynchronous code blocks with async and await for IO and Network bound tasks. Remember in IO or Network bound tasks thread remains idle to wait for response, instead why don’t we use them perform some other tasks because we have limited resources.
Now, there is one question left in our minds: “What is Asynchronous Live streaming?”
What is Asynchronous Video Streaming?
In asynchronous video streaming, we send packets of data to the receiving client instead of sending the complete file and the client will be the browser in our case. For asynchronous live streaming with ASP.NET Web APIs, we will make use of PushStreamContent class. The PushStreamContent class makes it possible to gradually send packets of data to the receiving client. With asynchronous streaming, we are reducing the load at server side so that the Server doesn’t have to serve the whole file at a time, instead it can serve it with specific size of packets.
At client side, we will use HTML 5 video element to playback the received video content. As we are asynchronously delivering the video content to the client, we don’t have to wait for the whole file to be downloaded. The playback will be immediately started. As long as client will be requesting for data, the server will be serving the client and if client disconnects, the streaming will be finished.
Demo
A lot more chit chat... So now, let’s create a handy ASP.Net MVC app that can stream videos from Server.
Remember, ASP.Net Web APIs are built from ASP.Net MVC, so the same conventions apply here too and you can also add a Web API controller inside an MVC project which is perfectly fine in ASP.Net 4.5. In fact, you can start from any ASP.NET project and later, you can add any component in it from ASP.NET family of technologies whether it's Web API controller, MVC controller, Web form, or SignalR hub.
- Create a new empty ASP.NET project with folder structure selected as MVC and paste any sample video in root directory of project for demo purposes.
- Right click on Controllers folder and add new Web API 2 empty controller with any name. In my case, I’ll name it SampleController.
- Now, first we have to read the file from server with FileStream so that we can write to output stream. Now, we’ll create a new Helper method that can read the file and write it output stream. Paste the following code in SampleController which is not a good practice but we can do this for demo purposes.
- public async void WriteContentToStream(Stream outputStream, HttpContent content, TransportContext transportContext) {
-
- var filePath = HttpContext.Current.Server.MapPath("~/MicrosoftBizSparkWorksWithStartups.mp4");
-
- int bufferSize = 1000;
- byte[] buffer = new byte[bufferSize];
-
- using(var fileStream = new FileStream(filePath, FileMode.Open, FileAccess.Read, FileShare.Read)) {
- int totalSize = (int) fileStream.Length;
-
-
-
- while (totalSize > 0) {
- int count = totalSize > bufferSize ? bufferSize : totalSize;
-
- int sizeOfReadedBuffer = fileStream.Read(buffer, 0, count);
-
- await outputStream.WriteAsync(buffer, 0, sizeOfReadedBuffer);
-
- totalSize -= sizeOfReadedBuffer;
- }
- }
- }
- Create a new action method with name GetVideoContent. Again, I am assuming that you have basic familiarity with ASP.NET web APIs and know how routing works. In GetVideoContent action, we will write the code that can gradually write our video's content returned from WriteContentToStream to HTTP response.
- public HttpResponseMessage GetVideoContent() {
- var httpResponce = Request.CreateResponse();
- httpResponce.Content = new PushStreamContent((Action < Stream, HttpContent, TransportContext > ) WriteContentToStream);
- return httpResponce;
- }
- Now, at server side, the final thing left is to register a route so that we can call into our GetVideoContent action with URL “api/Sample”.
- public static void Register(HttpConfiguration config) {
- config.MapHttpAttributeRoutes();
- config.Routes.MapHttpRoute(name: "DefaultApi", routeTemplate: "api/{controller}/{id}", defaults: new {
- id = RouteParameter.Optional
- });
- }
- Now, our Server is ready to serve the content on HTTP Get request at “api/Sample”. At client side, all we need is an HTML 5 video element with src=” api/Sample”. Create a new HTML file and put HTML 5 video element in it.
Now, right click in file and click view in browser.
And finally, now you can see the playback.
I’m using my own media player but you can use the default controls for demo purpose and I’m assuming you know how to use HTML 5 controls.
SampleController.cs
- using System;
- using System.IO;
- using System.Net;
- using System.Net.Http;
- using System.Web;
- using System.Web.Http;
- namespace MediaPlayer.Controllers {
- public class SampleController: ApiController {
- public HttpResponseMessage GetVideoContent() {
- var httpResponce = Request.CreateResponse();
- httpResponce.Content = new PushStreamContent((Action < Stream, HttpContent, TransportContext > ) WriteContentToStream);
- return httpResponce;
- }
- public async void WriteContentToStream(Stream outputStream, HttpContent content, TransportContext transportContext) {
-
- var filePath = HttpContext.Current.Server.MapPath("~/MicrosoftBizSparkWorksWithStartups.mp4");
-
- int bufferSize = 1000;
- byte[] buffer = new byte[bufferSize];
-
- using(var fileStream = new FileStream(filePath, FileMode.Open, FileAccess.Read, FileShare.Read)) {
- int totalSize = (int) fileStream.Length;
-
-
-
- while (totalSize > 0) {
- int count = totalSize > bufferSize ? bufferSize : totalSize;
-
- int sizeOfReadedBuffer = fileStream.Read(buffer, 0, count);
-
- await outputStream.WriteAsync(buffer, 0, sizeOfReadedBuffer);
-
- totalSize -= sizeOfReadedBuffer;
- }
- }
- }
- }
- }
WebApiConfig.cs
- using System.Web.Http;
- namespace MediaPlayer {
- public static class WebApiConfig {
- public static void Register(HttpConfiguration config) {
- config.MapHttpAttributeRoutes();
- config.Routes.MapHttpRoute(name: "DefaultApi", routeTemplate: "api/{controller}/{id}", defaults: new {
- id = RouteParameter.Optional
- });
- }
- }
- }