Git Product home page Git Product logo

node-media-server's Introduction

Node-Media-Server

npm npm npm npm Join the chat at https://gitter.im/Illuspas/Node-Media-Server

A Node.js implementation of RTMP/HTTP-FLV/WS-FLV/HLS/DASH Media Server

NodeMediaServer V3

https://www.nodemedia.cn/product/node-media-server/

Web Admin Panel Source

https://github.com/illuspas/Node-Media-Server-Admin

Web Admin Panel Screenshot

http://server_ip:8000/admin

admin preview

Features

  • Cross platform support Windows/Linux/Unix
  • Support H.264/AAC/MP3/SPEEX/NELLYMOSER/G.711
  • Extension support H.265(flv_id=12)/OPUS(flv_id=13)
  • Support GOP cache
  • Support remux to LIVE-HTTP/WS-FLV, Support NodePlayer.js playback
  • Support remux to HLS/DASH/MP4
  • Support xycdn style authentication
  • Support event callback
  • Support https/wss
  • Support Server Monitor
  • Support Rtsp/Rtmp relay
  • Support api control relay
  • Support real-time multi-resolution transcoding
  • Support Enhancing RTMP, FLV (HEVC/AV1 encoding using OBS)

Usage

npx

npx node-media-server

install as a global program

npm i node-media-server -g
node-media-server

docker version

docker run --name nms -d -p 1935:1935 -p 8000:8000 -p 8443:8443 illuspas/node-media-server

npm version (recommended)

mkdir nms
cd nms
npm install node-media-server
vi app.js
const NodeMediaServer = require('node-media-server');

const config = {
  rtmp: {
    port: 1935,
    chunk_size: 60000,
    gop_cache: true,
    ping: 30,
    ping_timeout: 60
  },
  http: {
    port: 8000,
    allow_origin: '*'
  }
};

var nms = new NodeMediaServer(config)
nms.run();
node app.js

Publishing live streams

From FFmpeg

If you have a video file with H.264 video and AAC audio:

ffmpeg -re -i INPUT_FILE_NAME -c copy -f flv rtmp://localhost/live/STREAM_NAME

Or if you have a video file that is encoded in other audio/video format:

ffmpeg -re -i INPUT_FILE_NAME -c:v libx264 -preset veryfast -tune zerolatency -c:a aac -ar 44100 -f flv rtmp://localhost/live/STREAM_NAME

From OBS

Settings -> Stream

Stream Type : Custom Streaming Server

URL : rtmp://localhost/live

Stream key : STREAM_NAME?sign=expires-HashValue (sign parameter required only if publish auth is enabled)

Accessing the live stream

RTMP

rtmp://localhost/live/STREAM_NAME

http-flv

http://localhost:8000/live/STREAM_NAME.flv

websocket-flv

ws://localhost:8000/live/STREAM_NAME.flv

HLS

http://localhost:8000/live/STREAM_NAME/index.m3u8

DASH

http://localhost:8000/live/STREAM_NAME/index.mpd

via flv.js over http-flv

<script src="https://cdn.bootcss.com/flv.js/1.5.0/flv.min.js"></script>
<video id="videoElement"></video>
<script>
    if (flvjs.isSupported()) {
        var videoElement = document.getElementById('videoElement');
        var flvPlayer = flvjs.createPlayer({
            type: 'flv',
            url: 'http://localhost:8000/live/STREAM_NAME.flv'
        });
        flvPlayer.attachMediaElement(videoElement);
        flvPlayer.load();
        flvPlayer.play();
    }
</script>

via flv.js over websocket-flv

<script src="https://cdn.bootcss.com/flv.js/1.5.0/flv.min.js"></script>
<video id="videoElement"></video>
<script>
    if (flvjs.isSupported()) {
        var videoElement = document.getElementById('videoElement');
        var flvPlayer = flvjs.createPlayer({
            type: 'flv',
            url: 'ws://localhost:8000/live/STREAM_NAME.flv'
        });
        flvPlayer.attachMediaElement(videoElement);
        flvPlayer.load();
        flvPlayer.play();
    }
</script>

Logging

Modify the logging type

It is now possible to modify the logging type which determines which console outputs are shown.

There are a total of 4 possible options:

  • 0 - Don't log anything
  • 1 - Log errors
  • 2 - Log errors and generic info
  • 3 - Log everything (debug)

Modifying the logging type is easy - just add a new value logType in the config and set it to a value between 0 and 4. By default, this is set to show errors and generic info internally (setting 2).

For custom log handling, see events for log message logMessage, errorMessage, debugMessage, and ffDebugMessage.

The logger events noted above are fired independently of the log level set by logType

const NodeMediaServer = require('node-media-server');

const config = {
  logType: 3,

  rtmp: {
    port: 1935,
    chunk_size: 60000,
    gop_cache: true,
    ping: 30,
    ping_timeout: 60
  },
  http: {
    port: 8000,
    allow_origin: '*'
  }
};

var nms = new NodeMediaServer(config)
nms.run();

Authentication

Encryption URL consists of:

rtmp://hostname:port/appname/stream?sign=expires-HashValue
http://hostname:port/appname/stream.flv?sign=expires-HashValue
ws://hostname:port/appname/stream.flv?sign=expires-HashValue

1.Publish or play address:

rtmp://192.168.0.10/live/stream

2.Config set auth->secret: 'nodemedia2017privatekey'

const config = {
  rtmp: {
    port: 1935,
    chunk_size: 60000,
    gop_cache: true,
    ping: 30,
    ping_timeout: 60
  },
  http: {
    port: 8000,
    allow_origin: '*'
  },
  auth: {
    play: true,
    publish: true,
    secret: 'nodemedia2017privatekey'
  }
}

3.expiration time: 2017/8/23 11:25:21 ,The calculated expiration timestamp is

1503458721

4.The combination HashValue is:

HashValue = md5("/live/stream-1503458721-nodemedia2017privatekey”)
HashValue = 80c1d1ad2e0c2ab63eebb50eed64201a

5.Final request address

rtmp://192.168.0.10/live/stream?sign=1503458721-80c1d1ad2e0c2ab63eebb50eed64201a
The 'sign' keyword can not be modified

H.265 over RTMP

AV1 over RTMP

  • OBS 29.1+

Event callback

......
nms.run();
nms.on('preConnect', (id, args) => {
  console.log('[NodeEvent on preConnect]', `id=${id} args=${JSON.stringify(args)}`);
  // let session = nms.getSession(id);
  // session.reject();
});

nms.on('postConnect', (id, args) => {
  console.log('[NodeEvent on postConnect]', `id=${id} args=${JSON.stringify(args)}`);
});

nms.on('doneConnect', (id, args) => {
  console.log('[NodeEvent on doneConnect]', `id=${id} args=${JSON.stringify(args)}`);
});

nms.on('prePublish', (id, StreamPath, args) => {
  console.log('[NodeEvent on prePublish]', `id=${id} StreamPath=${StreamPath} args=${JSON.stringify(args)}`);
  // let session = nms.getSession(id);
  // session.reject();
});

nms.on('postPublish', (id, StreamPath, args) => {
  console.log('[NodeEvent on postPublish]', `id=${id} StreamPath=${StreamPath} args=${JSON.stringify(args)}`);
});

nms.on('donePublish', (id, StreamPath, args) => {
  console.log('[NodeEvent on donePublish]', `id=${id} StreamPath=${StreamPath} args=${JSON.stringify(args)}`);
});

nms.on('prePlay', (id, StreamPath, args) => {
  console.log('[NodeEvent on prePlay]', `id=${id} StreamPath=${StreamPath} args=${JSON.stringify(args)}`);
  // let session = nms.getSession(id);
  // session.reject();
});

nms.on('postPlay', (id, StreamPath, args) => {
  console.log('[NodeEvent on postPlay]', `id=${id} StreamPath=${StreamPath} args=${JSON.stringify(args)}`);
});

nms.on('donePlay', (id, StreamPath, args) => {
  console.log('[NodeEvent on donePlay]', `id=${id} StreamPath=${StreamPath} args=${JSON.stringify(args)}`);
});

nms.on('logMessage', (...args) => {
  // custom logger log message handler
});

nms.on('errorMessage', (...args) => {
  // custom logger error message handler
});

nms.on('debugMessage', (...args) => {
  // custom logger debug message handler
});


nms.on('ffDebugMessage', (...args) => {
  // custom logger ffmpeg debug message handler
});

Https/Wss

Generate certificate

openssl req -newkey rsa:2048 -new -nodes -x509 -days 3650 -keyout key.pem -out cert.pem

Config https

const NodeMediaServer = require('node-media-server');

const config = {
  rtmp: {
    port: 1935,
    chunk_size: 60000,
    gop_cache: true,
    ping: 30,
    ping_timeout: 60
  },
  http: {
    port: 8000,
    allow_origin: '*'
  },
  https: {
    port: 8443,
    key:'./key.pem',
    cert:'./cert.pem',
  }
};


var nms = new NodeMediaServer(config)
nms.run();

Accessing

https://localhost:8443/live/STREAM_NAME.flv
wss://localhost:8443/live/STREAM_NAME.flv

In the browser environment, Self-signed certificates need to be added with trust before they can be accessed.

API

Protected API

const config = {
 .......
   auth: {
    api : true,
    api_user: 'admin',
    api_pass: 'nms2018',
  },
 
 ......
}

Based on the basic auth,Please change your password. The default is not turned on

Server stats

http://localhost:8000/api/server

{
  "os": {
    "arch": "x64",
    "platform": "darwin",
    "release": "16.7.0"
  },
  "cpu": {
    "num": 8,
    "load": 12,
    "model": "Intel(R) Core(TM) i7-4790 CPU @ 3.60GHz",
    "speed": 3592
  },
  "mem": {
    "totle": 8589934592,
    "free": 754126848
  },
  "net": {
    "inbytes": 6402345,
    "outbytes": 6901489
  },
  "nodejs": {
    "uptime": 109,
    "version": "v8.9.0",
    "mem": {
      "rss": 59998208,
      "heapTotal": 23478272,
      "heapUsed": 15818096,
      "external": 3556366
    }
  },
  "clients": {
    "accepted": 207,
    "active": 204,
    "idle": 0,
    "rtmp": 203,
    "http": 1,
    "ws": 0
  }
}

Streams stats

http://localhost:8000/api/streams

{
  "live": {
    "s": {
      "publisher": {
        "app": "live",
        "stream": "s",
        "clientId": "U3UYQ02P",
        "connectCreated": "2017-12-21T02:29:13.594Z",
        "bytes": 190279524,
        "ip": "::1",
        "audio": {
          "codec": "AAC",
          "profile": "LC",
          "samplerate": 48000,
          "channels": 6
        },
        "video": {
          "codec": "H264",
          "width": 1920,
          "height": 1080,
          "profile": "Main",
          "level": 4.1,
          "fps": 24
        }
      },
      "subscribers": [
        {
          "app": "live",
          "stream": "s",
          "clientId": "H227P4IR",
          "connectCreated": "2017-12-21T02:31:35.278Z",
          "bytes": 18591846,
          "ip": "::ffff:127.0.0.1",
          "protocol": "http"
        },
        {
          "app": "live",
          "stream": "s",
          "clientId": "ZNULPE9K",
          "connectCreated": "2017-12-21T02:31:45.394Z",
          "bytes": 8744478,
          "ip": "::ffff:127.0.0.1",
          "protocol": "ws"
        },
        {
          "app": "live",
          "stream": "s",
          "clientId": "C5G8NJ30",
          "connectCreated": "2017-12-21T02:31:51.736Z",
          "bytes": 2046073,
          "ip": "::ffff:192.168.0.91",
          "protocol": "rtmp"
        }
      ]
    },
    "stream": {
      "publisher": null,
      "subscribers": [
        {
          "app": "live",
          "stream": "stream",
          "clientId": "KBH4PCWB",
          "connectCreated": "2017-12-21T02:31:30.245Z",
          "bytes": 0,
          "ip": "::ffff:127.0.0.1",
          "protocol": "http"
        }
      ]
    }
  }
}

Remux to HLS/DASH live stream

const NodeMediaServer = require('node-media-server');

const config = {
  rtmp: {
    port: 1935,
    chunk_size: 60000,
    gop_cache: true,
    ping: 30,
    ping_timeout: 60
  },
  http: {
    port: 8000,
    mediaroot: './media',
    allow_origin: '*'
  },
  trans: {
    ffmpeg: '/usr/local/bin/ffmpeg',
    tasks: [
      {
        app: 'live',
        hls: true,
        hlsFlags: '[hls_time=2:hls_list_size=3:hls_flags=delete_segments]',
        hlsKeep: true, // to prevent hls file delete after end the stream
        dash: true,
        dashFlags: '[f=dash:window_size=3:extra_window_size=5]',
        dashKeep: true // to prevent dash file delete after end the stream
      }
    ]
  }
};

var nms = new NodeMediaServer(config)
nms.run();

Remux to RTMP/HLS/DASH live stream with audio transcode

const NodeMediaServer = require('node-media-server');

const config = {
  rtmp: {
    port: 1935,
    chunk_size: 60000,
    gop_cache: true,
    ping: 30,
    ping_timeout: 60
  },
  http: {
    port: 8000,
    mediaroot: './media',
    allow_origin: '*'
  },
  trans: {
    ffmpeg: '/usr/local/bin/ffmpeg',
    tasks: [
      {
        app: 'live',
        vc: "copy",
        vcParam: [],
        ac: "aac",
        acParam: ['-ab', '64k', '-ac', '1', '-ar', '44100'],
        rtmp:true,
        rtmpApp:'live2',
        hls: true,
        hlsFlags: '[hls_time=2:hls_list_size=3:hls_flags=delete_segments]',
        dash: true,
        dashFlags: '[f=dash:window_size=3:extra_window_size=5]'
      }
    ]
  }
};

var nms = new NodeMediaServer(config)
nms.run();

Remux to RTMP cannot use the same app name

Record to MP4

const NodeMediaServer = require('node-media-server');

const config = {
  rtmp: {
    port: 1935,
    chunk_size: 60000,
    gop_cache: true,
    ping: 30,
    ping_timeout: 60
  },
  http: {
    port: 8000,
    mediaroot: './media',
    allow_origin: '*'
  },
  trans: {
    ffmpeg: '/usr/local/bin/ffmpeg',
    tasks: [
      {
        app: 'live',
        mp4: true,
        mp4Flags: '[movflags=frag_keyframe+empty_moov]',
      }
    ]
  }
};

var nms = new NodeMediaServer(config)
nms.run();

Rtsp/Rtmp Relay

NodeMediaServer implement RTSP and RTMP relay with ffmpeg.

Static pull

The static pull mode is executed at service startup and reconnect after failure. It could be a live stream or a file. In theory, it is not limited to RTSP or RTMP protocol.

relay: {
  ffmpeg: '/usr/local/bin/ffmpeg',
  tasks: [
    {
      app: 'cctv',
      mode: 'static',
      edge: 'rtsp://admin:[email protected]:554/ISAPI/streaming/channels/101',
      name: '0_149_101',
      rtsp_transport : 'tcp' //['udp', 'tcp', 'udp_multicast', 'http']
    }, {
        app: 'iptv',
        mode: 'static',
        edge: 'rtmp://live.hkstv.hk.lxdns.com/live/hks',
        name: 'hks'
      }, {
        app: 'mv',
        mode: 'static',
        edge: '/Volumes/ExtData/Movies/Dancing.Queen-SD.mp4',
        name: 'dq'
      }
  ]
}

Dynamic pull

When the local server receives a play request. If the stream does not exist, pull the stream from the configured edge server to local. When the stream is not played by the client, it automatically disconnects.

relay: {
  ffmpeg: '/usr/local/bin/ffmpeg',
  tasks: [
    {
      app: 'live',
      mode: 'pull',
      edge: 'rtmp://192.168.0.20',
    }
  ]
}

Dynamic push

When the local server receives a publish request. Automatically push the stream to the edge server.

relay: {
  ffmpeg: '/usr/local/bin/ffmpeg',
  tasks: [
    {
      app: 'live',
      mode: 'push',
      edge: 'rtmp://192.168.0.10',
    }
  ]
}

Fission

Real-time transcoding multi-resolution output fission

fission: {
  ffmpeg: '/usr/local/bin/ffmpeg',
  tasks: [
    {
      rule: "game/*",
      model: [
        {
          ab: "128k",
          vb: "1500k",
          vs: "1280x720",
          vf: "30",
        },
        {
          ab: "96k",
          vb: "1000k",
          vs: "854x480",
          vf: "24",
        },
        {
          ab: "96k",
          vb: "600k",
          vs: "640x360",
          vf: "20",
        },
      ]
    },
    {
      rule: "show/*",
      model: [
        {
          ab: "128k",
          vb: "1500k",
          vs: "720x1280",
          vf: "30",
        },
        {
          ab: "96k",
          vb: "1000k",
          vs: "480x854",
          vf: "24",
        },
        {
          ab: "64k",
          vb: "600k",
          vs: "360x640",
          vf: "20",
        },
      ]
    },
  ]
}

Publisher and Player App/SDK

Android Livestream App

https://play.google.com/store/apps/details?id=cn.nodemedia.qlive

Android SDK

https://github.com/NodeMedia/NodeMediaClient-Android

iOS SDK

https://github.com/NodeMedia/NodeMediaClient-iOS

React-Native SDK

https://github.com/NodeMedia/react-native-nodemediaclient

NodePlayer.js HTML5 live player

  • Implemented with asm.js / wasm
  • http-flv/ws-flv
  • H.264/H.265 + AAC/Nellymoser/G.711 decoder
  • Ultra low latency
  • All modern browsers are supported

https://www.nodemedia.cn/product/nodeplayer-js/

node-media-server's People

Contributors

715209 avatar alen256 avatar alex4108 avatar bazookon avatar biglikegithub avatar btbn avatar cconley717 avatar cstringer avatar dependabot[bot] avatar diesermerlin avatar dipaksarkar avatar flupster avatar gitter-badger avatar hthetiot avatar illuspas avatar joeledwardson avatar llorx avatar lordmau5 avatar matishsiao avatar mattcwebster avatar primemb avatar rebelvg avatar sohail05 avatar takazamy avatar tekuconcept avatar vedraiyani avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

node-media-server's Issues

loadbalancing

do you have a plan how can we loadbalance for example i need to serve 20000 users at same time like cdn setup

RTMP中继的实现

nginx-rtmp-module 里pull push命令很好用,可以用来实现集群架构.
目前另一个项目libmedia.js已经实现了rtmp的客户端,可以用来做中继.底层用NAN封装一个c实现的librtmp库.
另外,利用nodejs抽象的IPC网络,可以模仿auto_push实现cluster多核.

HTTP flv.js client drops connection

Hey, first of all, great repo, love it.

Issue.
HTTP flv.js player drops connection after about 30 minutes. Here's logs from the browser and nodejs console.
At the same time I launched ffplay and it didn't drop the connection. So the issue possibly lies in the flv.js player.
Edit: looks like it's really a flv.js player issue. Please close this ticket if there's no need for it.
Another edit: Not sure if it's completely player issue.
https://github.com/Bilibili/flv.js/blob/master/docs/cors.md
This link here says that OPTIONS http request will be made at some point and server should respond, but in this case, server drops the connection because it can only answer on GET correctly.
According to the log, MSE SourceBuffer gets full and it attempts to play video after that, sends OPTIONS request and server responds with res.end() closing the connection.

this.res.end();

[MSEController] > MediaSource onSourceOpen logger.js:123:8
[FLVDemuxer] > Parsed onMetaData logger.js:123:8
[FLVDemuxer] > Parsed AudioSpecificConfig logger.js:123:8
[FLVDemuxer] > Parsed AVCDecoderConfigurationRecord logger.js:123:8
[MSEController] > Received Initialization Segment, mimeType: audio/mp4;codecs=mp4a.40.2 logger.js:123:8
[MSEController] > Received Initialization Segment, mimeType: video/mp4;codecs=avc1.64001f logger.js:123:8
[FlvPlayer] > MSE SourceBuffer is full, suspend transmuxing task logger.js:123:8
[FlvPlayer] > Continue loading from paused position logger.js:123:8
OPTIONS XHR http://127.0.0.1:8000/live/main.flv [HTTP/1.1 405 Method Not Allowed 2ms]
Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource at http://127.0.0.1:8000/live/main.flv. (Reason: CORS header ‘Access-Control-Allow-Origin’ missing). (unknown)
[IOController] > Loader error, code = -1, msg = ProgressEvent error logger.js:38:12
[TransmuxingController] > IOException: type = Exception, code = -1, msg = ProgressEvent error logger.js:38:12
Error: Uncaught, unspecified "error" event. (NetworkError) events.js:62

Parse AudioTagHeader sound_format=10 sound_type=1 sound_size=1 sound_rate=3
Parse VideoTagHeader frame_type=1 codec_id=7
[http-flv play] play stream live/main
[http-flv play] join stream live/main
http-flv parse message [start]
[http-flv play] play stream live/main
[http-flv play] join stream live/main
http-flv parse message [start]
http-flv parse message [stop]
Unsupported method=OPTIONS

Transcode not creating file

Hi, i got no file output while using the transcode option.
Here is my app.js

const NodeMediaServer = require('./node_media_server');

const config = {
  rtmp: {
    port: 1935,
    chunk_size: 60000,
    gop_cache: true,
    ping: 60,
    ping_timeout: 30
  },
  http: {
    port: 80,
    webroot: './public',
    mediaroot: './media',
    allow_origin: '*'
  },
  https: {
    port: 443,
    key: 'XXXXXXXXXXXXXXXXX',
    cert: 'XXXXXXXXXXXXXXXXX',
  },
  trans: {
    ffmpeg: '/usr/bin/ffmpeg',
    tasks: [
      {
        app: 'live',
        ac: 'aac',
        mp4: true,
        mp4Flags: '[movflags=faststart]',
        hls: true,
        hlsFlags: '[hls_time=2:hls_list_size=3:hls_flags=delete_segments]',
        dash: true,
        dashFlags: '[f=dash:window_size=3:extra_window_size=5]'
      }, {
        app: 'vod',
        ac: 'aac',
        mp4: true,
        mp4Flags: '[movflags=faststart]',
      }
    ],
  },
};

How to access published streams?

Where are streams published? Are they exposed as a RTMP stream from the server, or do I need to read directly from the Bufferpool?

Any advice would be appreciated.

Bad connections cause server crash

If connection is dropped during onPlay event the server will crash cause the socket gets destroyed and server can't write anything to it.

TypeError: this.res.write is not a function
at NodeFlvSession.onPlay (/root/klpq-media-server/node_modules/node-media-server/node_flv_session.js:192:14)
at NodeFlvSession.emit (events.js:159:13)
at NodeFlvSession.run (/root/klpq-media-server/node_modules/node-media-server/node_flv_session.js:72:12)
at NodeHttpServer.onConnect (/root/klpq-media-server/node_modules/node-media-server/node_http_server.js:76:13)
at WebSocketServer.wsServer.on (/root/klpq-media-server/node_modules/node-media-server/node_http_server.js:57:12)
at WebSocketServer.emit (events.js:159:13)
at handleUpgrade (/root/klpq-media-server/node_modules/ws/lib/WebSocketServer.js:88:16)
at WebSocketServer.completeUpgrade (/root/klpq-media-server/node_modules/ws/lib/WebSocketServer.js:270:5)
at WebSocketServer.handleUpgrade (/root/klpq-media-server/node_modules/ws/lib/WebSocketServer.js:197:10)
at Server.WebSocketServer._ultron.on (/root/klpq-media-server/node_modules/ws/lib/WebSocketServer.js:87:14)

我想对rtmp视频流进行切片处理我该怎么做?

@illuspas 这个框架支持视频流切片吗?前几天我在你的另一个项目上问过你GOP cache相关问题,在这里我想您问一下我能不能通过切片解决延迟问题,把延迟降到2s以内,如果可以的话我应该怎么做?给点建议,谢谢!

Socket timeout issue

If publisher losses connection during the stream he'll stay in the "publishers" hash-map and his session will still count as live. "Close" event for socket should catch this. I may be wrong, but "closeStream" event of the rtmp session doesn't get triggered on socket close so that's why session removal process is never executed.
Same thing happens for clients.

Question: Is there WebRTC to RTMP?

I see you accept OBS, which I have yet to try. It is likely I can't use OBS because of its license and what I need it for.

I am really new in this space so excuse any naive questions here. Is it possible to send WebRTC to this Media Server and have it output RTMP?

Issue with some RTMP players

Some RTMP flash players send slightly incorrect play path.
For example, JWplayer sends app name as "app/" with / at the end. So the full play path becomes "/app//channel".
I found a hacky way to fix this, just replace any "/" in the appname on the postConnect event, but this behavior should probably be fixed on the server.
You can test this here.
https://developer.jwplayer.com/tools/stream-tester/?playerversion=7
Select flash and enter link for your stream.
rtmp://localhost/app/channel

RTMP publish to NMS error. core_av line 182

what is u8 stand for?
I am doing publish with ffmpeg. Simply copy from TS stream. Not work for u8 not defined.
Publisher:
ffmpeg -i http://localhost/source.ts -acodec copy -vcodec copy -f flv rtmp://localhost/live/test

End as:
[rtmp handleVideoMessage] Parse VideoTagHeader frame_type=1 codec_id=7 codec_name=H264
/home/bs/content-site/rtmpServer/node_modules/node-media-server/node_core_av.js:182
for (n = 0; n < (cf_idc != 3 ? u8 : u12); n++) {
^

ReferenceError: u8 is not defined
at readH264SpecificConfig (/home/bs/content-site/rtmpServer/node_modules/node-media-server/node_core_av.js:182:40)

MORE INFO:
the TS stream contains H.264 High Profile. I set the TS stream to Main Profile, it works. But don't know why.

Can't get live video streaming recorded in MP4

Hi,

Thank you for sharing. I have problems trying to record the video live streaming. I used the configuration recommended in the documentation for record videos, but I can't see the recorded videos in the "media" folder.

Thanks for the help!

Stream MP4 Videos

Hi how can i stream a mp4 video instead of a flv video to play it in a browser. the video needs to be mp4 to be picked in a html5 video tag

Issue using authentication, always getting a sign=undefined

Hi,

I've been following the guide from the setup to perform authenticated connection but I'm alsways getting sign=undefined in the console log.

I even tryed using the same key and it's always say sign=undefined, I would have expected an expired notice.

Here is my an example of how I compile and generate my row
expiration = Math.floor(Date.now() / 1000) + (86400 * 365): 1551886982
PreHashValue: /live/stream-1551886982-nodemedia2017privatekey
HashValue: 696f9f34ba60e06657c13e35ae0c586b
URL: rtmp://localhost/live/stream?sign=1551886982-696f9f34ba60e06657c13e35ae0c586b

When adding the url in OBS Studio, I'm getting the following error message
[rtmp handshake] start
[rtmp handshake] done
[rtmp message parser] start
[rtmp handleRtmpMessage] Set In chunkSize:4096
[rtmp connect] app: livestream?sign=1551886982-696f9f34ba60e06657c13e35ae0c586b
[rtmp publish] Unauthorized. ID=GRY0VMML streamPath=/livestream?sign=1551886982-696f9f34ba60e06657c13e35ae0c586b/ sign=undefined

Question : RTMP still on going when source is stop

Hi,

I wanna ask about something. Is it an issue from NMS or ffmpeg i used.

I have 3 servers, lets say :

  • Server A as a RTMP server using NMS
  • Server B as a Transcode server using FFMPEG
  • Server C as a Transmuxing server using FFMPEG

I push my live stream to Server A, Server B pulling it for transcode it and push the multiple bitrates result to Server A.
and then, Server C is pulling multiple bitrates stream from Server A.

When i stop the stream, the main stream is "donePublish"-ing, but the transcoded stream is not finish yet. Is it a cache? or anything else?
I've set cache config to false, but it still like that.

If it's not an issue from NMS, it's ok. So i can trace from my FFMPEG.

Thanks!

rtmp to webrtc/websocket

it's possible:
-rtmp to webrtc/websocket
-webrtc/websocket to rtmp

It would be really fantastic. Above all for everyone who come from AS3.
Great work, thank you.

How to reload a config

First, this is a great project! Thanks Illuspas.

I created a new Media server with:

..
var nms = new NodeMediaServer(config)
nms.run();

How can i stop the mediaserver or restart it with a new config?

Like:
nms.stop();
nms.restart();

Does this feature makes sense for you?

EPIPE error

There's one crash that I can't really find a repro for. Only a short log message. But I have a few more details about it.
I thought #31 should fix it, but after I merged it into my local build it didn't help.
So what happens is, RTMP client that doesn't have the speed to properly download the stream (video lags for him) disconnects and that causes the server to crash.
As you can see, the session terminates at 07.135 but crash appears 07.149.
In the meantime, I'll try to find a better repro.

2017-12-08 20:07:01.134 +01:00: [rtmp message parser] done
2017-12-08 20:07:01.135 +01:00: [NodeEvent on donePlay] id=SNT1EEZ5 StreamPath=/live/kino args={}
2017-12-08 20:07:01.135 +01:00: [NodeEvent on doneConnect] id=SNT1EEZ5 args={"app":"live","flashVer":"MAC 10,0,32,18","tcUrl":"rtmp://vps.klpq.men:1935/live","fpad":false,"capabilities":15,"audioCodecs":3191,"videoCodecs":252,"videoFunction":1}
2017-12-08 20:07:01.149 +01:00: Error: write EPIPE
at _errnoException (util.js:1031:13)
at WriteWrap.afterWrite (net.js:873:14)

Unable to access stream

I m running a node media server. PFB the code

`var nodeMediaSer = require('node-media-server');

const config = {
rtmp: {
port: 1935,
chunk_size: 60000,
gop_cache: true,
ping: 60,
ping_timeout: 30
},
http: {
port: 8000,
allow_origin: '*'
}
};

var nms = new nodeMediaSer(config);
nms.run(()=> {
console.log("Server Started");
})

nms.on('preConnect', (id, args) => {
console.log('[NodeEvent on preConnect]', id=${id} args=${JSON.stringify(args)});
// let session = nms.getSession(id);
// session.reject();
});

nms.on('postConnect', (id, args) => {
console.log('[NodeEvent on postConnect]', id=${id} args=${JSON.stringify(args)});
});

nms.on('doneConnect', (id, args) => {
console.log('[NodeEvent on doneConnect]', id=${id} args=${JSON.stringify(args)});
});

nms.on('prePublish', (id, StreamPath, args) => {
console.log('[NodeEvent on prePublish]', id=${id} StreamPath=${StreamPath} args=${JSON.stringify(args)});
// let session = nms.getSession(id);
// session.reject();
});

nms.on('postPublish', (id, StreamPath, args) => {
console.log('[NodeEvent on postPublish]', id=${id} StreamPath=${StreamPath} args=${JSON.stringify(args)});
});

nms.on('donePublish', (id, StreamPath, args) => {
console.log('[NodeEvent on donePublish]', id=${id} StreamPath=${StreamPath} args=${JSON.stringify(args)});
});

nms.on('prePlay', (id, StreamPath, args) => {
console.log('[NodeEvent on prePlay]', id=${id} StreamPath=${StreamPath} args=${JSON.stringify(args)});
// let session = nms.getSession(id);
// session.reject();
});

nms.on('postPlay', (id, StreamPath, args) => {
console.log('[NodeEvent on postPlay]', id=${id} StreamPath=${StreamPath} args=${JSON.stringify(args)});
});

nms.on('donePlay', (id, StreamPath, args) => {
console.log('[NodeEvent on donePlay]', id=${id} StreamPath=${StreamPath} args=${JSON.stringify(args)});
});

`

after this I run comman npm run start
with ffmpeg installed with 'sudo apt-get install ffmpeg'
I run the below commands
'ffmpeg -re -i INPUT_FILE_NAME -c:v libx264 -preset superfast -tune zerolatency -c:a aac -ar 44100 -f flv rtmp://localhost/live/STREAM_NAME'
'ffplay http://localhost:8000/live/STREAM_NAME.flv' after running the second command I always get the same error on the console that the stream is not found /live/STREAM_NAME is not found.

NOTE: STREAM_NAME is being changed with the file name

Push relay from nginx-rtmp does not work

I'm attempting to test relaying from an existing nginx-rtmp server taking in rtmp from ffmpeg sources. The nginx-rtmp config looks like

		application live {
			live on;
			allow publish 127.0.0.1;
			deny publish all;
			push rtmp://localhost:1936/live/;
		}

node-media-server is running on 1936. node-media-server log shows

Node Media Rtmp Server started on port: 1936
Node Media Http Server started on port: 8083
Node Media WebSocket Server started on port: 8083
[rtmp handshake] start
[rtmp handshake] done
[rtmp message parser]  start
[rtmp handleRtmpMessage] Set In chunkSize:4096
[rtmp connect]  app: live
[rtmp publish] new stream path /live/4 streamId:1
[rtmp message parser] done

It never reaches the [rtmp handleVideoMessage] Parse VideoTagHeader frame_type=1 codec_id=7 step which I normally see from ffmpeg publishing directly to node-media-server. Any idea what is wrong with the nginx-rtmp push?

RTMP stream breaks after 5 hours

Really hard bug to reproduce, but I tested this multiple times and found a repro case.
Basically, no client can connect to the stream if the stream has been live for 5 hours. Only happens if client tries to connect via rtmp, http-flv works fine.

This is the log from ffmpeg/rtmpdump.
2017-12-01 04:05:45.393 +02:00: Larger timestamp than 24-bit: 0xd1750a9a
DTS 3514123186, next:24671666 st:1 invalid dropping
PTS 3514123269, next:24671666 invalid dropping st:1

Can't connect via rtmp when there's no stream online

It's more a feature request than an issue.
As I understand all publisher IDs are added to the publishers hash-map. And if there's no stream online, any connection accessing this channel/publisher will be dropped. But most rtmp players (at least flash ones) can connect to the server, receive onConnect and idle until onPlay is launched.
So the idea is to accept these connections, store them somewhere as connections without publishers and if publisher for this channel appears, add them to this publisher.

MP4录制,HLS/DASH的实现

flv的实时录制是比较容易实现的,但作为回放格式并不如mp4好.
也并不打算在本项目里实现MP4的封装,尽管可以通过封装C库来实现也不难.
但考虑到如果通过flash推流上来是Nellymoser音频编码,需要进行AAC转码.
不如直接调用ffmpeg来进行MP4录制.
当监听到postPublish时,ffmpeg播放本地rtmp流, 根据音频编码来决定是否进行音频转码,可以同时输出为MP4文件,HLS流,DASH流.
也因为是进程调用,所以文件IO也不会影响主进程的网络IO.

还有一个方案是封装libav*库,比如libmedia.js的实现,底层是基于AsyncWorker,也不会影响事件循环,也能更好的利用多核.麻烦的是编译复杂,目前还不准备提供源码,所以为了支持跨平台每次更新需要编译多个平台,费劲,但效果很好. 这个方案暂时不想继续下去,空闲时间太少.

因此,准备使用child_process来实现MP4录制,hls,dash.

websocket not work stream not found /live/STREAM_NAME

Node Media Rtmp Server started on port: 1935
Node Media Http Server started on port: 8000
Node Media WebSocket Server started on port: 8000
[rtmp handshake] start
[rtmp handshake] done
[rtmp message parser] start
[rtmp handleRtmpMessage] Set In chunkSize:4096
[NodeEvent on preConnect] id=0EQGYK2C args={"app":"live/STREAM_NAME","type":"nonprivate","flashVer":"FMLE/3.0 (compatible; FMSc/1.0)","swfUrl":"rtmp://localhost/live/STREAM_NAME","tcUrl":"rtmp://localhost/live/STREAM_NAME"}
[rtmp connect] app: live/STREAM_NAME
[NodeEvent on postConnect] id=0EQGYK2C args={"app":"live/STREAM_NAME","type":"nonprivate","flashVer":"FMLE/3.0 (compatible; FMSc/1.0)","swfUrl":"rtmp://localhost/live/STREAM_NAME","tcUrl":"rtmp://localhost/live/STREAM_NAME"}
[NodeEvent on prePublish] id=0EQGYK2C StreamPath=/live/STREAM_NAME/ args={}
[rtmp publish] new stream path /live/STREAM_NAME/ streamId:1
[NodeEvent on postPublish] id=0EQGYK2C StreamPath=/live/STREAM_NAME/ args={}
[rtmp handleAudioMessage] Parse AudioTagHeader sound_format=10 sound_type=1 sound_size=1 sound_rate=3
[rtmp handleVideoMessage] Parse VideoTagHeader frame_type=1 codec_id=7
[NodeEvent on preConnect] id=6UPEB9P4 args={"method":"GET","streamPath":"/live/STREAM_NAME","query":{}}
[websocket-flv message parser] start
[NodeEvent on postConnect] id=6UPEB9P4 args={"method":"GET","streamPath":"/live/STREAM_NAME","query":{}}
[websocket-flv play] play stream /live/STREAM_NAME
[NodeEvent on prePlay] id=6UPEB9P4 StreamPath=/live/STREAM_NAME args={}
[websocket-flv play] stream not found /live/STREAM_NAME

How to reduce the live delay

const config = {
rtmp: {
port: 1935,
chunk_size: 4096,
gop_cache: false,
ping: 1,
ping_timeout: 1
},
http: {
port: 8000,
allow_origin: '*'
},
auth: {
play: false,
publish: false,
secret: 'nodemedia2017privatekey'
}
};

Is there a document for the configure?

Nginx config.

Hi there!

Great lib :)

I was just thinking what kind of Nginx config I need to run this on let's say Digitalocean?

Any pointers would be helpful!

Thanks

Feature request: more API endpoints

Feature request for the future.
Please, add more API endpoints.
So for example, node_media_server.js exports NodeMediaServer class, so we have access to the actual servers via nrs and nhs properties.
It would be great if those servers could emit events on rtmp or http client which will pass the session in so we can get a hold of this object and make something with it, write data from it to the database for example.
PrePlay and PrePublish events for session would be great so we can implement our own auth logic or else.
Thanks!

RTMP 播放BUG

1)同一个设备如果同时播放同一条RTMP流,第二次播放的那条流一定卡死。
1)同一个设备,先用FLV播放同一条流,再用RTMP播放同一条流,RTMP必卡死。

Tab switching for FLV.js through http or websocket makes the video lag behind

Maybe this is a browser feature that needs to be considered(MSE decoding being suspended on tab leave?!?), but having my tests done with this publisher:

ffmpeg -loglevel verbose \
  -re \
  -r 30 \
  -f lavfi -i testsrc \
  -vf scale=1280:720 \
  -vcodec libx264 \
  -pix_fmt yuv420p \
  -preset superfast \
  -tune zerolatency \
  -c:a aac -ar 44100 \
  -f flv rtmp://localhost:1935/live/stream

And the native player through ffplay:

ffplay -loglevel verbose rtmp://localhost:1935/live/stream

And this html player code:

<!DOCTYPE html>
<html>
  <head>
    <meta charset="UTF-8" />
    <title>title</title>
    <meta name="author" content="name" />
    <meta name="description" content="description here" />
    <meta name="keywords" content="keywords,here" />
    <link rel="shortcut icon" href="favicon.ico" type="image/vnd.microsoft.icon" />
    <style type="text/css">
    </style>
    <script src="//ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js" type="text/javascript"></script>
  </head>
  <body>
    <video id="videoElement"></video>
    <script src="https://cdn.bootcss.com/flv.js/1.3.3/flv.min.js"></script>
    <script>
      $(document).ready(function() {
        if (flvjs.isSupported()) {
            var videoElement = document.getElementById('videoElement');
            var flvPlayer = flvjs.createPlayer({
                type: 'flv',
                // url: 'ws://localhost:8000/live/stream.flv',
                url: 'http://localhost:8000/live/stream.flv'
            });
            flvPlayer.attachMediaElement(videoElement);
            flvPlayer.load();
            flvPlayer.play();
        }
      });
    </script>
  </body>
</html>

The browser starts to lag behind:
image

But as soon as I refresh the page, it is all good:
image

Can you give it a look ?

Event callbacks

Hello, i really like this package. But in this stage, is it possible to catch the event so you can add extra functionality outside the package. For example: An onPublish event that can be cought, so you can do stuff with it. For example create another message or setup an connection to an external server?

this.gFun.next(); Error: Error: Unknown field

Node Media Server bound on port: 1935
client connect id: vbjiosoqclpn
rtmp handshake [start]
rtmp handshake [ok]
rtmp connect app: live
rtmp publish stream: stream
Unknown field 17
/data1/nodejs/Node-Media-Server/nm_bufferpool.js:21
this.gFun.next();
^

Error: Error: Unknown field
at amfXDecodeOne (/data1/nodejs/Node-Media-Server/nm_rtmp_amf.js:887:15)
at amf0DecodeOne (/data1/nodejs/Node-Media-Server/nm_rtmp_amf.js:898:12)
at /data1/nodejs/Node-Media-Server/nm_rtmp_amf.js:1047:25
at Array.forEach (native)
at Object.decodeAMF0Cmd (/data1/nodejs/Node-Media-Server/nm_rtmp_amf.js:1045:34)
at NMRtmpConn.NMRtmpConn.handleRtmpMessage (/data1/nodejs/Node-Media-Server/nm_rtmp_conn.js:329:31)
at parseRtmpMessage (/data1/nodejs/Node-Media-Server/nm_rtmp_conn.js:233:18)
at next (native)
at BufferPool.push (/data1/nodejs/Node-Media-Server/nm_bufferpool.js:21:23)
at Socket. (/data1/nodejs/Node-Media-Server/nm_server.js:19:27)

Is it possible to forward the stream?

The server works as I expect it to. I can stream to it and then test that it works by opening the rtmp URL with VLC player.

I need to actually receive the stream on my server just for some orchestration purposes before sending it to another location for the actual broadcast. Is there any way to do this with your package?

Specify required node version in package json

Hi, awesome project, I just tried to run the demo code after npm install but I got this weird error:

node_modules\node-media-server\api\controllers\server.js:72
async function getInfo(req, res, next) {
      ^^^^^^^^
SyntaxError: Unexpected token function
    at createScript (vm.js:56:10)
    at Object.runInThisContext (vm.js:97:10)
    at Module._compile (module.js:542:28)
    at Object.Module._extensions..js (module.js:579:10)
    at Module.load (module.js:487:32)
    at tryModuleLoad (module.js:446:12)
    at Function.Module._load (module.js:438:3)
    at Module.require (module.js:497:17)
    at require (internal/module.js:20:19)
    at Object.<anonymous> (node_modules\node-media-server\api\routes\server.js:3:26)

Then I moved from v6.11.4 to v8.9.4 and all worked fine.
So adding { "engines" : { "node" : ">=8.9.4" } } would be of great help, I don't know what you have as minimal requirement, I just picked up today's LTS which is 8.9.4

如何做身份验证了?

首先感谢作者的源代码!
请问如何在此代码基础上来做上行流和下行流的身份验证呢?
希望您能给一些实现帮助或者是思路

RTMP play issue

There's sometimes this strange bug that prevents you from playing the stream via rtmp.
Basically what happens is that you can't connect to the stream. It's not a network issue cause that happened to me on localhost. Server logs don't show anything useful, only onPlay and then suddenly donePlay. Don't have a repro scenario, but I have a log from ffmpeg.

2017-12-07 21:10:10.032 +02:00: [h264 @ 00000000028bf800] co located POCs unavailable
2017-12-07 21:10:10.049 +02:00: [h264 @ 00000000028cce00] mmco: unref short failure
2017-12-07 21:10:10.070 +02:00: [h264 @ 00000000028cd6a0] co located POCs unavailable
2017-12-07 21:10:10.111 +02:00: [h264 @ 00000000028cd6a0] mmco: unref short failure
2017-12-07 21:10:12.776 +02:00: Too many packets buffered for output stream 0:1.
[aac @ 000000000296c420] Qavg: 321.561
[aac @ 000000000296c420] 2 frames left in the queue on closing
2017-12-07 21:10:12.784 +02:00: Conversion failed!

Read ME

Hello,

Firstly thank you so much really friend.

how can i do m3u export stream ? help me pls.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.