Video Streaming with Akka

Orji samuel
5 min readMay 3, 2020

--

I recently worked on a project, where I had to implement a streaming service where users could skip ahead to the content they wanted and stop the stream whenever they wanted. I decided to apply the same principle to video streaming and here is how I implemented it with Akka http and Akka Streams, as well as manually sending chunks of data to the client.

It’s pretty evident that streaming data to a client is needed if you don’t want to deal with having to load so much data into memory. If I had a 3GB file that I need to send from my server to a client, it’s impractical to load the data into memory before sending, a better approach is to stream the data by reading smaller chunks of the file gradually and then sending to the client. Here is a very basic barebone example of me using Akka Streams to stream a 2GB video file to be downloaded by the client.

Nothing much to see here, I just got a reference to the movie file and easily streamed the file to the user with the Content-Disposition header which tells the browser that we want the movie to be downloaded as an attachment with the right filename.

We then use FileIO.fromPath from Akka Streams to stream the movie to the client, using the application/octet-stream Content-Type. This is the basic principle of how I used to stream different kinds of data from databases, s3 to clients. This was my first time streaming with HTML and this kind of streaming just didn’t work.

<!DOCTYPE html>
<html>
<body>
<video width="320" height="240" controls>
<source src="http://localhost:9092/download" type="video/mp4">
Your browser does not support the video tag.
</video>
</body>
</html>

I then figured out that the streaming service I had previously implemented wasn’t compatible with what was required by the client with the html tag. I read this wikipedia entry and figured out that the video tag doesn’t work like regular streaming technologies or Flash, It actually performs chunking by making use of Http RANGE requests to start playing a video without actually having to download the whole video first. So I then had to implement that using akka-http.

Request header for video tag

Looking at the request header from the video tag, you’ll see the header RANGE:bytes=0-, this is saying, give me content starting from the first or zero position. Subsequent requests will be made to the src url with different positions to indicate what part of the stream that is of interest to the front end, another example of such subsequent request is shown below.

Now to handle these requests, I took these basic steps

  1. Read the Range header to fetch how much data is needed by the video tag
  2. Stream the requested chunk of data back to the client along with the right headers.

Yeah, it’s really just this simple, although some other things are involved in the process. The first thing is what kind of response we need to send back to the client, here are the response headers that were needed to be sent in my case.

Content-Range: bytes ${start}-${end}/${fileSize} 
Accept-Ranges: bytes,
Content-Length: chunksize, //usually (end - start)
Content-Type: video/mp4,

These headers are pretty self explanatory, we send the Content-Range, so the video tag doesn’t ask for more bytes than expected or exceed the range, start is where the client asked us to read from, end is the maximum limit of data we can send and fileSize corresponds to the overall length of the file. We also send the Content-Length as well as the Content-Type which is video/mp4 in my case. It’s also important to note that the Http Status Code should be 216, for partial content. Yeah enough talk, let’s see some code, here is how I did this in akka-http

What I did here is pretty simple, I extract the Range header, get the start as well as end position, using the same streaming technique as provided by Akka Streams, but here instead of attempting to stream the whole file everytime, I just jump to the point where I want to start the stream from as supplied by the third parameter to FileIO.fromPath, and responded with the right headers. You may ask, where’s the Content-Length ,Content-Type header as well as the 216 status code, all that is handled by the HttpResponse with a status code of PartialContent, Content-Type is supplied by the MediaTypes.`video/mp4` and whatever amount of data that was read by the stream is supplied as the Content-Length, here is an example of a request-response cycle for one of the video tag requests

With this, it’s really so easy to stream my video, and when the user skips to a particular point in the video, the video tag just fetches data starting from the point the user asks for.

Please note that in this case where the video tag was used, it’s important that the response status code is 216, I tried to use 200, but it only kept on restarting the stream from the beginning whenever I wanted to skip ahead or behind

The only issue I had with this method was that I wasn’t in control of how much chunk of data that was sent to the client, what If I wanted to apply some sort of compression or apply adaptive bitrate streaming or transcoding to each chunk of data?. I could do it with akka streams, but here is a simpler alternative solution I came up with to read a fixed length of only certain parts of a file.

In this method, I try to read only 4MB of data at a time, and I make use of a RandomAccessFile to skip to the position we want to start reading from.
With this method, the readChunk variable actually references the byte Array that contains your data, and you can then perform whatever task you intended to perform on it or forward the data to another machine for some sort of processing.

The only downside to this is that your browser tends to make more requests than the previous example as each request is bound to return a maximum of 4MB as shown below.

This post is definitely not exhaustive as there are other nuances involved in streaming data, but this was able to suffice in my case.

If you know a better way of doing this, feel free to add a comment.

For more reading, here is an article on streaming with youtube

--

--

Orji samuel

Scala and Golang Developer, Fitness Addict, Loves watching movies and making music in my spare time.