All Projects → notedit → bls

notedit / bls

Licence: other
RTMP framework for Nodejs

Programming Languages

C++
36643 projects - #6 most used programming language
c
50402 projects - #5 most used programming language
javascript
184084 projects - #8 most used programming language

Projects that are alternatives of or similar to bls

sms
rtmp server and super media server whith golang.
Stars: ✭ 65 (+261.11%)
Mutual labels:  rtmp, flv
cordova-plugin-tencent-liteav
A cordova plugin for video playing with Tencent's LiteAV SDK. Support RTMP/HLS/FLV/MP4.
Stars: ✭ 24 (+33.33%)
Mutual labels:  rtmp, flv
Livego
live video streaming server in golang
Stars: ✭ 7,312 (+40522.22%)
Mutual labels:  rtmp, flv
Zlmediakit
WebRTC/RTSP/RTMP/HTTP/HLS/HTTP-FLV/WebSocket-FLV/HTTP-TS/HTTP-fMP4/WebSocket-TS/WebSocket-fMP4/GB28181 server and client framework based on C++11
Stars: ✭ 5,248 (+29055.56%)
Mutual labels:  rtmp, flv
tms
tms(toy media server) is a toy media server for myself learning media develop. Just for fun.
Stars: ✭ 29 (+61.11%)
Mutual labels:  rtmp, flv
Node Media Server
A Node.js implementation of RTMP/HTTP-FLV/WS-FLV/HLS/DASH/MP4 Media Server
Stars: ✭ 4,433 (+24527.78%)
Mutual labels:  rtmp, flv
Media Server
RTSP/RTP/RTMP/FLV/HLS/MPEG-TS/MPEG-PS/MPEG-DASH/MP4/fMP4/MKV/WebM
Stars: ✭ 1,363 (+7472.22%)
Mutual labels:  rtmp, flv
Monibuca
🧩 Monibuca is a Modularized, Extensible framework for building Streaming Server
Stars: ✭ 307 (+1605.56%)
Mutual labels:  rtmp, flv
Ffplayout Engine
python and ffmpeg based playout
Stars: ✭ 128 (+611.11%)
Mutual labels:  rtmp, broadcast
Harmonic
A high performance and scalable RTMP live streaming application framework
Stars: ✭ 121 (+572.22%)
Mutual labels:  rtmp, flv
Analysisavp
音视频学习,相关文件格式/协议分析。h264 nalu aac adts flv
Stars: ✭ 38 (+111.11%)
Mutual labels:  rtmp, flv
VideoCodecKit
iOS macOS 编解码库 脱离ffmpeg等外部依赖 支持H.264 H.265裸流播放 硬件编解码 rtmp推流等
Stars: ✭ 78 (+333.33%)
Mutual labels:  rtmp, flv
Rtmp
RTMP Server , RTMP Pusher , RTMP Client
Stars: ✭ 119 (+561.11%)
Mutual labels:  rtmp, flv
Media Server Go Demo
webrtc media server go demo
Stars: ✭ 140 (+677.78%)
Mutual labels:  rtmp, broadcast
ZLMediaKit
WebRTC/RTSP/RTMP/HTTP/HLS/HTTP-FLV/WebSocket-FLV/HTTP-TS/HTTP-fMP4/WebSocket-TS/WebSocket-fMP4/GB28181/SRT server and client framework based on C++11
Stars: ✭ 7,790 (+43177.78%)
Mutual labels:  rtmp, flv
react-native-ibeacon-simulator
Simulate device act as an iBeacon, or transmit as an iBeacon signal from your phone
Stars: ✭ 48 (+166.67%)
Mutual labels:  broadcast
minirtmp
Mini RTMP
Stars: ✭ 57 (+216.67%)
Mutual labels:  rtmp
KnzkLive
No ads, Unlimited, Open-Source Live Streaming Service.
Stars: ✭ 46 (+155.56%)
Mutual labels:  broadcast
smart rtmpd
RTMP server, smart, compact, high performance(c, c++), high concurrency, easy to maintain, easy to deploy, (supports multiple operating systems Windows and Linux, ARM, FreeBSD)
Stars: ✭ 159 (+783.33%)
Mutual labels:  rtmp
go-oryx-lib
The public multiple media library for https://github.com/ossrs/go-oryx.
Stars: ✭ 98 (+444.44%)
Mutual labels:  flv

bls

BLS is a rtmp server framework for Nodejs. This server is developed in libuv I/O framework which is used by Nodejs. So it's performace in case of a large number of clients push or pull stream data concurrently is very good. At the same time, you can add custom logics, such as auth/cluster, in this framework easily with js api. A variety of API are provided to manage RTMP stream, such as open and close a stream, get the quality of one stream.


Requirement

  • support nodejs 6.9. nodejs 0.1x is no longer supported.
  • Linux 64 bit

Install

npm install bls

Features of RTMP

  • Not the full RTMP protocal is supported. But the basic function of live play has been realised.
  • BLS cache the last gop of a stream. So player can show video picture very quickly.
  • Only support H264/AAC.
  • One client can only publishs/plays one stream just now.

Example

SimpleServer

A simple RTMP server. You can publish stream with ffmpeg, and play stream with flash/vlc/ffmpeg...

//simple_server.js

var server = require("bls");

var config = {
    //log file path bls write its own log to
    log_path : "log/bls.log",

    //trace:0 debug:1 info:2 warn:3 err:4 critical:5 off:6
    //if you use low level, bls will be more busy
    log_level : 1,

    //the maximum number of clients connect to server concurrently
    max_client_num : 2000,

    //port listen to
    port : 8956,

    //the interval seconds bls uses to send heartbeat msg to clients
    ping_pong_time : 10,
};

//record the publishing stream's name
var publishing_stream = {};

//start listen and serve as RTMP server
//cb func is called when a client connects(tcp connect) to server
//client argument presents a rtmp client
server.start_server(config, function(client){
    console.log("client come on! id: %s", client.client_id);

    //the callback func when this client sends RTMP connect command
    client.on("connect", function(trans_id, connect_info)
    {
        console.log("new client connect. %s tsid: %d connect_info: %j", 
            client.client_id, trans_id, connect_info);

        client.accept(true);
        //client.accept(false, "NetConnection.Connect.Rejected", "reject");
        
        //you can send any command to client
        //if you need result from client, the callback function must be set
        client.call("needResult", [{}, {data:66}], function(res_cmd, res_args){
            console.log("get result from client %s %s", res_cmd, res_args);
        });
    });

    //this client leave
    client.on("close", function(close_status)
    {
        console.log("%s client close ", client.client_id, close_status);

        if (client.publish_stream_name) {
            delete publishing_stream[client.publish_stream_name];
        }
    });

    //register a cb func when this client wants to publish a stream.
    //note: bls just allows one client publishs one stream now.
    client.on("publish", function(trans_id, cmd_objs, stream_name)
    {
        console.log("client call publish. tsid: %d cmd_objs: %j stream_name: %s",
            trans_id, cmd_objs, stream_name);

        //if this stream name is publishing, you can not publish the same stream name
        if (!publishing_stream[stream_name]) {
            //if you allow this client to publish stream with stream_name, just need to call publish function
            //trans_id must be same with trans_id in cb arguments
            //you can custom the stream name which bls uses to publish
            client.publish(trans_id, stream_name);

            publishing_stream[stream_name] = true;
            client.publish_stream_name = stream_name;
        } else {
            client.close();
        }
    });

    //register a cb func when this client wants to play a stream
    //note: bls just allows one client play one stream now.
    client.on("play", function(trans_id, cmd_obj, stream_name){
        console.log("client call play. tsid: %d cmd_objs: %j stream_name: %s",
            trans_id, cmd_obj, stream_name);

        if (publishing_stream[stream_name]) {
            //trans_id must be same with the cb arguments
            //you can choose a stream name for this client, not must be same with the client wants
            //
            //NOTE: you can also wait for publish src ready than call play method. In this example, 
            //we just close this player.
            client.play(trans_id, stream_name);
        } else {
            client.close();
        }
    });

    //when client publishs a stream, there will be a meta data in stream data
    //meta data size should not be bigger than MAX_BUFFER_LEN, default is 2KB
    client.on("onMetaData", function(meta_data){
        console.log("get metadata %j", meta_data);
    })

    //when this client call stop play command
    client.on("unplay", function(){
        console.log("client unplay stream......");
    });

    //when this client call unplish, which means this client wants stop publish stream
    client.on("unpublish", function(){
        console.log("client unpublish stream......");
    });

    //bls sends heartbeat to client with seconds interval, which is indicated in config
    //when client send back pong msg, which is required, this cb func will be called
    //delay indicates the transport delay between bls and client
    client.on("ping_pong_request", function(delay, recv_sum){
        console.log("get pong response! %d %d", delay, recv_sum);
    });

    //listen to custom command from client, so client can send custom data to bls
    client.on("customCmd", function(trans_id, cmd_obj, data){
        console.log("get user custom command. %s %s %s", trans_id, cmd_obj, data);

        var result = ["result data"];

        //you can answer client with "_result" or "_error"
        //trans_id must be same with the one in cb func arguments
        client.result("_result", trans_id, result);
    });

    client.enable_av_cb(function(av_type, timestamp, is_sh, is_key, data){
        console.log("get a %s data. ts:%d, is sequence header:%s, is key frame:%s", 
            av_type, timestamp, is_sh, is_key);
    });
    
    setTimeout(function(){
        client.disable_av_cb()
    }, 5000);
});

Cluster

A RTMP cluster with two hosts. The simple server upon runs as a source host. This edge server pull stream from source host.You can build more complex topo with BLS.

//test_edge_server.js

var bls = require("bls");

var config = {
	log_path : "log/bls_edge.log",
    log_level : 3,
	max_client_num : 20,
	port : 8900,
	ping_pong_time : 10,
};

var edged_stream = {};

var result = bls.start_server(config, function(client){
	console.log("client come on! id: %s", client.client_id);

	client.on("connect", function(trans_id, connect_info)
	{
		console.log("new client connect. tsid: %d connect_info: %j", 
			trans_id, connect_info);
		client.accept(true);
		//client.accept(false, "NetConnection.Connect.Rejected", "hehe");
	});

	client.on("close", function(close_status)
	{
		console.log("client close ", close_status);
	});

	client.on("play", function(trans_id, cmd_obj, stream_name){
		console.log("client call play. tsid: %d cmd_objs: %j stream_name: %s",
			trans_id, cmd_obj, stream_name);

        //if the stream has beed pull from src host,
        //then it can play directly.
        if (edged_stream[stream_name]) {
            console.log("play %s directly", stream_name);
		    client.play(trans_id, stream_name);
        } else {
            console.log("need pull from src host");
            pull_stream_from_src(stream_name, function(res) {
                if (res) {
                    edged_stream[stream_name] = true;
                    client.play(trans_id, stream_name);
                } else {
                    console.log("pull stream fail");
                    client.close();
                    console.log("debug");
                }
            });
        }
	});

	client.on("unplay", function(){
		console.log("client unplay stream......");
	});

	// setTimeout(function(){
	// 	client.close();
	// }, 5000);
});

function pull_stream_from_src(stream_name, cb_func){
    //connect remote src BLS first
	bls.remote_connect("127.0.0.1", 8956, function(edge_connect){

        //TCP connect success
		if(edge_connect)
		{
			console.log("connect remote server success.")

            var has_return = false;

            //you can send custom infomations to source BLS when doing RTMP connect
			edge_connect.connect({info:"custom info"}, function(results){
				console.log("send connect to remote server. recv:");
				console.dir(arguments);

				edge_connect.edge(stream_name, function(){
                    //Note: If this edge client is closed when waiting for edge result, 
                    //this call back will never be triggled.
                    console.log("edge complete");

                    //call back success
                    cb_func(true);
                    has_return = true;
                });
			});

            edge_connect.on("close", function(){
                console.log("edge for %s close", stream_name);
                
                if (!has_return) {
                    cb_func(false);
                }
            });
		}
		else
		{
			console.log("connect remote server fail");
            cb_func(false);
		}
	});

}

Performance

We test BLS's performance with many ffmpegs client connecting to BLS at a time pushing and pulling streams. One player plays one publisher, as a pair. With the number of pairs grows up, CPU idle is the main resource BLS takes. So we just forcus on usage of one CPU core. Result is shown below.

The rate of each stream is about 800Kb/s

number of pair CPU usage
300 10%
500 20%
1000 40%
2000 80%
3000 99%

API

Function: start_server(config, cb(client))


start a rtmp server. If start and listen fail, this process will just exit.

  • config [object] configuration for server, including log path / port and so on.
  • cb [function] callback function which is triggled when a new client come on TCP level. In this function, you can register many event callbacks for client, and control this client
    • client [BlsClient] callback argument. stand for a client, see detail about BlsClient

configure items:

Item required type description
log_path yes string log file path for bls to record detail info
log_level yes number trace:0 debug:1 info:2 warn:3 err:4 critical:5 off:6
max_client_num yes number how many clients the server can hold at the same time
port yes number the port server listens to
ping_pong_time no number the interval seconds server sends ping package for detecting whether this client is alive or not. Default 10.

Function:remote_connect(ip, port, cb(client))


Create a TCP connection to another bls server.

  • ip [string] remote bls server ip
  • port [number] remote bls server port
  • cb [function] callback function
    • client [BlsClient] callback argument. If connect fail client will be None, else it will be a BlsClient instance. You should call client.connect() method to complete RTMP connect.

Example

var bls = require("bls");
bls.remote_connect("127.0.0.1", 8955, function(edge_connect){
    if(edge_connect)
    {
        console.log("connect remote server success.")
        edge_connect.connect({info:"auth"}, function(flag, args){
            console.log("send connect to remote server. flag:%s args:%j", flag, args);
        });
    }
    else
    {
        console.log("connect remote server fail");
    }
});

Var:MAX_BUFFER_LEN


Indicate the max size of command data.

Class:BlsClient


BlsClient instance stands for a client that connects to server. A lot of events can be catched from a client, and you can control this client through APIs. BlsClient inherits from Emitter.

BlsClient.prototype.accept(allow, code, descript)


Decide whether accept this client in RTMP protocol.

  • allow [boolean] true means accept, false means reject

  • code [string] RTMP connect reject code. If allow is true, code is NetConnection.Connect.Success default. Otherwise it is [NetConnection.Connect.Error|NetConnection.Connect.Fail|...]

  • descript [string] description about rejection result.

    client.on("connect", function(trans_id, connect_info)
    {
        console.log("new client connect. %s tsid: %d connect_info: %j",
            client.client_id, trans_id, connect_info);

		//accept
        client.accept(true);
        ////reject
        //client.accept(false, "NetConnection.Connect.Rejected", "reject");
        });
    });

BlsClient.prototype.call(cmd_name, args_array, cb_func(result_flag, args))


Send user custom command to client. If result is not needed, cb_func should be None.

  • cmd_name [cmd_name] user custom command name
  • args_array [array] command args.
  • cb_func [function] callback function when client sends result according to this command.
    • result_flag [string] "_result" or "_error" recv from client.
    • args [array] result data recv from client

BlsClient.prototype.close()


Close this client connection.

BlsClient.prototype.edge(stream_name, cb())


This method is made for cluster. Local BLS can pull stream data from a remote BLS server as a source. Then player clients can play this stream from local BLS. The client must be producted from remote_connect function.

  • stream_name [string] the name of stream you want to pull from remote BLS. And this stream_name will be local stream name.
  • cb [function] called when pull finish, which means players can play the stream name from local BLS from now on.
bls.remote_connect("127.0.0.1", 8956, function(edge_connect){
    if(edge_connect)
    {
        console.log("connect remote server success.")
        edge_connect.connect({info:"hehe"}, function(results){
            console.log("send connect to remote server. recv:");
            console.dir(arguments);

            edge_connect.edge("78c1f9ba124611e4815aac853dd1c904", function(){
                console.log("edge complete");
            });
        });
    }
    else
    {
        console.log("connect remote server fail");
    }
});

BlsClient.prototype.get_aac_sh()


return aac sequence header data recieved from client.

BlsClient.prototype.get_avc_sh()


return avc sequence header data recieved from client.

BlsClient.prototype.is_closed()


return True if client is not alive.

BlsClient.prototype.play(trans_id, stream_name)


Allow client to play one stream.

Note: One client can only play one stream now. Note: If this stream name is not publishing, the player will never get stream data even if this stream publish later. So you can wait for publish soucre ready then call play method of player.

  • trans_id [number] must be same with trans id in play event
  • stream_name [number] indicates which stream is passed to client. The stream_name must be same with the publish one. But it is not necessary same with stream name in play event.

BlsClient.prototype.publish(trans_id, stream_name)


Allow client to publish one stream

Note: One client can only publish one stream at the same time.

  • trans_id [number] must be same with trans id in publish event.
  • stream_name [number] indicates the stream name to publish with this client.

BlsClient.prototype.push(stream_name, cb)


This method is made for cluster. Local BLS can push stream data to a remote BLS server as a source. Then player clients can play this stream from remote BLS. The BLS client must be producted from remote_connect function.

  • stream_name [string] the name of stream you want to push to remote BLS.
  • cb [function] called when push finish, which means players can play the stream name from remote BLS from now on.

BlsClient.prototype.result(result_flag, transid, args)


Send result to client according to the command received from client.

  • result_flag [string] "_result" or "_error"
  • transid [number] must be same with transid in command event
  • args [array] result data

Example:

    //listen to custom command from client, so client can send custom data to bls
    client.on("customCmd", function(trans_id, cmd_obj, data){
        console.log("get user custom command. %s %s %s", trans_id, cmd_obj, data);

        var result = ["result data"];

        //you can answer client with "_result" or "_error"
        //trans_id must be same with the one in cb func arguments
        client.result("_result", trans_id, result);
    });

BlsClient.prototype.unpublish()


Client stop publishing stream.

BlsClient.prototype.enable_av_cb(cb(av_type, timestamp, is_sh, is_key, data))


You can get each audio/video frame from client with this method.

  • cb [function] call back function called when get a frame
    • av_type [string] "video" or "audio"
    • timestamp [number] time stamp carried with this frame
    • is_sh [boolean] whether is sequence header data
    • is_key [boolean] whether is key frame
    • data [buffer] frame data

example:

client.enable_av_cb(function(av_type, timestamp, is_sh, is_key, data){
    console.log("get a %s data. ts:%d, is sequence header:%s, is key frame:%s", 
        av_type, timestamp, is_sh, is_key);
});

BlsClient.prototype.disable_av_cb()


don't throw up audio/video data to js call back function.

Event:connect(trans_id, connect_info)


Emitted when a client send RTMP connect command to BLS.

  • trans_id [number] rtmp protocol needs.
  • connect_info [object] connect information recieved from client.

Event:close(close_status)


Emitted when client leave.

Event:publish(trans_id, cmd_objs, stream_name)


Emitted when client wants to publish a stream

Event:play(trans_id, cmd_obj, stream_name)


Emitted when client wants to play a stream

Event:play_stop_event()


When a stream stop publishing, players to this source will get this event emitted.

Event:onMetaData(meta_data)


Emitted when recieved meta data from client in process of publish stream.

Event:unplay()


Emitted when client stop play stream.

Event:unpublish()


Emitted when client stop publish stream.

Event:ping_pong_request(delay, recv_sum)


Emitted when client send pong response to BLS.

  • delay [number] delay after BLS send ping request to client.
  • recv_sum [number] how many bytes recved from client totally.

Event:{customCommand}(trans_id, cmd_obj, data)


Emitted when receive user custom command.

Note that the project description data, including the texts, logos, images, and/or trademarks, for each open source project belongs to its rightful owner. If you wish to add or remove any projects, please contact us at [email protected].