mirror of
https://github.com/ossrs/srs.git
synced 2025-03-09 15:49:59 +00:00
Merge branch '4.0release' into merge/develop
This commit is contained in:
commit
4e79e91ede
13 changed files with 299 additions and 488 deletions
2
.gitignore
vendored
2
.gitignore
vendored
|
@ -34,3 +34,5 @@
|
||||||
.idea
|
.idea
|
||||||
.DS_Store
|
.DS_Store
|
||||||
|
|
||||||
|
/cmake-build-debug/
|
||||||
|
/CMakeLists.txt
|
||||||
|
|
|
@ -84,3 +84,5 @@ CONTRIBUTORS ordered by first contribution.
|
||||||
* xbpeng121<53243357+xbpeng121@users.noreply.github.com>
|
* xbpeng121<53243357+xbpeng121@users.noreply.github.com>
|
||||||
* johzzy<hellojinqiang@gmail.com>
|
* johzzy<hellojinqiang@gmail.com>
|
||||||
* stone<bluestn@163.com>
|
* stone<bluestn@163.com>
|
||||||
|
* cfw11<34058899+cfw11@users.noreply.github.com>
|
||||||
|
* louis.xia<68469352@qq.com>
|
||||||
|
|
34
README.md
34
README.md
|
@ -9,9 +9,10 @@ SRS/4.0,[Leo][release4],是一个简单高效的实时视频服务器,支
|
||||||
|
|
||||||
SRS is a simple, high efficiency and realtime video server, supports RTMP/WebRTC/HLS/HTTP-FLV/SRT/GB28181.
|
SRS is a simple, high efficiency and realtime video server, supports RTMP/WebRTC/HLS/HTTP-FLV/SRT/GB28181.
|
||||||
|
|
||||||
> Note: SRS is licenced under [MIT][LICENSE], but some depended libraries are distributed using their [own licenses][LicenseMixing].
|
SRS is licenced under [MIT][LICENSE], but some depended libraries are distributed using their [own licenses][LicenseMixing].
|
||||||
|
|
||||||
<a name="product"></a>
|
<a name="product"></a>
|
||||||
|
<a name="usage-docker"></a>
|
||||||
## Usage
|
## Usage
|
||||||
|
|
||||||
Run SRS by [docker][docker-srs4], images is [here](https://hub.docker.com/r/ossrs/srs/tags) or [there](https://cr.console.aliyun.com/repository/cn-hangzhou/ossrs/srs/images),
|
Run SRS by [docker][docker-srs4], images is [here](https://hub.docker.com/r/ossrs/srs/tags) or [there](https://cr.console.aliyun.com/repository/cn-hangzhou/ossrs/srs/images),
|
||||||
|
@ -23,6 +24,7 @@ docker run --rm -it -p 1935:1935 -p 1985:1985 -p 8080:8080 \
|
||||||
ossrs/srs:v4.0.117 ./objs/srs -c conf/srs.conf
|
ossrs/srs:v4.0.117 ./objs/srs -c conf/srs.conf
|
||||||
```
|
```
|
||||||
|
|
||||||
|
<a name="usage-source"></a>
|
||||||
Or build SRS from source(or [mirrors](#mirrors)), by CentOS7(or Linux([CN][v4_CN_Build],[EN][v4_EN_Build])):
|
Or build SRS from source(or [mirrors](#mirrors)), by CentOS7(or Linux([CN][v4_CN_Build],[EN][v4_EN_Build])):
|
||||||
|
|
||||||
```
|
```
|
||||||
|
@ -77,15 +79,20 @@ Other important wiki:
|
||||||
|
|
||||||
## Ports
|
## Ports
|
||||||
|
|
||||||
The ports used by SRS:
|
The ports used by SRS, kernel services:
|
||||||
|
|
||||||
|
* tcp://1935, for RTMP live streaming server([CN][v4_CN_DeliveryRTMP],[EN][v4_EN_DeliveryRTMP]).
|
||||||
|
* tcp://1985, HTTP API server, for HTTP-API([CN][v4_CN_HTTPApi], [EN][v4_EN_HTTPApi]), WebRTC([CN][v4_CN_WebRTC], [EN][v4_EN_WebRTC]), etc.
|
||||||
|
* tcp://8080, HTTP live streaming server, HTTP-FLV([CN][v4_CN_SampleHttpFlv], [EN][v4_EN_SampleHttpFlv]), HLS([CN][v4_CN_SampleHLS], [EN][v4_EN_SampleHLS]) as such.
|
||||||
|
* udp://8000, WebRTC Media([CN][v4_CN_WebRTC], [EN][v4_EN_WebRTC]) server.
|
||||||
|
|
||||||
|
For optional HTTPS services, which might be provided by other web servers:
|
||||||
|
|
||||||
* tcp://1935, for RTMP live streaming server.
|
|
||||||
* tcp://1985, HTTP API server.
|
|
||||||
* tcp://1990, HTTPS API server.
|
|
||||||
* tcp://8080, HTTP live streaming server.
|
|
||||||
* tcp://8088, HTTPS live streaming server.
|
* tcp://8088, HTTPS live streaming server.
|
||||||
* udp://8000, [WebRTC Media](https://github.com/ossrs/srs/wiki/v4_CN_WebRTC) server.
|
* tcp://1990, HTTPS API server.
|
||||||
* udp://1980, [WebRTC Signaling](https://github.com/ossrs/signaling#usage) server.
|
|
||||||
|
For optional stream caster services, to push streams to SRS:
|
||||||
|
|
||||||
* udp://8935, Stream Caster: [Push MPEGTS over UDP](https://github.com/ossrs/srs/wiki/v4_CN_Streamer#push-mpeg-ts-over-udp) server.
|
* udp://8935, Stream Caster: [Push MPEGTS over UDP](https://github.com/ossrs/srs/wiki/v4_CN_Streamer#push-mpeg-ts-over-udp) server.
|
||||||
* tcp://554, Stream Caster: [Push RTSP](https://github.com/ossrs/srs/wiki/v4_CN_Streamer#push-rtsp-to-srs) server.
|
* tcp://554, Stream Caster: [Push RTSP](https://github.com/ossrs/srs/wiki/v4_CN_Streamer#push-rtsp-to-srs) server.
|
||||||
* tcp://8936, Stream Caster: [Push HTTP-FLV](https://github.com/ossrs/srs/wiki/v4_CN_Streamer#push-http-flv-to-srs) server.
|
* tcp://8936, Stream Caster: [Push HTTP-FLV](https://github.com/ossrs/srs/wiki/v4_CN_Streamer#push-http-flv-to-srs) server.
|
||||||
|
@ -94,6 +101,10 @@ The ports used by SRS:
|
||||||
* udp://58200-58300, Stream Caster: [Push GB28181 Media(no-bundle)](https://github.com/ossrs/srs/issues/1500#issuecomment-606695679) server.
|
* udp://58200-58300, Stream Caster: [Push GB28181 Media(no-bundle)](https://github.com/ossrs/srs/issues/1500#issuecomment-606695679) server.
|
||||||
* udp://10080, Stream Caster: [Push SRT Media](https://github.com/ossrs/srs/issues/1147#issuecomment-577469119) server.
|
* udp://10080, Stream Caster: [Push SRT Media](https://github.com/ossrs/srs/issues/1147#issuecomment-577469119) server.
|
||||||
|
|
||||||
|
For external services to work with SRS:
|
||||||
|
|
||||||
|
* udp://1989, [WebRTC Signaling](https://github.com/ossrs/signaling#usage) server.
|
||||||
|
|
||||||
## Features
|
## Features
|
||||||
|
|
||||||
- [x] Using coroutine by ST, it's really simple and stupid enough.
|
- [x] Using coroutine by ST, it's really simple and stupid enough.
|
||||||
|
@ -1298,14 +1309,13 @@ Remark:
|
||||||
| ......) | | |
|
| ......) | | |
|
||||||
+----------------------+ | |
|
+----------------------+ | |
|
||||||
| MediaSource(2) | | |
|
| MediaSource(2) | | |
|
||||||
| (RTSP,FILE, | | |
|
| (MPEGTSoverUDP | | |
|
||||||
| HTTP,HLS, --push-+->- StreamCaster(4) -(rtmp)-+-> SRS |
|
| HTTP-FLV, --push-+->- StreamCaster(4) -(rtmp)-+-> SRS |
|
||||||
| Device, | | |
|
| GB28181,SRT, | | |
|
||||||
| ......) | | |
|
| ......) | | |
|
||||||
+----------------------+ | |
|
+----------------------+ | |
|
||||||
| FFMPEG --push(srt)--+->- SRTModule(5) ---(rtmp)-+-> SRS |
|
| FFMPEG --push(srt)--+->- SRTModule(5) ---(rtmp)-+-> SRS |
|
||||||
+----------------------+----------------------------+----------------+
|
+----------------------+----------------------------+----------------+
|
||||||
|
|
||||||
```
|
```
|
||||||
|
|
||||||
Remark:
|
Remark:
|
||||||
|
|
11
trunk/3rdparty/signaling/www/demos/index.html
vendored
11
trunk/3rdparty/signaling/www/demos/index.html
vendored
|
@ -19,7 +19,16 @@
|
||||||
let elems = document.getElementsByClassName('srs_demo');
|
let elems = document.getElementsByClassName('srs_demo');
|
||||||
for (var i = 0; i < elems.length; i++) {
|
for (var i = 0; i < elems.length; i++) {
|
||||||
let elem = elems.item(i);
|
let elem = elems.item(i);
|
||||||
elem.setAttribute('href', elem.getAttribute('href') + '&room=' + roomName);
|
|
||||||
|
// Use random room.
|
||||||
|
let href = elem.getAttribute('href') + '&room=' + roomName;
|
||||||
|
|
||||||
|
// For run demos on SRS http server.
|
||||||
|
if (window.location.port === '8080') {
|
||||||
|
href += '&wsp=1989';
|
||||||
|
}
|
||||||
|
|
||||||
|
elem.setAttribute('href', href);
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
</body>
|
</body>
|
||||||
|
|
52
trunk/3rdparty/signaling/www/demos/js/srs.sdk.js
vendored
52
trunk/3rdparty/signaling/www/demos/js/srs.sdk.js
vendored
|
@ -29,6 +29,14 @@
|
||||||
function SrsRtcPublisherAsync() {
|
function SrsRtcPublisherAsync() {
|
||||||
var self = {};
|
var self = {};
|
||||||
|
|
||||||
|
// https://developer.mozilla.org/en-US/docs/Web/API/MediaDevices/getUserMedia
|
||||||
|
self.constraints = {
|
||||||
|
audio: true,
|
||||||
|
video: {
|
||||||
|
width: {ideal: 320, max: 576}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
// @see https://github.com/rtcdn/rtcdn-draft
|
// @see https://github.com/rtcdn/rtcdn-draft
|
||||||
// @url The WebRTC url to play with, for example:
|
// @url The WebRTC url to play with, for example:
|
||||||
// webrtc://r.ossrs.net/live/livestream
|
// webrtc://r.ossrs.net/live/livestream
|
||||||
|
@ -56,12 +64,14 @@ function SrsRtcPublisherAsync() {
|
||||||
self.pc.addTransceiver("audio", {direction: "sendonly"});
|
self.pc.addTransceiver("audio", {direction: "sendonly"});
|
||||||
self.pc.addTransceiver("video", {direction: "sendonly"});
|
self.pc.addTransceiver("video", {direction: "sendonly"});
|
||||||
|
|
||||||
var stream = await navigator.mediaDevices.getUserMedia(
|
var stream = await navigator.mediaDevices.getUserMedia(self.constraints);
|
||||||
{audio: true, video: {width: {max: 320}}}
|
|
||||||
);
|
|
||||||
// @see https://developer.mozilla.org/en-US/docs/Web/API/RTCPeerConnection/addStream#Migrating_to_addTrack
|
// @see https://developer.mozilla.org/en-US/docs/Web/API/RTCPeerConnection/addStream#Migrating_to_addTrack
|
||||||
stream.getTracks().forEach(function (track) {
|
stream.getTracks().forEach(function (track) {
|
||||||
self.pc.addTrack(track);
|
self.pc.addTrack(track);
|
||||||
|
|
||||||
|
// Notify about local track when stream is ok.
|
||||||
|
self.ontrack && self.ontrack({track: track});
|
||||||
});
|
});
|
||||||
|
|
||||||
var offer = await self.pc.createOffer();
|
var offer = await self.pc.createOffer();
|
||||||
|
@ -94,9 +104,6 @@ function SrsRtcPublisherAsync() {
|
||||||
);
|
);
|
||||||
session.simulator = conf.schema + '//' + conf.urlObject.server + ':' + conf.port + '/rtc/v1/nack/';
|
session.simulator = conf.schema + '//' + conf.urlObject.server + ':' + conf.port + '/rtc/v1/nack/';
|
||||||
|
|
||||||
// Notify about local stream when success.
|
|
||||||
self.onaddstream && self.onaddstream({stream: stream});
|
|
||||||
|
|
||||||
return session;
|
return session;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -107,7 +114,10 @@ function SrsRtcPublisherAsync() {
|
||||||
};
|
};
|
||||||
|
|
||||||
// The callback when got local stream.
|
// The callback when got local stream.
|
||||||
self.onaddstream = function (event) {
|
// @see https://developer.mozilla.org/en-US/docs/Web/API/RTCPeerConnection/addStream#Migrating_to_addTrack
|
||||||
|
self.ontrack = function (event) {
|
||||||
|
// Add track to stream of SDK.
|
||||||
|
self.stream.addTrack(event.track);
|
||||||
};
|
};
|
||||||
|
|
||||||
// Internal APIs.
|
// Internal APIs.
|
||||||
|
@ -253,6 +263,11 @@ function SrsRtcPublisherAsync() {
|
||||||
|
|
||||||
self.pc = new RTCPeerConnection(null);
|
self.pc = new RTCPeerConnection(null);
|
||||||
|
|
||||||
|
// To keep api consistent between player and publisher.
|
||||||
|
// @see https://developer.mozilla.org/en-US/docs/Web/API/RTCPeerConnection/addStream#Migrating_to_addTrack
|
||||||
|
// @see https://webrtc.org/getting-started/media-devices
|
||||||
|
self.stream = new MediaStream();
|
||||||
|
|
||||||
return self;
|
return self;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -315,6 +330,7 @@ function SrsRtcPlayerAsync() {
|
||||||
await self.pc.setRemoteDescription(
|
await self.pc.setRemoteDescription(
|
||||||
new RTCSessionDescription({type: 'answer', sdp: session.sdp})
|
new RTCSessionDescription({type: 'answer', sdp: session.sdp})
|
||||||
);
|
);
|
||||||
|
session.simulator = conf.schema + '//' + conf.urlObject.server + ':' + conf.port + '/rtc/v1/nack/';
|
||||||
return session;
|
return session;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -324,8 +340,12 @@ function SrsRtcPlayerAsync() {
|
||||||
self.pc = null;
|
self.pc = null;
|
||||||
};
|
};
|
||||||
|
|
||||||
// The callback when got remote stream.
|
// The callback when got remote track.
|
||||||
self.onaddstream = function (event) {};
|
// Note that the onaddstream is deprecated, @see https://developer.mozilla.org/en-US/docs/Web/API/RTCPeerConnection/onaddstream
|
||||||
|
self.ontrack = function (event) {
|
||||||
|
// https://webrtc.org/getting-started/remote-streams
|
||||||
|
self.stream.addTrack(event.track);
|
||||||
|
};
|
||||||
|
|
||||||
// Internal APIs.
|
// Internal APIs.
|
||||||
self.__internal = {
|
self.__internal = {
|
||||||
|
@ -469,9 +489,14 @@ function SrsRtcPlayerAsync() {
|
||||||
};
|
};
|
||||||
|
|
||||||
self.pc = new RTCPeerConnection(null);
|
self.pc = new RTCPeerConnection(null);
|
||||||
self.pc.onaddstream = function (event) {
|
|
||||||
if (self.onaddstream) {
|
// Create a stream to add track to the stream, @see https://webrtc.org/getting-started/remote-streams
|
||||||
self.onaddstream(event);
|
self.stream = new MediaStream();
|
||||||
|
|
||||||
|
// https://developer.mozilla.org/en-US/docs/Web/API/RTCPeerConnection/ontrack
|
||||||
|
self.pc.ontrack = function(event) {
|
||||||
|
if (self.ontrack) {
|
||||||
|
self.ontrack(event);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -483,7 +508,8 @@ function SrsRtcPlayerAsync() {
|
||||||
function SrsRtcFormatSenders(senders, kind) {
|
function SrsRtcFormatSenders(senders, kind) {
|
||||||
var codecs = [];
|
var codecs = [];
|
||||||
senders.forEach(function (sender) {
|
senders.forEach(function (sender) {
|
||||||
sender.getParameters().codecs.forEach(function(c) {
|
var params = sender.getParameters();
|
||||||
|
params && params.codecs && params.codecs.forEach(function(c) {
|
||||||
if (kind && sender.track.kind !== kind) {
|
if (kind && sender.track.kind !== kind) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
14
trunk/3rdparty/signaling/www/demos/one2one.html
vendored
14
trunk/3rdparty/signaling/www/demos/one2one.html
vendored
|
@ -22,7 +22,7 @@
|
||||||
<a class="brand" href="https://github.com/ossrs/srs">SRS</a>
|
<a class="brand" href="https://github.com/ossrs/srs">SRS</a>
|
||||||
<div class="nav-collapse collapse">
|
<div class="nav-collapse collapse">
|
||||||
<ul class="nav srs_nav">
|
<ul class="nav srs_nav">
|
||||||
<li class="active"><a href="#">一对一通话</a></li>
|
<li class="active"><a href="one2one.html">一对一通话</a></li>
|
||||||
<li><a href="room.html">多人通话</a></li>
|
<li><a href="room.html">多人通话</a></li>
|
||||||
<li class="srs_ignore">
|
<li class="srs_ignore">
|
||||||
<a href="https://github.com/ossrs/signaling">
|
<a href="https://github.com/ossrs/signaling">
|
||||||
|
@ -226,10 +226,7 @@
|
||||||
publisher.close();
|
publisher.close();
|
||||||
}
|
}
|
||||||
publisher = new SrsRtcPublisherAsync();
|
publisher = new SrsRtcPublisherAsync();
|
||||||
publisher.onaddstream = function (event) {
|
$('#rtc_media_publisher').prop('srcObject', publisher.stream);
|
||||||
console.log('Start publish, event: ', event);
|
|
||||||
$('#rtc_media_publisher').prop('srcObject', event.stream);
|
|
||||||
};
|
|
||||||
|
|
||||||
return publisher.publish(url).then(function(session){
|
return publisher.publish(url).then(function(session){
|
||||||
$('#self').text('Self: ' + url);
|
$('#self').text('Self: ' + url);
|
||||||
|
@ -254,10 +251,7 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
player = new SrsRtcPlayerAsync();
|
player = new SrsRtcPlayerAsync();
|
||||||
player.onaddstream = function (event) {
|
$('#rtc_media_player').prop('srcObject', player.stream);
|
||||||
console.log('Start play, event: ', event);
|
|
||||||
$('#rtc_media_player').prop('srcObject', event.stream);
|
|
||||||
};
|
|
||||||
|
|
||||||
player.play(url).then(function(session){
|
player.play(url).then(function(session){
|
||||||
$('#peer').text('Peer: ' + display);
|
$('#peer').text('Peer: ' + display);
|
||||||
|
@ -284,7 +278,7 @@
|
||||||
$('#ff_preview').attr('href', 'http://ossrs.net/players/srs_player.html?app=' + $('#txt_room').val() + '&stream=merge.flv&server=' + conf.host + '&vhost=' + conf.host + '&autostart=true');
|
$('#ff_preview').attr('href', 'http://ossrs.net/players/srs_player.html?app=' + $('#txt_room').val() + '&stream=merge.flv&server=' + conf.host + '&vhost=' + conf.host + '&autostart=true');
|
||||||
|
|
||||||
// Update href for all navs.
|
// Update href for all navs.
|
||||||
$('ul.srs_nav').children('li').not('.srs_ignore').children('a').not("[href='#']").each(function (i, e) {
|
$('ul.srs_nav').children('li').not('.srs_ignore').children('a').each(function (i, e) {
|
||||||
$(e).attr('href', $(e).attr('href') + conf.rawQuery);
|
$(e).attr('href', $(e).attr('href') + conf.rawQuery);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
14
trunk/3rdparty/signaling/www/demos/room.html
vendored
14
trunk/3rdparty/signaling/www/demos/room.html
vendored
|
@ -23,7 +23,7 @@
|
||||||
<div class="nav-collapse collapse">
|
<div class="nav-collapse collapse">
|
||||||
<ul class="nav srs_nav">
|
<ul class="nav srs_nav">
|
||||||
<li><a href="one2one.html">一对一通话</a></li>
|
<li><a href="one2one.html">一对一通话</a></li>
|
||||||
<li class="active"><a href="#">多人通话</a></li>
|
<li class="active"><a href="room.html">多人通话</a></li>
|
||||||
<li class="srs_ignore">
|
<li class="srs_ignore">
|
||||||
<a href="https://github.com/ossrs/signaling">
|
<a href="https://github.com/ossrs/signaling">
|
||||||
<img alt="GitHub Repo stars" src="https://img.shields.io/github/stars/ossrs/signaling?style=social">
|
<img alt="GitHub Repo stars" src="https://img.shields.io/github/stars/ossrs/signaling?style=social">
|
||||||
|
@ -139,10 +139,7 @@
|
||||||
publisher.close();
|
publisher.close();
|
||||||
}
|
}
|
||||||
publisher = new SrsRtcPublisherAsync();
|
publisher = new SrsRtcPublisherAsync();
|
||||||
publisher.onaddstream = function (event) {
|
$('#rtc_media_publisher').prop('srcObject', publisher.stream);
|
||||||
console.log('Start publish, event: ', event);
|
|
||||||
$('#rtc_media_publisher').prop('srcObject', event.stream);
|
|
||||||
};
|
|
||||||
|
|
||||||
return publisher.publish(url).then(function(session){
|
return publisher.publish(url).then(function(session){
|
||||||
$('#self').text('Self: ' + url);
|
$('#self').text('Self: ' + url);
|
||||||
|
@ -178,10 +175,7 @@
|
||||||
video.show();
|
video.show();
|
||||||
ui.show();
|
ui.show();
|
||||||
|
|
||||||
player.onaddstream = function (event) {
|
video.prop('srcObject', player.stream);
|
||||||
console.log('Start play, event: ', event);
|
|
||||||
video.prop('srcObject', event.stream);
|
|
||||||
};
|
|
||||||
|
|
||||||
player.play(url).then(function(session){
|
player.play(url).then(function(session){
|
||||||
ui.children('#peer').text('Peer: ' + url);
|
ui.children('#peer').text('Peer: ' + url);
|
||||||
|
@ -200,7 +194,7 @@
|
||||||
$('#txt_display').val(conf.display);
|
$('#txt_display').val(conf.display);
|
||||||
|
|
||||||
// Update href for all navs.
|
// Update href for all navs.
|
||||||
$('ul.srs_nav').children('li').not('.srs_ignore').children('a').not("[href='#']").each(function (i, e) {
|
$('ul.srs_nav').children('li').not('.srs_ignore').children('a').each(function (i, e) {
|
||||||
$(e).attr('href', $(e).attr('href') + conf.rawQuery);
|
$(e).attr('href', $(e).attr('href') + conf.rawQuery);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -33,8 +33,8 @@ stream_caster {
|
||||||
# 接收设备端rtp流的多路复用端口
|
# 接收设备端rtp流的多路复用端口
|
||||||
listen 9000;
|
listen 9000;
|
||||||
# 多路复用端口类型,on为tcp,off为udp
|
# 多路复用端口类型,on为tcp,off为udp
|
||||||
# 默认:off
|
# 默认:on
|
||||||
tcp_enable off;
|
tcp_enable on;
|
||||||
|
|
||||||
# rtp接收监听端口范围,最小值
|
# rtp接收监听端口范围,最小值
|
||||||
rtp_port_min 58200;
|
rtp_port_min 58200;
|
||||||
|
@ -64,7 +64,8 @@ stream_caster {
|
||||||
|
|
||||||
# 是否开启rtp缓冲
|
# 是否开启rtp缓冲
|
||||||
# 开启之后能有效解决rtp乱序等问题
|
# 开启之后能有效解决rtp乱序等问题
|
||||||
jitterbuffer_enable on;
|
# tcp模式建议关闭
|
||||||
|
jitterbuffer_enable off;
|
||||||
|
|
||||||
# 服务器主机号,可以域名或ip地址
|
# 服务器主机号,可以域名或ip地址
|
||||||
# 也就是设备端将媒体发送的地址,如果是服务器是内外网
|
# 也就是设备端将媒体发送的地址,如果是服务器是内外网
|
||||||
|
|
143
trunk/conf/push.gb28181.tcp.conf
Normal file
143
trunk/conf/push.gb28181.tcp.conf
Normal file
|
@ -0,0 +1,143 @@
|
||||||
|
# push gb28181 stream to SRS.
|
||||||
|
|
||||||
|
listen 1935;
|
||||||
|
max_connections 1000;
|
||||||
|
daemon off;
|
||||||
|
srs_log_tank console;
|
||||||
|
|
||||||
|
http_api {
|
||||||
|
enabled on;
|
||||||
|
listen 1985;
|
||||||
|
}
|
||||||
|
|
||||||
|
http_server {
|
||||||
|
enabled on;
|
||||||
|
listen 8080;
|
||||||
|
}
|
||||||
|
|
||||||
|
stats {
|
||||||
|
network 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
stream_caster {
|
||||||
|
enabled on;
|
||||||
|
caster gb28181;
|
||||||
|
|
||||||
|
# 转发流到rtmp服务器地址与端口
|
||||||
|
# TODO: https://github.com/ossrs/srs/pull/1679/files#r400875104
|
||||||
|
# [stream] is VideoChannelCodecID(视频通道编码ID) for sip
|
||||||
|
# 自动创建的道通[stream] 是‘chid[ssrc]’ [ssrc]是rtp的ssrc
|
||||||
|
# [ssrc] rtp中的ssrc
|
||||||
|
output rtmp://127.0.0.1:1935/live/[stream];
|
||||||
|
|
||||||
|
# 接收设备端rtp流的多路复用端口
|
||||||
|
listen 9000;
|
||||||
|
# 多路复用端口类型,on为tcp,off为udp
|
||||||
|
# 默认:off
|
||||||
|
tcp_enable on;
|
||||||
|
|
||||||
|
# rtp接收监听端口范围,最小值
|
||||||
|
rtp_port_min 58200;
|
||||||
|
# rtp接收监听端口范围,最大值
|
||||||
|
rtp_port_max 58300;
|
||||||
|
|
||||||
|
# 是否等待关键帧之后,再转发,
|
||||||
|
# off:不需等待,直接转发
|
||||||
|
# on:等第一个关键帧后,再转发
|
||||||
|
wait_keyframe on;
|
||||||
|
|
||||||
|
# rtp包空闲等待时间,如果指定时间没有收到任何包
|
||||||
|
# rtp监听连接自动停止,发送BYE命令
|
||||||
|
rtp_idle_timeout 30;
|
||||||
|
|
||||||
|
# 是否转发音频流
|
||||||
|
# 目前只支持aac格式,所以需要设备支持aac格式
|
||||||
|
# on:转发音频
|
||||||
|
# off:不转发音频,只有视频
|
||||||
|
# *注意*!!!:flv 只支持11025 22050 44100 三种
|
||||||
|
# 如果设备端没有三种中任何一个,转发时为自动选择一种格式
|
||||||
|
# 同时也会将adts的头封装在flv aac raw数据中
|
||||||
|
# 这样的话播放器为自动通过adts头自动选择采样频率
|
||||||
|
# 像ffplay, vlc都可以,但是flash是没有声音,
|
||||||
|
# 因为flash,只支持11025 22050 44100
|
||||||
|
audio_enable off;
|
||||||
|
|
||||||
|
# 是否开启rtp缓冲
|
||||||
|
# 开启之后能有效解决rtp乱序等问题
|
||||||
|
# tcp模式建议关闭
|
||||||
|
jitterbuffer_enable off;
|
||||||
|
|
||||||
|
# 服务器主机号,可以域名或ip地址
|
||||||
|
# 也就是设备端将媒体发送的地址,如果是服务器是内外网
|
||||||
|
# 需要写外网地址,
|
||||||
|
# 调用api创建stream session时返回ip地址也是host
|
||||||
|
# $CANDIDATE 是系统环境变量,从环境变量获取地址,如果没有配置,用*
|
||||||
|
# *代表指定stats network 的网卡号地址,如果没有配置network,默认则是第0号网卡地址
|
||||||
|
# TODO: https://github.com/ossrs/srs/pull/1679/files#r400917594
|
||||||
|
host $CANDIDATE;
|
||||||
|
|
||||||
|
#根据收到ps rtp包自带创建rtmp媒体通道,不需要api接口创建
|
||||||
|
#rtmp地址参数[stream] 就是通道id 格式chid[ssrc]
|
||||||
|
auto_create_channel off;
|
||||||
|
|
||||||
|
sip {
|
||||||
|
# 是否启用srs内部sip信令
|
||||||
|
# 为on信令走srs, off 只转发ps流
|
||||||
|
enabled on;
|
||||||
|
|
||||||
|
# sip监听udp端口
|
||||||
|
listen 5060;
|
||||||
|
|
||||||
|
# SIP server ID(SIP服务器ID).
|
||||||
|
# 设备端配置编号需要与该值一致,否则无法注册
|
||||||
|
serial 34020000002000000001;
|
||||||
|
|
||||||
|
# SIP server domain(SIP服务器域)
|
||||||
|
realm 3402000000;
|
||||||
|
|
||||||
|
# 服务端发送ack后,接收回应的超时时间,单位为秒
|
||||||
|
# 如果指定时间没有回应,认为失败
|
||||||
|
ack_timeout 30;
|
||||||
|
|
||||||
|
# 设备心跳维持时间,如果指定时间内(秒)没有接收一个心跳
|
||||||
|
# 认为设备离线
|
||||||
|
keepalive_timeout 120;
|
||||||
|
|
||||||
|
# 注册之后是否自动给设备端发送invite
|
||||||
|
# on: 是 off 不是,需要通过api控制
|
||||||
|
auto_play on;
|
||||||
|
# 设备将流发送的端口,是否固定
|
||||||
|
# on 发送流到多路复用端口 如9000
|
||||||
|
# off 自动从rtp_mix_port - rtp_max_port 之间的值中
|
||||||
|
# 选一个可以用的端口
|
||||||
|
invite_port_fixed on;
|
||||||
|
|
||||||
|
# 向设备或下级域查询设备列表的间隔,单位(秒)
|
||||||
|
# 默认60秒
|
||||||
|
query_catalog_interval 60;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
rtc_server {
|
||||||
|
enabled on;
|
||||||
|
# Listen at udp://8000
|
||||||
|
listen 8000;
|
||||||
|
#
|
||||||
|
# The $CANDIDATE means fetch from env, if not configed, use * as default.
|
||||||
|
#
|
||||||
|
# The * means retrieving server IP automatically, from all network interfaces,
|
||||||
|
# @see https://github.com/ossrs/srs/issues/307#issuecomment-599028124
|
||||||
|
candidate $CANDIDATE;
|
||||||
|
}
|
||||||
|
|
||||||
|
vhost __defaultVhost__ {
|
||||||
|
rtc {
|
||||||
|
enabled on;
|
||||||
|
bframe discard;
|
||||||
|
}
|
||||||
|
|
||||||
|
http_remux {
|
||||||
|
enabled on;
|
||||||
|
mount [vhost]/[app]/[stream].flv;
|
||||||
|
}
|
||||||
|
}
|
|
@ -330,6 +330,8 @@ function SrsRtcPlayerAsync() {
|
||||||
await self.pc.setRemoteDescription(
|
await self.pc.setRemoteDescription(
|
||||||
new RTCSessionDescription({type: 'answer', sdp: session.sdp})
|
new RTCSessionDescription({type: 'answer', sdp: session.sdp})
|
||||||
);
|
);
|
||||||
|
session.simulator = conf.schema + '//' + conf.urlObject.server + ':' + conf.port + '/rtc/v1/nack/';
|
||||||
|
|
||||||
return session;
|
return session;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -202,6 +202,11 @@ srs_error_t SrsGb28181PsRtpProcessor::on_udp_packet(const sockaddr* from, const
|
||||||
return on_rtp_packet(from, fromlen, buf, nb_buf);
|
return on_rtp_packet(from, fromlen, buf, nb_buf);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
srs_error_t SrsGb28181PsRtpProcessor::on_tcp_packet(const sockaddr* from, const int fromlen, char* buf, int nb_buf)
|
||||||
|
{
|
||||||
|
on_udp_packet(from, fromlen, buf, nb_buf);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
srs_error_t SrsGb28181PsRtpProcessor::on_rtp_packet(const sockaddr* from, const int fromlen, char* buf, int nb_buf)
|
srs_error_t SrsGb28181PsRtpProcessor::on_rtp_packet(const sockaddr* from, const int fromlen, char* buf, int nb_buf)
|
||||||
{
|
{
|
||||||
|
@ -460,334 +465,6 @@ srs_error_t SrsGb28181PsRtpProcessor::on_rtp_packet_jitter(const sockaddr* from,
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
//SrsGb28181TcpPsRtpProcessor
|
|
||||||
SrsGb28181TcpPsRtpProcessor::SrsGb28181TcpPsRtpProcessor(SrsGb28181Config* c, std::string id)
|
|
||||||
{
|
|
||||||
config = c;
|
|
||||||
pprint = SrsPithyPrint::create_caster();
|
|
||||||
channel_id = id;
|
|
||||||
}
|
|
||||||
|
|
||||||
SrsGb28181TcpPsRtpProcessor::~SrsGb28181TcpPsRtpProcessor()
|
|
||||||
{
|
|
||||||
dispose();
|
|
||||||
srs_freep(pprint);
|
|
||||||
}
|
|
||||||
|
|
||||||
void SrsGb28181TcpPsRtpProcessor::dispose()
|
|
||||||
{
|
|
||||||
map<std::string, SrsPsRtpPacket*>::iterator it2;
|
|
||||||
for (it2 = cache_ps_rtp_packet.begin(); it2 != cache_ps_rtp_packet.end(); ++it2) {
|
|
||||||
srs_freep(it2->second);
|
|
||||||
}
|
|
||||||
cache_ps_rtp_packet.clear();
|
|
||||||
|
|
||||||
clear_pre_packet();
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
void SrsGb28181TcpPsRtpProcessor::clear_pre_packet()
|
|
||||||
{
|
|
||||||
map<std::string, SrsPsRtpPacket*>::iterator it;
|
|
||||||
for (it = pre_packet.begin(); it != pre_packet.end(); ++it) {
|
|
||||||
srs_freep(it->second);
|
|
||||||
}
|
|
||||||
pre_packet.clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
srs_error_t SrsGb28181TcpPsRtpProcessor::on_rtp(char* buf, int nb_buf, std::string ip, int port)
|
|
||||||
{
|
|
||||||
srs_error_t err = srs_success;
|
|
||||||
|
|
||||||
if (config->jitterbuffer_enable) {
|
|
||||||
err = on_rtp_packet_jitter(buf, nb_buf, ip, port);
|
|
||||||
if (err != srs_success) {
|
|
||||||
srs_warn("SrsGb28181TcpPsRtpProcessor::on_rtp on_rtp_packet_jitter err");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
return on_rtp_packet(buf, nb_buf, ip, port);
|
|
||||||
}
|
|
||||||
return err;
|
|
||||||
}
|
|
||||||
|
|
||||||
srs_error_t SrsGb28181TcpPsRtpProcessor::on_rtp_packet(char* buf, int nb_buf, std::string ip, int port)
|
|
||||||
{
|
|
||||||
srs_error_t err = srs_success;
|
|
||||||
bool completed = false;
|
|
||||||
|
|
||||||
pprint->elapse();
|
|
||||||
|
|
||||||
char address_string[64] = {0};
|
|
||||||
char port_string[16] = {0};
|
|
||||||
/*if (getnameinfo(from, fromlen,
|
|
||||||
(char*)&address_string, sizeof(address_string),
|
|
||||||
(char*)&port_string, sizeof(port_string),
|
|
||||||
NI_NUMERICHOST | NI_NUMERICSERV)) {
|
|
||||||
return srs_error_new(ERROR_SYSTEM_IP_INVALID, "bad address");
|
|
||||||
}*/
|
|
||||||
|
|
||||||
//itoa(port, port_string, 10);
|
|
||||||
int peer_port = port;// atoi(port_string);
|
|
||||||
|
|
||||||
if (true) {
|
|
||||||
SrsBuffer stream(buf, nb_buf);
|
|
||||||
SrsPsRtpPacket pkt;
|
|
||||||
|
|
||||||
if ((err = pkt.decode(&stream)) != srs_success) {
|
|
||||||
return srs_error_wrap(err, "ps rtp decode error");
|
|
||||||
}
|
|
||||||
|
|
||||||
//TODO: fixme: the same device uses the same SSRC to send with different local ports
|
|
||||||
std::stringstream ss;
|
|
||||||
ss << pkt.ssrc << ":" << pkt.timestamp << ":" << port;// port_string;
|
|
||||||
std::string pkt_key = ss.str();
|
|
||||||
|
|
||||||
std::stringstream ss2;
|
|
||||||
ss2 << pkt.ssrc << ":" << port_string;
|
|
||||||
std::string pre_pkt_key = ss2.str();
|
|
||||||
|
|
||||||
if (pre_packet.find(pre_pkt_key) == pre_packet.end()) {
|
|
||||||
pre_packet[pre_pkt_key] = new SrsPsRtpPacket();
|
|
||||||
pre_packet[pre_pkt_key]->copy(&pkt);
|
|
||||||
}
|
|
||||||
//cache pkt by ssrc and timestamp
|
|
||||||
if (cache_ps_rtp_packet.find(pkt_key) == cache_ps_rtp_packet.end()) {
|
|
||||||
cache_ps_rtp_packet[pkt_key] = new SrsPsRtpPacket();
|
|
||||||
}
|
|
||||||
|
|
||||||
//get previous timestamp by ssrc
|
|
||||||
uint32_t pre_timestamp = pre_packet[pre_pkt_key]->timestamp;
|
|
||||||
uint32_t pre_sequence_number = pre_packet[pre_pkt_key]->sequence_number;
|
|
||||||
|
|
||||||
//TODO: check sequence number out of order
|
|
||||||
//it may be out of order, or multiple streaming ssrc are the same
|
|
||||||
if (((pre_sequence_number + 1) % 65536) != pkt.sequence_number &&
|
|
||||||
pre_sequence_number != pkt.sequence_number) {
|
|
||||||
srs_warn("gb28181: ps sequence_number out of order, ssrc=%#x, pre=%u, cur=%u, peer(%s, %s)",
|
|
||||||
pkt.ssrc, pre_sequence_number, pkt.sequence_number, ip.c_str(), port_string);
|
|
||||||
//return err;
|
|
||||||
}
|
|
||||||
|
|
||||||
//copy header to cache
|
|
||||||
cache_ps_rtp_packet[pkt_key]->copy(&pkt);
|
|
||||||
//accumulate one frame of data, to payload cache
|
|
||||||
cache_ps_rtp_packet[pkt_key]->payload->append(pkt.payload);
|
|
||||||
|
|
||||||
//detect whether it is a completed frame
|
|
||||||
if (pkt.marker) {// rtp maker is true, is a completed frame
|
|
||||||
completed = true;
|
|
||||||
}
|
|
||||||
else if (pre_timestamp != pkt.timestamp) {
|
|
||||||
//current timestamp is different from previous timestamp
|
|
||||||
//previous timestamp, is a completed frame
|
|
||||||
std::stringstream ss;
|
|
||||||
ss << pkt.ssrc << ":" << pre_timestamp << ":" << port_string;
|
|
||||||
pkt_key = ss.str();
|
|
||||||
if (cache_ps_rtp_packet.find(pkt_key) != cache_ps_rtp_packet.end()) {
|
|
||||||
completed = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (pprint->can_print()) {
|
|
||||||
srs_trace("<- " SRS_CONSTS_LOG_GB28181_CASTER " gb28181: client_id %s, peer(%s, %d) ps rtp packet %dB, age=%d, vt=%d/%u, sts=%u/%u/%#x, paylod=%dB",
|
|
||||||
channel_id.c_str(), ip.c_str(), peer_port, nb_buf, pprint->age(), pkt.version,
|
|
||||||
pkt.payload_type, pkt.sequence_number, pkt.timestamp, pkt.ssrc,
|
|
||||||
pkt.payload->length()
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
//current packet becomes previous packet
|
|
||||||
srs_freep(pre_packet[pre_pkt_key]);
|
|
||||||
pre_packet[pre_pkt_key] = new SrsPsRtpPacket();
|
|
||||||
pre_packet[pre_pkt_key]->copy(&pkt);;
|
|
||||||
|
|
||||||
if (!completed) {
|
|
||||||
return err;
|
|
||||||
}
|
|
||||||
//process completed frame data
|
|
||||||
//clear processed one ps frame
|
|
||||||
//on completed frame data rtp packet in muxer enqueue
|
|
||||||
map<std::string, SrsPsRtpPacket*>::iterator key = cache_ps_rtp_packet.find(pkt_key);
|
|
||||||
if (key != cache_ps_rtp_packet.end())
|
|
||||||
{
|
|
||||||
SrsGb28181RtmpMuxer* muxer = NULL;
|
|
||||||
//First, search according to the channel_id. Otherwise, search according to the SSRC.
|
|
||||||
//Some channel_id are created by RTP pool, which are different ports.
|
|
||||||
//No channel_id are created by multiplexing ports, which are the same port
|
|
||||||
if (!channel_id.empty()) {
|
|
||||||
muxer = _srs_gb28181->fetch_rtmpmuxer(channel_id);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
muxer = _srs_gb28181->fetch_rtmpmuxer_by_ssrc(pkt.ssrc);
|
|
||||||
}
|
|
||||||
|
|
||||||
//auto crate channel
|
|
||||||
if (!muxer && config->auto_create_channel) {
|
|
||||||
//auto create channel generated id
|
|
||||||
std::stringstream ss, ss1;
|
|
||||||
ss << "chid" << pkt.ssrc;
|
|
||||||
std::string tmp_id = ss.str();
|
|
||||||
|
|
||||||
SrsGb28181StreamChannel channel;
|
|
||||||
channel.set_channel_id(tmp_id);
|
|
||||||
channel.set_port_mode(RTP_PORT_MODE_FIXED);
|
|
||||||
channel.set_ssrc(pkt.ssrc);
|
|
||||||
|
|
||||||
srs_error_t err2 = srs_success;
|
|
||||||
if ((err2 = _srs_gb28181->create_stream_channel(&channel)) != srs_success) {
|
|
||||||
srs_warn("gb28181: RtpProcessor create stream channel error %s", srs_error_desc(err2).c_str());
|
|
||||||
srs_error_reset(err2);
|
|
||||||
};
|
|
||||||
|
|
||||||
muxer = _srs_gb28181->fetch_rtmpmuxer(tmp_id);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (muxer) {
|
|
||||||
//TODO: fixme: the same device uses the same SSRC to send with different local ports
|
|
||||||
//record the first peer port
|
|
||||||
muxer->set_channel_peer_port(peer_port);
|
|
||||||
muxer->set_channel_peer_ip(address_string);
|
|
||||||
//not the first peer port's non processing
|
|
||||||
if (muxer->channel_peer_port() != peer_port) {
|
|
||||||
srs_warn("<- " SRS_CONSTS_LOG_GB28181_CASTER " gb28181: client_id %s, ssrc=%#x, first peer_port=%d cur peer_port=%d",
|
|
||||||
muxer->get_channel_id().c_str(), pkt.ssrc, muxer->channel_peer_port(), peer_port);
|
|
||||||
srs_freep(key->second);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
//put it in queue, wait for consumer to process, and then free
|
|
||||||
muxer->ps_packet_enqueue(key->second);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
//no consumer process it, discarded
|
|
||||||
srs_freep(key->second);
|
|
||||||
}
|
|
||||||
cache_ps_rtp_packet.erase(pkt_key);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return err;
|
|
||||||
}
|
|
||||||
|
|
||||||
SrsGb28181RtmpMuxer* SrsGb28181TcpPsRtpProcessor::create_rtmpmuxer(std::string channel_id, uint32_t ssrc)
|
|
||||||
{
|
|
||||||
if (true) {
|
|
||||||
SrsGb28181RtmpMuxer* muxer = NULL;
|
|
||||||
//First, search according to the channel_id. Otherwise, search according to the SSRC.
|
|
||||||
//Some channel_id are created by RTP pool, which are different ports.
|
|
||||||
//No channel_id are created by multiplexing ports, which are the same port
|
|
||||||
if (!channel_id.empty()) {
|
|
||||||
muxer = _srs_gb28181->fetch_rtmpmuxer(channel_id);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
muxer = _srs_gb28181->fetch_rtmpmuxer_by_ssrc(ssrc);
|
|
||||||
}
|
|
||||||
|
|
||||||
//auto crate channel
|
|
||||||
if (!muxer && config->auto_create_channel) {
|
|
||||||
//auto create channel generated id
|
|
||||||
std::stringstream ss, ss1;
|
|
||||||
ss << "chid" << ssrc;
|
|
||||||
std::string tmp_id = ss.str();
|
|
||||||
|
|
||||||
SrsGb28181StreamChannel channel;
|
|
||||||
channel.set_channel_id(tmp_id);
|
|
||||||
channel.set_port_mode(RTP_PORT_MODE_FIXED);
|
|
||||||
channel.set_ssrc(ssrc);
|
|
||||||
|
|
||||||
srs_error_t err2 = srs_success;
|
|
||||||
if ((err2 = _srs_gb28181->create_stream_channel(&channel)) != srs_success) {
|
|
||||||
srs_warn("gb28181: RtpProcessor create stream channel error %s", srs_error_desc(err2).c_str());
|
|
||||||
srs_error_reset(err2);
|
|
||||||
};
|
|
||||||
|
|
||||||
muxer = _srs_gb28181->fetch_rtmpmuxer(tmp_id);
|
|
||||||
}
|
|
||||||
|
|
||||||
return muxer;
|
|
||||||
}//end if FoundFrame
|
|
||||||
}
|
|
||||||
|
|
||||||
srs_error_t SrsGb28181TcpPsRtpProcessor::rtmpmuxer_enqueue_data(SrsGb28181RtmpMuxer *muxer, uint32_t ssrc,
|
|
||||||
int peer_port, std::string address_string, SrsPsRtpPacket *pkt)
|
|
||||||
{
|
|
||||||
srs_error_t err = srs_success;
|
|
||||||
|
|
||||||
if (!muxer)
|
|
||||||
return err;
|
|
||||||
|
|
||||||
if (muxer) {
|
|
||||||
//TODO: fixme: the same device uses the same SSRC to send with different local ports
|
|
||||||
//record the first peer port
|
|
||||||
muxer->set_channel_peer_port(peer_port);
|
|
||||||
muxer->set_channel_peer_ip(address_string);
|
|
||||||
//not the first peer port's non processing
|
|
||||||
if (muxer->channel_peer_port() != peer_port) {
|
|
||||||
srs_warn("<- " SRS_CONSTS_LOG_GB28181_CASTER " gb28181: client_id %s, ssrc=%#x, first peer_port=%d cur peer_port=%d",
|
|
||||||
muxer->get_channel_id().c_str(), ssrc, muxer->channel_peer_port(), peer_port);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
//muxer->ps_packet_enqueue(pkt);
|
|
||||||
muxer->insert_jitterbuffer(pkt);
|
|
||||||
}//end if (muxer->channel_peer_port() != peer_port)
|
|
||||||
}//end if (muxer)
|
|
||||||
|
|
||||||
return err;
|
|
||||||
}
|
|
||||||
|
|
||||||
srs_error_t SrsGb28181TcpPsRtpProcessor::on_rtp_packet_jitter(char* buf, int nb_buf, std::string ip, int port)
|
|
||||||
{
|
|
||||||
srs_error_t err = srs_success;
|
|
||||||
|
|
||||||
pprint->elapse();
|
|
||||||
|
|
||||||
char address_string[64] = {0};
|
|
||||||
/*char port_string[16] = {0};
|
|
||||||
if (getnameinfo(from, fromlen,
|
|
||||||
(char*)&address_string, sizeof(address_string),
|
|
||||||
(char*)&port_string, sizeof(port_string),
|
|
||||||
NI_NUMERICHOST | NI_NUMERICSERV)) {
|
|
||||||
return srs_error_new(ERROR_SYSTEM_IP_INVALID, "bad address");
|
|
||||||
}*/
|
|
||||||
|
|
||||||
//itoa(port, port_string, 10);
|
|
||||||
int peer_port = port;// atoi(port_string);
|
|
||||||
|
|
||||||
if (true) {
|
|
||||||
SrsBuffer stream(buf, nb_buf);
|
|
||||||
SrsPsRtpPacket *pkt = new SrsPsRtpPacket();;
|
|
||||||
|
|
||||||
if ((err = pkt->decode(&stream)) != srs_success) {
|
|
||||||
srs_freep(pkt);
|
|
||||||
return srs_error_wrap(err, "ps rtp decode error");
|
|
||||||
}
|
|
||||||
|
|
||||||
std::stringstream ss3;
|
|
||||||
ss3 << pkt->ssrc << ":" << port;// port_string;
|
|
||||||
std::string jitter_key = ss3.str();
|
|
||||||
|
|
||||||
pkt->completed = pkt->marker;
|
|
||||||
|
|
||||||
|
|
||||||
if (pprint->can_print()) {
|
|
||||||
srs_trace("<- " SRS_CONSTS_LOG_GB28181_CASTER " SrsGb28181TcpPsRtpProcessor::on_rtp_packet_jitter gb28181: client_id %s, peer(%s, %d) ps rtp packet %dB, age=%d, vt=%d/%u, sts=%u/%u/%#x, paylod=%dB",
|
|
||||||
channel_id.c_str(), address_string, peer_port, nb_buf, pprint->age(), pkt->version,
|
|
||||||
pkt->payload_type, pkt->sequence_number, pkt->timestamp, pkt->ssrc,
|
|
||||||
pkt->payload->length()
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
SrsGb28181RtmpMuxer *muxer = create_rtmpmuxer(channel_id, pkt->ssrc);
|
|
||||||
if (muxer) {
|
|
||||||
rtmpmuxer_enqueue_data(muxer, pkt->ssrc, peer_port, ip, pkt);
|
|
||||||
}
|
|
||||||
|
|
||||||
SrsAutoFree(SrsPsRtpPacket, pkt);
|
|
||||||
}
|
|
||||||
|
|
||||||
return err;
|
|
||||||
}
|
|
||||||
|
|
||||||
//ISrsPsStreamHander ps stream raw video/audio hander interface
|
//ISrsPsStreamHander ps stream raw video/audio hander interface
|
||||||
ISrsPsStreamHander::ISrsPsStreamHander()
|
ISrsPsStreamHander::ISrsPsStreamHander()
|
||||||
|
@ -2830,9 +2507,10 @@ srs_error_t SrsGb28181Manger::query_device_list(std::string id, SrsJsonArray* ar
|
||||||
|
|
||||||
return sip_service->query_device_list(id, arr);
|
return sip_service->query_device_list(id, arr);
|
||||||
}
|
}
|
||||||
|
#define SRS_RTSP_BUFFER 8192
|
||||||
#define SRS_RTSP_BUFFER 262144
|
#define RTP_TCP_HEADER 2
|
||||||
SrsGb28181Conn::SrsGb28181Conn(SrsGb28181Caster* c, srs_netfd_t fd, SrsGb28181TcpPsRtpProcessor *rtp_processor)
|
#define MAX_PACKAGE_SIZE 1024 * 10
|
||||||
|
SrsGb28181Conn::SrsGb28181Conn(SrsGb28181Caster* c, srs_netfd_t fd, SrsGb28181PsRtpProcessor *rtp_processor)
|
||||||
{
|
{
|
||||||
caster = c;
|
caster = c;
|
||||||
stfd = fd;
|
stfd = fd;
|
||||||
|
@ -2877,90 +2555,64 @@ srs_error_t SrsGb28181Conn::do_cycle()
|
||||||
{
|
{
|
||||||
srs_error_t err = srs_success;
|
srs_error_t err = srs_success;
|
||||||
|
|
||||||
// retrieve ip of client.
|
// retrieve ip of client.
|
||||||
int fd = srs_netfd_fileno(stfd);
|
int fd = srs_netfd_fileno(stfd);
|
||||||
std::string ip = srs_get_peer_ip(fd);
|
std::string ip = srs_get_peer_ip(fd);
|
||||||
int port = srs_get_peer_port(fd);
|
int port = srs_get_peer_port(fd);
|
||||||
|
int addr_len = sizeof(sockaddr_in);
|
||||||
|
sockaddr_in *peer_sockaddr = (sockaddr_in*)malloc(addr_len);
|
||||||
|
peer_sockaddr->sin_family = AF_INET; //设置地址家族
|
||||||
|
peer_sockaddr->sin_port = htons(port); //设置端口
|
||||||
|
peer_sockaddr->sin_addr.s_addr = inet_addr(ip.c_str());
|
||||||
|
|
||||||
if (ip.empty() && !_srs_config->empty_ip_ok()) {
|
|
||||||
srs_warn("empty ip for fd=%d", srs_netfd_fileno(stfd));
|
|
||||||
}
|
|
||||||
srs_trace("rtsp: serve %s:%d", ip.c_str(), port);
|
|
||||||
|
|
||||||
char* leftData = (char*)malloc(SRS_RTSP_BUFFER);;
|
if (ip.empty() && !_srs_config->empty_ip_ok()) {
|
||||||
uint32_t leftDataLength = 0;
|
srs_warn("empty ip for fd=%d", srs_netfd_fileno(stfd));
|
||||||
int16_t length = 0;
|
}
|
||||||
char* pp = (char*)&length;
|
srs_trace("gb28181 new connect by rtp-tcp from: %s:%d", ip.c_str(), port);
|
||||||
char* p = &(mbuffer[0]);
|
|
||||||
ssize_t nb_read = 0;
|
|
||||||
int16_t length2;
|
|
||||||
|
|
||||||
// consume all rtp data.
|
uint32_t left_data_len = 0; //缓存剩余数据
|
||||||
while (true) {
|
ssize_t nb_read = 0;
|
||||||
if ((err = trd->pull()) != srs_success) {
|
uint16_t packet_len = 0; //rtp包长度
|
||||||
free(leftData);
|
|
||||||
return srs_error_wrap(err, "rtsp cycle");
|
|
||||||
}
|
|
||||||
|
|
||||||
//memset(buffer, 0, SRS_RTSP_BUFFER);
|
// consume all rtp data.
|
||||||
nb_read = 0;
|
while (true) {
|
||||||
if ((err = skt->read(mbuffer + leftDataLength, SRS_RTSP_BUFFER - leftDataLength, &nb_read)) != srs_success) {
|
if ((err = trd->pull()) != srs_success) {
|
||||||
free(leftData);
|
return srs_error_wrap(err, "rtsp cycle");
|
||||||
return srs_error_wrap(err, "recv data");
|
}
|
||||||
}
|
nb_read = 0;
|
||||||
|
if ((err = skt->read(mbuffer + left_data_len, SRS_RTSP_BUFFER - left_data_len, &nb_read)) != srs_success) {
|
||||||
|
return srs_error_wrap(err, "recv data");
|
||||||
|
}
|
||||||
|
|
||||||
nb_read = nb_read + leftDataLength;
|
left_data_len = nb_read + left_data_len;
|
||||||
|
char * buf = mbuffer;
|
||||||
|
|
||||||
pp = (char*)&length;
|
uint32_t index = 0;
|
||||||
p = &(mbuffer[0]);
|
for( ; index < left_data_len; ){
|
||||||
pp[1] = *p++;
|
if (index + RTP_TCP_HEADER >= left_data_len){ //less rtp package
|
||||||
pp[0] = *p++;
|
break;
|
||||||
|
}
|
||||||
|
packet_len = (((uint8_t *) buf)[index] << 8) | ((uint8_t *) buf)[index + 1];
|
||||||
|
if (packet_len > MAX_PACKAGE_SIZE){
|
||||||
|
//FIXME 自动重新invite?
|
||||||
|
srs_error("abnormal RTP packet length:%d, close the tcp conn:%s", packet_len, remote_ip().c_str());
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
if (index + RTP_TCP_HEADER + packet_len >= left_data_len){
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
processor->on_tcp_packet((sockaddr*)peer_sockaddr, addr_len, buf + index + RTP_TCP_HEADER, packet_len);
|
||||||
|
index = index + RTP_TCP_HEADER + packet_len;
|
||||||
|
}
|
||||||
|
if (index != 0) { //update left data
|
||||||
|
left_data_len = left_data_len - index;
|
||||||
|
memmove(mbuffer, buf + index, left_data_len);
|
||||||
|
}
|
||||||
|
|
||||||
if (nb_read < (length + 2)) {//Not enough one packet.
|
}
|
||||||
leftDataLength = leftDataLength + nb_read;
|
free(peer_sockaddr);
|
||||||
continue;
|
return err;
|
||||||
}
|
|
||||||
|
|
||||||
memset(leftData, 0, SRS_RTSP_BUFFER);
|
|
||||||
|
|
||||||
while (length > 0) {
|
|
||||||
if ((length + 2) == nb_read) {//Only one packet.
|
|
||||||
nb_read = nb_read - 2;
|
|
||||||
processor->on_rtp(mbuffer + 2, nb_read, ip, port);
|
|
||||||
leftDataLength = 0;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
else { //multi packets.
|
|
||||||
pp = (char*)&length2;
|
|
||||||
p = &(mbuffer[length + 2]);
|
|
||||||
pp[1] = *p++;
|
|
||||||
pp[0] = *p++;
|
|
||||||
|
|
||||||
processor->on_rtp(mbuffer + 2, length, ip, port);
|
|
||||||
|
|
||||||
leftDataLength = nb_read - (length + 2);
|
|
||||||
nb_read = leftDataLength;
|
|
||||||
memcpy(leftData, mbuffer + length + 2, leftDataLength);
|
|
||||||
|
|
||||||
pp = (char*)&length;
|
|
||||||
p = &(mbuffer[length + 2]);
|
|
||||||
pp[1] = *p++;
|
|
||||||
pp[0] = *p++;
|
|
||||||
|
|
||||||
if (leftDataLength < (length + 2)) {//Not enough one packet.
|
|
||||||
memcpy(mbuffer, leftData, leftDataLength);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
memcpy(mbuffer, leftData, leftDataLength);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
free(leftData);
|
|
||||||
|
|
||||||
return err;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
srs_error_t SrsGb28181Conn::cycle()
|
srs_error_t SrsGb28181Conn::cycle()
|
||||||
|
@ -2996,7 +2648,7 @@ SrsGb28181Caster::SrsGb28181Caster(SrsConfDirective* c)
|
||||||
// TODO: FIXME: support reload.
|
// TODO: FIXME: support reload.
|
||||||
output = _srs_config->get_stream_caster_output(c);
|
output = _srs_config->get_stream_caster_output(c);
|
||||||
config = new SrsGb28181Config(c);
|
config = new SrsGb28181Config(c);
|
||||||
rtp_processor = new SrsGb28181TcpPsRtpProcessor(config, "");
|
rtp_processor = new SrsGb28181PsRtpProcessor(config, "");
|
||||||
manager = new SrsResourceManager("GB28181TCP", true);
|
manager = new SrsResourceManager("GB28181TCP", true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -94,7 +94,6 @@ class SrsSipRequest;
|
||||||
class SrsGb28181RtmpMuxer;
|
class SrsGb28181RtmpMuxer;
|
||||||
class SrsGb28181Config;
|
class SrsGb28181Config;
|
||||||
class SrsGb28181PsRtpProcessor;
|
class SrsGb28181PsRtpProcessor;
|
||||||
class SrsGb28181TcpPsRtpProcessor;
|
|
||||||
class SrsGb28181SipService;
|
class SrsGb28181SipService;
|
||||||
class SrsGb28181StreamChannel;
|
class SrsGb28181StreamChannel;
|
||||||
class SrsGb28181SipSession;
|
class SrsGb28181SipSession;
|
||||||
|
@ -176,37 +175,12 @@ private:
|
||||||
// Interface ISrsUdpHandler
|
// Interface ISrsUdpHandler
|
||||||
public:
|
public:
|
||||||
virtual srs_error_t on_udp_packet(const sockaddr* from, const int fromlen, char* buf, int nb_buf);
|
virtual srs_error_t on_udp_packet(const sockaddr* from, const int fromlen, char* buf, int nb_buf);
|
||||||
|
virtual srs_error_t on_tcp_packet(const sockaddr* from, const int fromlen, char* buf, int nb_buf);
|
||||||
public:
|
public:
|
||||||
virtual srs_error_t on_rtp_packet_jitter(const sockaddr* from, const int fromlen, char* buf, int nb_buf);
|
virtual srs_error_t on_rtp_packet_jitter(const sockaddr* from, const int fromlen, char* buf, int nb_buf);
|
||||||
virtual srs_error_t on_rtp_packet(const sockaddr* from, const int fromlen, char* buf, int nb_buf);
|
virtual srs_error_t on_rtp_packet(const sockaddr* from, const int fromlen, char* buf, int nb_buf);
|
||||||
};
|
};
|
||||||
|
|
||||||
class SrsGb28181TcpPsRtpProcessor
|
|
||||||
{
|
|
||||||
private:
|
|
||||||
SrsPithyPrint* pprint;
|
|
||||||
SrsGb28181Config* config;
|
|
||||||
std::map<std::string, SrsPsRtpPacket*> cache_ps_rtp_packet;
|
|
||||||
std::map<std::string, SrsPsRtpPacket*> pre_packet;
|
|
||||||
std::string channel_id;
|
|
||||||
bool auto_create_channel;
|
|
||||||
public:
|
|
||||||
SrsGb28181TcpPsRtpProcessor(SrsGb28181Config* c, std::string sid);
|
|
||||||
virtual ~SrsGb28181TcpPsRtpProcessor();
|
|
||||||
private:
|
|
||||||
bool can_send_ps_av_packet();
|
|
||||||
void dispose();
|
|
||||||
void clear_pre_packet();
|
|
||||||
SrsGb28181RtmpMuxer* create_rtmpmuxer(std::string channel_id, uint32_t ssrc);
|
|
||||||
srs_error_t rtmpmuxer_enqueue_data(SrsGb28181RtmpMuxer *muxer, uint32_t ssrc,
|
|
||||||
int peer_port, std::string address_string, SrsPsRtpPacket *pkt);
|
|
||||||
// Interface ISrsTcpHandler
|
|
||||||
public:
|
|
||||||
virtual srs_error_t on_rtp(char* buf, int nb_buf, std::string ip, int port);
|
|
||||||
public:
|
|
||||||
virtual srs_error_t on_rtp_packet_jitter(char* buf, int nb_buf, std::string ip, int port);
|
|
||||||
virtual srs_error_t on_rtp_packet(char* buf, int nb_buf, std::string ip, int port);
|
|
||||||
};
|
|
||||||
|
|
||||||
//ps stream processing parsing interface
|
//ps stream processing parsing interface
|
||||||
class ISrsPsStreamHander
|
class ISrsPsStreamHander
|
||||||
|
@ -581,9 +555,9 @@ private:
|
||||||
SrsRtspStack* rtsp;
|
SrsRtspStack* rtsp;
|
||||||
SrsGb28181Caster* caster;
|
SrsGb28181Caster* caster;
|
||||||
SrsCoroutine* trd;
|
SrsCoroutine* trd;
|
||||||
SrsGb28181TcpPsRtpProcessor *processor;
|
SrsGb28181PsRtpProcessor *processor;
|
||||||
public:
|
public:
|
||||||
SrsGb28181Conn(SrsGb28181Caster* c, srs_netfd_t fd, SrsGb28181TcpPsRtpProcessor *rtp_processor);
|
SrsGb28181Conn(SrsGb28181Caster* c, srs_netfd_t fd, SrsGb28181PsRtpProcessor *rtp_processor);
|
||||||
virtual ~SrsGb28181Conn();
|
virtual ~SrsGb28181Conn();
|
||||||
public:
|
public:
|
||||||
virtual srs_error_t serve();
|
virtual srs_error_t serve();
|
||||||
|
@ -603,7 +577,7 @@ class SrsGb28181Caster : public ISrsTcpHandler
|
||||||
private:
|
private:
|
||||||
std::string output;
|
std::string output;
|
||||||
SrsGb28181Config *config;
|
SrsGb28181Config *config;
|
||||||
SrsGb28181TcpPsRtpProcessor *rtp_processor;
|
SrsGb28181PsRtpProcessor *rtp_processor;
|
||||||
private:
|
private:
|
||||||
std::vector<SrsGb28181Conn*> clients;
|
std::vector<SrsGb28181Conn*> clients;
|
||||||
SrsResourceManager* manager;
|
SrsResourceManager* manager;
|
||||||
|
|
|
@ -1062,6 +1062,8 @@ void SrsSipStack::req_invite(stringstream& ss, SrsSipRequest *req, string ip, in
|
||||||
//<< "m=video " << port << " TCP/RTP/AVP 98" << SRS_RTSP_CRLF
|
//<< "m=video " << port << " TCP/RTP/AVP 98" << SRS_RTSP_CRLF
|
||||||
<< "a=recvonly" << SRS_RTSP_CRLF
|
<< "a=recvonly" << SRS_RTSP_CRLF
|
||||||
<< "a=rtpmap:96 PS/90000" << SRS_RTSP_CRLF
|
<< "a=rtpmap:96 PS/90000" << SRS_RTSP_CRLF
|
||||||
|
<< "a=setup:passive" << SRS_RTSP_CRLF
|
||||||
|
<< "a=connection:new" << SRS_RTSP_CRLF
|
||||||
//TODO: current no support
|
//TODO: current no support
|
||||||
//<< "a=rtpmap:97 MPEG4/90000" << SRS_RTSP_CRLF
|
//<< "a=rtpmap:97 MPEG4/90000" << SRS_RTSP_CRLF
|
||||||
//<< "a=rtpmap:98 H264/90000" << SRS_RTSP_CRLF
|
//<< "a=rtpmap:98 H264/90000" << SRS_RTSP_CRLF
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue