Category: HTML5

Recently, I’m working out a system to smoothly stream live events for an organization. That is pretty new to me and, after a bunch of research, found that Nginx with the RTMP module seems to be a good choice. There are many difficulties when setting all this up and after several days of testing, I found a good setting that is worth a post.

Setup Nginx and RTMP module

First, let’s get Nginx set up. In order to use the RTMP module, we need to compile that as an Nginx module. It would look something like this:

If you can see that Nginx RTMP is included, you can go to the next step. Before we proceed to configuring Nginx for live streaming, we should confirm what kind of resolution we should provide for live streams and how much hardware power you have.

Prerequisites

For converting live streams into several streams for adaptive streaming, you need to make sure your server have enough CPU for such workload. Otherwise, the live stream will suffer from continuous delays and/or server becomes unresponsive. I have spawn some EC2 c3.large and c3.xlarge instances, test with them and I found out their optimized CPU can handle such workload with ease. Something that also worth mention is about the I/O limits of the disks. If possible, store the HLS fragments generated to an high-speed SSD helps maintain smooth streaming experiences.

CPU Usage when using an EC2 c3.xlarge instance.

Then, you also need to think about what kind of resolutions you will be offering for adaptive streaming. Generally about 4-5 variants are good enough to provide great loading speeds for different network speeds and devices. Here’s my recommended list of variants used for live streaming:

240p Low Definition stream at 288kbps

480p Standard Definition stream at 448kbps

540p Standard Definition stream at 1152kbps

720p High Definition stream at 2048kbps

Source resolution, source bitrate

Configuring nginx for live streaming

Here is my own nginx.conf with comments that you can have references on.

Sometimes we need to feed videos dynamically from the server-side. If you’re feeding the video to a HTML5 <video> element, you may find that the video progress controls freezes and users cannot move it in any ways. (Thought this situation only happens in some browsers like Chrome and Firefox, the user experience hurts a lot.)

With a bit of investigation, I found out that Chrome requested the video with an HTTP range request which, the server-side handle it incorrectly and Chrome falls back to progressive downloading the video. With the little PHP script I wrote below, the server-side can now handle the HTTP range requests normally and the progress controls no longer freezes! (There’s one more benefit: fast forward and backward works much smoother in large video files.)

PHP handles HTTP range requests.

PHP

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

<?php

// Clears the cache and prevent unwanted output

ob_clean();

@ini_set('error_reporting',E_ALL&~E_NOTICE);

@apache_setenv('no-gzip',1);

@ini_set('zlib.output_compression','Off');

$file="/path/to/your/media/file";// The media file's location

$mime="application/octet-stream";// The MIME type of the file, this should be replaced with your own.

$size=filesize($file);// The size of the file

// Send the content type header

header('Content-type: '.$mime);

// Check if it's a HTTP range request

if(isset($_SERVER['HTTP_RANGE'])){

// Parse the range header to get the byte offset

$ranges=array_map(

'intval',// Parse the parts into integer

explode(

'-',// The range separator

substr($_SERVER['HTTP_RANGE'],6)// Skip the `bytes=` part of the header

)

);

// If the last range param is empty, it means the EOF (End of File)

if(!$ranges[1]){

$ranges[1]=$size-1;

}

// Send the appropriate headers

header('HTTP/1.1 206 Partial Content');

header('Accept-Ranges: bytes');

header('Content-Length: '.($ranges[1]-$ranges[0]));// The size of the range

Have you ever seen some visual effects when playing music with your favourite music player? (Here’s some example photos.)

This is just… great. But how they do this kind of effects? We need to understand how sound is made first. Sound is actually the vibrations of air (and more generally, objects) and the change in air pressure is recorded using a microphone. Everytime when you play a music, the speakers generates the vibrations using the change in air pressures recorded by microphone.

We can make use of these data to make visual effects from sounds. In this tutorial, I’ll teach you how to create a visualization like this:

In this demonstration, we’ll be able to drop audio files in and play the music with visuals. OK! Let’s start!

First, we need to set up the HTML for our visuals. It’ll be pretty simple as we only need a canvas.

When I first learn node.js, I learned how to use socket.io, a node.js module for real-time communication between the client and server. However, when I’m going back coding PHP for a while, I started to figure out only few PHP libraries offered this functions and the techniques they uses are old (AJAX Streaming, Forever <iframe>, etc.). One day I found a new technique called Server-sent Events and it’s pretty easy to implant. I have an idea of creating an interface for Server-sent Events in order to speed up development and make it easier to use. libSSE is the library I’ve create just for this and it’s event-based which means data is sent only when an event happens. It also has some utility classes for communicate with other PHP scripts.