mirror of
https://github.com/ossrs/srs.git
synced 2025-02-15 04:42:04 +00:00
Merge
This commit is contained in:
commit
16162eccce
34 changed files with 836 additions and 85 deletions
|
@ -182,6 +182,8 @@ The ports used by SRS:
|
|||
|
||||
## V4 changes
|
||||
|
||||
* v4.0, 2021-05-04, Add video room demo. 4.0.98
|
||||
* v4.0, 2021-05-03, Add RTC stream merging demo by FFmpeg. 4.0.97
|
||||
* v4.0, 2021-05-02, Add one to one demo. 4.0.96
|
||||
* v4.0, 2021-04-20, Support RTC2RTMP bridger and shared FastTimer. 4.0.95
|
||||
* v4.0, 2021-04-20, Refine transcoder to support aac2opus and opus2aac. 4.0.94
|
||||
|
|
22
trunk/3rdparty/copy_to_gits.sh
vendored
Executable file
22
trunk/3rdparty/copy_to_gits.sh
vendored
Executable file
|
@ -0,0 +1,22 @@
|
|||
#!/bin/bash
|
||||
|
||||
if [[ ! -d signaling ]]; then
|
||||
cd 3rdparty
|
||||
fi
|
||||
if [[ ! -d signaling ]]; then
|
||||
echo "no 3rdparty"
|
||||
exit -1
|
||||
fi
|
||||
if [[ ! -d ~/git/signaling ]]; then
|
||||
echo "no signaling"
|
||||
exit -1
|
||||
fi
|
||||
|
||||
echo "Copy signaling"
|
||||
cp -R signaling/* ~/git/signaling/ && (cd ~/git/signaling && git st)
|
||||
|
||||
echo "Copy httpx-static"
|
||||
cp -R httpx-static/* ~/git/go-oryx/httpx-static/ && (cd ~/git/go-oryx && git st)
|
||||
|
||||
echo "Copy srs-bench"
|
||||
cp -R srs-bench/* ~/git/srs-bench/ && (cd ~/git/srs-bench && git st)
|
21
trunk/3rdparty/httpx-static/README.md
vendored
21
trunk/3rdparty/httpx-static/README.md
vendored
|
@ -29,7 +29,7 @@ $GOPATH/bin/httpx-static -https 8443 -root `pwd`/html
|
|||
|
||||
Open https://localhost:8443/ in browser.
|
||||
|
||||
> Remark: Click `ADVANCED` => `Proceed to localhost (unsafe)`.
|
||||
> Remark: Click `ADVANCED` => `Proceed to localhost (unsafe)`, or type `thisisunsafe` in page.
|
||||
|
||||
*HTTPS proxy*: Proxy http as https
|
||||
|
||||
|
@ -44,6 +44,25 @@ $GOPATH/bin/httpx-static -https 8443 -root `pwd`/html -proxy http://ossrs.net:19
|
|||
|
||||
Open https://localhost:8443/api/v1/summaries in browser.
|
||||
|
||||
## Docker
|
||||
|
||||
Run httpx-static in docker:
|
||||
|
||||
```bash
|
||||
docker run --rm -p 80:80 -p 443:443 registry.cn-hangzhou.aliyuncs.com/ossrs/httpx:v1.0.2
|
||||
```
|
||||
|
||||
> Note: More images and version is [here](https://cr.console.aliyun.com/repository/cn-hangzhou/ossrs/httpx/images).
|
||||
|
||||
To proxy to other dockers, in macOS:
|
||||
|
||||
```bash
|
||||
CANDIDATE=$(ifconfig en0 inet| grep 'inet '|awk '{print $2}') &&
|
||||
docker run --rm -p 80:80 -p 443:443 registry.cn-hangzhou.aliyuncs.com/ossrs/httpx:v1.0.5 \
|
||||
./bin/httpx-static -http 80 -https 443 -ssk ./etc/server.key -ssc ./etc/server.crt \
|
||||
-proxy http://$CANDIDATE:8080/
|
||||
```
|
||||
|
||||
## History
|
||||
|
||||
* v0.0.3, 2017-11-03, Support multiple proxy HTTP to HTTPS.
|
||||
|
|
24
trunk/3rdparty/signaling/Dockerfile
vendored
Normal file
24
trunk/3rdparty/signaling/Dockerfile
vendored
Normal file
|
@ -0,0 +1,24 @@
|
|||
|
||||
############################################################
|
||||
# build
|
||||
############################################################
|
||||
FROM registry.cn-hangzhou.aliyuncs.com/ossrs/srs:dev AS build
|
||||
|
||||
COPY . /tmp/signaling
|
||||
RUN cd /tmp/signaling && make
|
||||
RUN cp /tmp/signaling/objs/signaling /usr/local/bin/signaling
|
||||
RUN cp -R /tmp/signaling/www /usr/local/
|
||||
|
||||
############################################################
|
||||
# dist
|
||||
############################################################
|
||||
FROM centos:7 AS dist
|
||||
|
||||
# HTTP/1989
|
||||
EXPOSE 1989
|
||||
# SRS binary, config files and srs-console.
|
||||
COPY --from=build /usr/local/bin/signaling /usr/local/bin/
|
||||
COPY --from=build /usr/local/www /usr/local/www
|
||||
# Default workdir and command.
|
||||
WORKDIR /usr/local
|
||||
CMD ["./bin/signaling"]
|
48
trunk/3rdparty/signaling/README.md
vendored
48
trunk/3rdparty/signaling/README.md
vendored
|
@ -4,21 +4,59 @@ WebRTC signaling for https://github.com/ossrs/srs
|
|||
|
||||
## Usage
|
||||
|
||||
Build and [run SRS](https://github.com/ossrs/srs/tree/4.0release#usage):
|
||||
[Run SRS](https://github.com/ossrs/srs/tree/4.0release#usage) in docker:
|
||||
|
||||
```bash
|
||||
git clone -b 4.0release https://gitee.com/ossrs/srs.git srs &&
|
||||
cd srs/trunk && ./configure && make && ./objs/srs -c conf/rtc.conf
|
||||
docker run --rm --env CANDIDATE=$(ifconfig en0 inet| grep 'inet '|awk '{print $2}') \
|
||||
-p 1935:1935 -p 8080:8080 -p 1985:1985 -p 8000:8000/udp \
|
||||
registry.cn-hangzhou.aliyuncs.com/ossrs/srs:v4.0.95 \
|
||||
objs/srs -c conf/rtc.conf
|
||||
```
|
||||
|
||||
Build and run signaling:
|
||||
> Note: More images and version is [here](https://cr.console.aliyun.com/repository/cn-hangzhou/ossrs/srs/images).
|
||||
|
||||
Run signaling in docker:
|
||||
|
||||
```bash
|
||||
cd srs/trunk/3rdparty/signaling && make && ./objs/signaling
|
||||
docker run --rm -p 1989:1989 registry.cn-hangzhou.aliyuncs.com/ossrs/signaling:v1.0.4
|
||||
```
|
||||
|
||||
> Note: More images and version is [here](https://cr.console.aliyun.com/repository/cn-hangzhou/ossrs/signaling/images).
|
||||
|
||||
Open the H5 demos:
|
||||
|
||||
* [WebRTC: One to One over SFU(SRS)](http://localhost:1989/demos/one2one.html?autostart=true)
|
||||
|
||||
## Build from source
|
||||
|
||||
Build and [run SRS](https://github.com/ossrs/srs/tree/4.0release#usage):
|
||||
|
||||
```bash
|
||||
cd ~/git && git clone -b 4.0release https://gitee.com/ossrs/srs.git srs &&
|
||||
cd ~/git/srs/trunk && ./configure && make && ./objs/srs -c conf/rtc.conf
|
||||
```
|
||||
|
||||
Build and run signaling:
|
||||
|
||||
```bash
|
||||
cd ~/git/srs/trunk/3rdparty/signaling && make && ./objs/signaling
|
||||
```
|
||||
|
||||
Open demos by localhost: http://localhost:1989/demos
|
||||
|
||||
Build and run httpx-static for HTTPS/WSS:
|
||||
|
||||
```bash
|
||||
cd ~/git/srs/trunk/3rdparty/httpx-static && make &&
|
||||
./objs/httpx-static -http 80 -https 443 -ssk server.key -ssc server.crt \
|
||||
-proxy http://127.0.0.1:1989/sig -proxy http://127.0.0.1:1985/rtc \
|
||||
-proxy http://127.0.0.1:8080/
|
||||
```
|
||||
|
||||
Open demos by HTTPS or IP:
|
||||
|
||||
* http://localhost/demos/
|
||||
* https://localhost/demos/
|
||||
* https://192.168.3.6/demos/
|
||||
|
||||
Winlin 2021.05
|
||||
|
|
70
trunk/3rdparty/signaling/auto/release.sh
vendored
Executable file
70
trunk/3rdparty/signaling/auto/release.sh
vendored
Executable file
|
@ -0,0 +1,70 @@
|
|||
#!/bin/bash
|
||||
|
||||
SRS_GIT=$HOME/git/signaling
|
||||
SRS_TAG=
|
||||
|
||||
# linux shell color support.
|
||||
RED="\\033[31m"
|
||||
GREEN="\\033[32m"
|
||||
YELLOW="\\033[33m"
|
||||
BLACK="\\033[0m"
|
||||
|
||||
function NICE() {
|
||||
echo -e "${GREEN}$@${BLACK}"
|
||||
}
|
||||
|
||||
function TRACE() {
|
||||
echo -e "${BLACK}$@${BLACK}"
|
||||
}
|
||||
|
||||
function WARN() {
|
||||
echo -e "${YELLOW}$@${BLACK}"
|
||||
}
|
||||
|
||||
function ERROR() {
|
||||
echo -e "${RED}$@${BLACK}"
|
||||
}
|
||||
|
||||
##################################################################################
|
||||
##################################################################################
|
||||
##################################################################################
|
||||
if [[ -z $SRS_TAG ]]; then
|
||||
SRS_TAG=`(cd $SRS_GIT && git describe --tags --abbrev=0 --exclude release-* 2>/dev/null)`
|
||||
if [[ $? -ne 0 ]]; then
|
||||
echo "Invalid tag $SRS_TAG of $SRS_FILTER in $SRS_GIT"
|
||||
exit -1
|
||||
fi
|
||||
fi
|
||||
|
||||
NICE "Build docker for $SRS_GIT, tag is $SRS_TAG"
|
||||
|
||||
git ci -am "Release $SRS_TAG"
|
||||
|
||||
# For aliyun hub.
|
||||
NICE "aliyun hub release-v$SRS_TAG"
|
||||
|
||||
echo "git push aliyun"
|
||||
git push aliyun
|
||||
|
||||
git tag -d release-v$SRS_TAG 2>/dev/null
|
||||
echo "Cleanup tag $SRS_TAG for aliyun"
|
||||
|
||||
git tag release-v$SRS_TAG; git push -f aliyun release-v$SRS_TAG
|
||||
echo "Create new tag $SRS_TAG for aliyun"
|
||||
echo ""
|
||||
|
||||
NICE "aliyun hub release-vlatest"
|
||||
git tag -d release-vlatest 2>/dev/null
|
||||
echo "Cleanup tag latest for aliyun"
|
||||
|
||||
git tag release-vlatest; git push -f aliyun release-vlatest
|
||||
echo "Create new tag latest for aliyun"
|
||||
|
||||
# For github.com
|
||||
echo "git push origin"
|
||||
git push origin
|
||||
|
||||
echo "git push origin $SRS_TAG"
|
||||
git push origin $SRS_TAG
|
||||
|
||||
NICE "Update github ok"
|
43
trunk/3rdparty/signaling/main.go
vendored
43
trunk/3rdparty/signaling/main.go
vendored
|
@ -96,7 +96,7 @@ func (v *Room) Remove(p *Participant) {
|
|||
}
|
||||
}
|
||||
|
||||
func (v *Room) Notify(ctx context.Context, peer *Participant, event string) {
|
||||
func (v *Room) Notify(ctx context.Context, peer *Participant, event, param, data string) {
|
||||
var participants []*Participant
|
||||
func() {
|
||||
v.lock.RLock()
|
||||
|
@ -112,12 +112,15 @@ func (v *Room) Notify(ctx context.Context, peer *Participant, event string) {
|
|||
res := struct {
|
||||
Action string `json:"action"`
|
||||
Event string `json:"event"`
|
||||
Param string `json:"param,omitempty"`
|
||||
Data string `json:"data,omitempty"`
|
||||
Room string `json:"room"`
|
||||
Self *Participant `json:"self"`
|
||||
Peer *Participant `json:"peer"`
|
||||
Participants []*Participant `json:"participants"`
|
||||
}{
|
||||
"notify", event, v.Name, r, peer, participants,
|
||||
"notify", event, param, data,
|
||||
v.Name, r, peer, participants,
|
||||
}
|
||||
|
||||
b, err := json.Marshal(struct {
|
||||
|
@ -187,10 +190,16 @@ func main() {
|
|||
var self *Participant
|
||||
go func() {
|
||||
<-ctx.Done()
|
||||
if self != nil {
|
||||
self.Room.Remove(self)
|
||||
logger.Tf(ctx, "Remove client %v", self)
|
||||
if self == nil {
|
||||
return
|
||||
}
|
||||
|
||||
// Notify other peers that we're quiting.
|
||||
// @remark The ctx(of self) is done, so we must use a new context.
|
||||
go self.Room.Notify(context.Background(), self, "leave", "", "")
|
||||
|
||||
self.Room.Remove(self)
|
||||
logger.Tf(ctx, "Remove client %v", self)
|
||||
}()
|
||||
|
||||
inMessages := make(chan []byte, 0)
|
||||
|
@ -228,7 +237,6 @@ func main() {
|
|||
}
|
||||
|
||||
var res interface{}
|
||||
var p *Participant
|
||||
if action.Message.Action == "join" {
|
||||
obj := struct {
|
||||
Message struct {
|
||||
|
@ -241,7 +249,7 @@ func main() {
|
|||
}
|
||||
|
||||
r, _ := rooms.LoadOrStore(obj.Message.Room, &Room{Name: obj.Message.Room})
|
||||
p = &Participant{Room: r.(*Room), Display: obj.Message.Display, Out: outMessages}
|
||||
p := &Participant{Room: r.(*Room), Display: obj.Message.Display, Out: outMessages}
|
||||
if err := r.(*Room).Add(p); err != nil {
|
||||
return errors.Wrapf(err, "join")
|
||||
}
|
||||
|
@ -258,7 +266,7 @@ func main() {
|
|||
action.Message.Action, obj.Message.Room, p, r.(*Room).Participants,
|
||||
}
|
||||
|
||||
go r.(*Room).Notify(ctx, p, action.Message.Action)
|
||||
go r.(*Room).Notify(ctx, p, action.Message.Action, "", "")
|
||||
} else if action.Message.Action == "publish" {
|
||||
obj := struct {
|
||||
Message struct {
|
||||
|
@ -276,7 +284,24 @@ func main() {
|
|||
// Now, the peer is publishing.
|
||||
p.Publishing = true
|
||||
|
||||
go r.(*Room).Notify(ctx, p, action.Message.Action)
|
||||
go r.(*Room).Notify(ctx, p, action.Message.Action, "", "")
|
||||
} else if action.Message.Action == "control" {
|
||||
obj := struct {
|
||||
Message struct {
|
||||
Room string `json:"room"`
|
||||
Display string `json:"display"`
|
||||
Call string `json:"call"`
|
||||
Data string `json:"data"`
|
||||
} `json:"msg"`
|
||||
}{}
|
||||
if err := json.Unmarshal(m, &obj); err != nil {
|
||||
return errors.Wrapf(err, "Unmarshal %s", m)
|
||||
}
|
||||
|
||||
r, _ := rooms.LoadOrStore(obj.Message.Room, &Room{Name: obj.Message.Room})
|
||||
p := r.(*Room).Get(obj.Message.Display)
|
||||
|
||||
go r.(*Room).Notify(ctx, p, action.Message.Action, obj.Message.Call, obj.Message.Data)
|
||||
} else {
|
||||
return errors.Errorf("Invalid message %s", m)
|
||||
}
|
||||
|
|
16
trunk/3rdparty/signaling/www/demos/index.html
vendored
16
trunk/3rdparty/signaling/www/demos/index.html
vendored
|
@ -7,7 +7,19 @@
|
|||
<body>
|
||||
<h3><a href="https://github.com/ossrs/signaling">Signaling</a> works!</h3>
|
||||
<p>
|
||||
Run demo for <a href="one2one.html">WebRTC: One to One over SFU(SRS)</a><br/>
|
||||
点击进入<a href="one2one.html">SRS一对一通话演示</a>
|
||||
Run demo for <a class="srs_demo" href="one2one.html?autostart=true">WebRTC: One to One over SFU(SRS)</a><br/>
|
||||
点击进入<a class="srs_demo" href="one2one.html?autostart=true">SRS一对一通话演示</a>
|
||||
</p>
|
||||
<p>
|
||||
Run demo for <a class="srs_demo" href="room.html?autostart=true">WebRTC: Video Room over SFU(SRS)</a><br/>
|
||||
点击进入<a class="srs_demo" href="room.html?autostart=true">SRS多人通话演示</a>
|
||||
</p>
|
||||
<script>
|
||||
let roomName = Number(new Date().getTime() + parseInt(String(Math.random() * 10000000000))).toString(16).substr(3);
|
||||
let elems = document.getElementsByClassName('srs_demo');
|
||||
for (var i = 0; i < elems.length; i++) {
|
||||
let elem = elems.item(i);
|
||||
elem.setAttribute('href', elem.getAttribute('href') + '&room=' + roomName);
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
|
|
|
@ -57,7 +57,7 @@ function SrsRtcPublisherAsync() {
|
|||
self.pc.addTransceiver("video", {direction: "sendonly"});
|
||||
|
||||
var stream = await navigator.mediaDevices.getUserMedia(
|
||||
{audio: true, video: {height: {max: 320}}}
|
||||
{audio: true, video: {width: {max: 320}}}
|
||||
);
|
||||
// @see https://developer.mozilla.org/en-US/docs/Web/API/RTCPeerConnection/addStream#Migrating_to_addTrack
|
||||
stream.getTracks().forEach(function (track) {
|
||||
|
@ -144,7 +144,7 @@ function SrsRtcPublisherAsync() {
|
|||
|
||||
return {
|
||||
apiUrl: apiUrl, streamUrl: streamUrl, schema: schema, urlObject: urlObject, port: port,
|
||||
tid: new Date().getTime().toString(16)
|
||||
tid: Number(new Date().getTime() + parseInt(String(Math.random() * 10000000000))).toString(16)
|
||||
};
|
||||
},
|
||||
parse: function (url) {
|
||||
|
@ -361,7 +361,7 @@ function SrsRtcPlayerAsync() {
|
|||
|
||||
return {
|
||||
apiUrl: apiUrl, streamUrl: streamUrl, schema: schema, urlObject: urlObject, port: port,
|
||||
tid: new Date().getTime().toString(16)
|
||||
tid: Number(new Date().getTime() + parseInt(String(Math.random() * 10000000000))).toString(16)
|
||||
};
|
||||
},
|
||||
parse: function (url) {
|
||||
|
|
36
trunk/3rdparty/signaling/www/demos/js/srs.sig.js
vendored
36
trunk/3rdparty/signaling/www/demos/js/srs.sig.js
vendored
|
@ -59,7 +59,7 @@ function SrsRtcSignalingAsync() {
|
|||
// The message is a json object.
|
||||
self.send = async function (message) {
|
||||
return new Promise(function (resolve, reject) {
|
||||
var r = {tid: new Date().getTime().toString(16), msg: message};
|
||||
var r = {tid: Number(new Date().getTime() + parseInt(String(Math.random() * 10000000000))).toString(16), msg: message};
|
||||
self._internals.msgs[r.tid] = {resolve: resolve, reject: reject};
|
||||
self.ws.send(JSON.stringify(r));
|
||||
});
|
||||
|
@ -100,21 +100,49 @@ function SrsRtcSignalingParse(location) {
|
|||
|
||||
let wsPort = location.href.split('wsp=')[1];
|
||||
wsPort = wsPort? wsPort.split('&')[0] : location.host.split(':')[1];
|
||||
wsHost = wsPort? wsHost.split(':')[0] + ':' + wsPort : wsHost;
|
||||
|
||||
let host = location.href.split('host=')[1];
|
||||
host = host? host.split('&')[0] : location.hostname;
|
||||
|
||||
let room = location.href.split('room=')[1];
|
||||
room = room? room.split('&')[0] : null;
|
||||
|
||||
let display = location.href.split('display=')[1];
|
||||
display = display? display.split('&')[0] : new Date().getTime().toString(16).substr(3);
|
||||
display = display? display.split('&')[0] : Number(new Date().getTime() + parseInt(String(Math.random() * 10000000000))).toString(16).substr(3);
|
||||
|
||||
let autostart = location.href.split('autostart=')[1];
|
||||
autostart = autostart && autostart.split('&')[0] === 'true';
|
||||
|
||||
// Remove data in query.
|
||||
let rawQuery = query;
|
||||
if (query) {
|
||||
query = query.replace('wss=' + wsSchema, '');
|
||||
query = query.replace('wsh=' + wsHost, '');
|
||||
query = query.replace('wsp=' + wsPort, '');
|
||||
query = query.replace('host=' + host, '');
|
||||
if (room) {
|
||||
query = query.replace('room=' + room, '');
|
||||
}
|
||||
query = query.replace('display=' + display, '');
|
||||
query = query.replace('autostart=' + autostart, '');
|
||||
|
||||
while (query.indexOf('&&') >= 0) {
|
||||
query = query.replace('&&', '&');
|
||||
}
|
||||
query = query.replace('?&', '?');
|
||||
if (query.lastIndexOf('?') === query.length - 1) {
|
||||
query = query.substr(0, query.length - 1);
|
||||
}
|
||||
if (query.lastIndexOf('&') === query.length - 1) {
|
||||
query = query.substr(0, query.length - 1);
|
||||
}
|
||||
}
|
||||
|
||||
// Regenerate the host of websocket.
|
||||
wsHost = wsPort? wsHost.split(':')[0] + ':' + wsPort : wsHost;
|
||||
|
||||
return {
|
||||
query: query, wsSchema: wsSchema, wsHost: wsHost, host: host,
|
||||
query: query, rawQuery: rawQuery, wsSchema: wsSchema, wsHost: wsHost, host: host,
|
||||
room: room, display: display, autostart: autostart,
|
||||
};
|
||||
}
|
||||
|
|
166
trunk/3rdparty/signaling/www/demos/one2one.html
vendored
166
trunk/3rdparty/signaling/www/demos/one2one.html
vendored
|
@ -5,7 +5,7 @@
|
|||
<meta charset="utf-8">
|
||||
<style>
|
||||
body{
|
||||
padding-top: 55px;
|
||||
padding-top: 30px;
|
||||
}
|
||||
</style>
|
||||
<link rel="stylesheet" type="text/css" href="css/bootstrap.min.css"/>
|
||||
|
@ -15,15 +15,16 @@
|
|||
<script type="text/javascript" src="js/srs.sig.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<img src='https://ossrs.net/gif/v1/sls.gif?site=ossrs.net&path=/player/rtcpublisher'/>
|
||||
<img src='https://ossrs.net/gif/v1/sls.gif?site=ossrs.net&path=/player/one2one'/>
|
||||
<div class="navbar navbar-fixed-top">
|
||||
<div class="navbar-inner">
|
||||
<div class="container">
|
||||
<a class="brand" href="https://github.com/ossrs/srs">SRS</a>
|
||||
<div class="nav-collapse collapse">
|
||||
<ul class="nav">
|
||||
<ul class="nav srs_nav">
|
||||
<li class="active"><a href="#">一对一通话</a></li>
|
||||
<li>
|
||||
<li><a href="room.html">多人通话</a></li>
|
||||
<li class="srs_ignore">
|
||||
<a href="https://github.com/ossrs/signaling">
|
||||
<img alt="GitHub Repo stars" src="https://img.shields.io/github/stars/ossrs/signaling?style=social">
|
||||
</a>
|
||||
|
@ -45,26 +46,89 @@
|
|||
</div>
|
||||
|
||||
<div class="row">
|
||||
<div class="span5">
|
||||
<div class="span4 hide" id="publisher">
|
||||
<label></label>
|
||||
<video id="rtc_media_publisher" width="320" autoplay muted controls></video>
|
||||
<video id="rtc_media_publisher" width="310" autoplay muted controls></video>
|
||||
|
||||
<label></label>
|
||||
<span id='self'></span>
|
||||
</div>
|
||||
<div class="span6">
|
||||
<div class="span6 hide" id="player">
|
||||
<label></label>
|
||||
<video id="rtc_media_player" width="320" autoplay muted controls></video>
|
||||
<video id="rtc_media_player" width="310" autoplay muted controls></video>
|
||||
|
||||
<label></label>
|
||||
<span id='peer'></span>
|
||||
<a href="javascript:control_refresh_peer()">Refresh</a>
|
||||
<input type="text" id="txt_alert" class="input-medium" value="">
|
||||
<a href="javascript:control_alert_peer()">Alert</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<label></label>
|
||||
|
||||
<div class="accordion hide srs_merge">
|
||||
<div class="accordion-group">
|
||||
<div class="accordion-heading">
|
||||
<a href="javascript:void(0)" class="accordion-toggle">FFmpeg合流转直播</a>
|
||||
</div>
|
||||
<div class="accordion-body collapse in">
|
||||
<div class="accordion-inner" style="overflow:auto">
|
||||
ffmpeg -f flv -i rtmp://<span class="ff_host"></span>/<span class="ff_app"></span>/<span class="ff_first"></span> -f flv -i rtmp://<span class="ff_host"></span>/<span class="ff_app"></span>/<span class="ff_second"></span> \ <br/>
|
||||
-filter_complex "[1:v]scale=w=96:h=72[ckout];[0:v][ckout]overlay=x=W-w-10:y=H-h-10[out]" -map "[out]" \ <br/>
|
||||
-c:v libx264 -profile:v high -preset medium \ <br/>
|
||||
-filter_complex amix -c:a aac \ <br/>
|
||||
-f flv -y
|
||||
<span id="ff_output">
|
||||
rtmp://<span class="ff_host"></span>/<span class="ff_app"></span>/merge
|
||||
</span>
|
||||
<span id="ff_wxvideo"></span>
|
||||
&& <br/>
|
||||
echo "ok"
|
||||
</div>
|
||||
<div class="accordion-inner">
|
||||
<a href="#" id="ff_preview" target="_blank" class="accordion-toggle">
|
||||
预览:rtmp://<span class="ff_host"></span>/<span class="ff_app"></span>/merge
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<label></label>
|
||||
|
||||
<div class="accordion hide srs_merge">
|
||||
<div class="accordion-group">
|
||||
<div class="accordion-heading">
|
||||
<a href="javascript:void(0)" class="accordion-toggle">
|
||||
视频号推流信息
|
||||
</a>
|
||||
</div>
|
||||
<div class="accordion-body collapse in">
|
||||
<div class="accordion-inner">
|
||||
推流地址 <input type="text" id="txt_wx_video_tcurl" class="input-xxlarge">
|
||||
</div>
|
||||
<div class="accordion-inner">
|
||||
推流密钥 <input type="text" id="txt_wx_video_stream" class="input-xxlarge">
|
||||
</div>
|
||||
<div class="accordion-inner">
|
||||
<button class="btn btn-primary" id="btn_apply">应用</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<footer class="footer">
|
||||
<div class="container">
|
||||
<p>© SRS 2020</p>
|
||||
</div>
|
||||
</footer>
|
||||
<script type="text/javascript">
|
||||
var sig = null;
|
||||
var publisher = null;
|
||||
var player = null;
|
||||
var control_refresh_peer = null;
|
||||
var control_alert_peer = null;
|
||||
$(function(){
|
||||
console.log('?wss=x to specify the websocket schema, ws or wss');
|
||||
console.log('?wsh=x to specify the websocket server ip');
|
||||
|
@ -85,13 +149,44 @@
|
|||
sig = new SrsRtcSignalingAsync();
|
||||
sig.onmessage = function (msg) {
|
||||
console.log('Notify: ', msg);
|
||||
msg.participants.forEach(function (participant) {
|
||||
if (participant.display === display || !participant.publishing) return;
|
||||
startPlay(host, room, participant.display);
|
||||
});
|
||||
|
||||
if (msg.event === 'leave') {
|
||||
$('#player').hide();
|
||||
}
|
||||
|
||||
if (msg.event === 'publish') {
|
||||
if (msg.peer && msg.peer.publishing && msg.peer.display !== display) {
|
||||
startPlay(host, room, msg.peer.display);
|
||||
}
|
||||
}
|
||||
|
||||
if (msg.event === 'control') {
|
||||
if (msg.param === 'refresh') {
|
||||
setTimeout(function () {
|
||||
window.location.reload();
|
||||
}, 500);
|
||||
} else if (msg.param === 'alert') {
|
||||
alert('From ' + msg.peer.display + ': ' + msg.data);
|
||||
}
|
||||
}
|
||||
|
||||
if (msg.participants.length >= 2) {
|
||||
$('.srs_merge').show();
|
||||
} else {
|
||||
$('.srs_merge').hide();
|
||||
}
|
||||
};
|
||||
await sig.connect(conf.wsSchema, conf.wsHost, room, display);
|
||||
|
||||
control_refresh_peer = async function () {
|
||||
let r1 = await sig.send({action:'control', room:room, display:display, call:'refresh'});
|
||||
console.log('Signaling: control peer to refresh ok', r1);
|
||||
};
|
||||
control_alert_peer = async function () {
|
||||
let r1 = await sig.send({action:'control', room:room, display:display, call:'alert', data:$('#txt_alert').val()});
|
||||
console.log('Signaling: control peer to alert ok', r1);
|
||||
};
|
||||
|
||||
let r0 = await sig.send({action:'join', room:room, display:display});
|
||||
console.log('Signaling: join ok', r0);
|
||||
|
||||
|
@ -112,11 +207,20 @@
|
|||
if (participant.display === display || !participant.publishing) return;
|
||||
startPlay(host, room, participant.display);
|
||||
});
|
||||
|
||||
if (r0.participants.length >= 2) {
|
||||
$('.srs_merge').show();
|
||||
}
|
||||
};
|
||||
|
||||
var startPublish = function (host, room, display) {
|
||||
$(".ff_first").each(function(i,e) {
|
||||
$(e).text(display);
|
||||
});
|
||||
|
||||
var url = 'webrtc://' + host + '/' + room + '/' + display + conf.query;
|
||||
$('#rtc_media_publisher').show();
|
||||
$('#publisher').show();
|
||||
|
||||
if (publisher) {
|
||||
publisher.close();
|
||||
|
@ -128,7 +232,7 @@
|
|||
};
|
||||
|
||||
return publisher.publish(url).then(function(session){
|
||||
$('#self').text('Self: ' + display);
|
||||
$('#self').text('Self: ' + url);
|
||||
}).catch(function (reason) {
|
||||
publisher.close();
|
||||
$('#rtc_media_publisher').hide();
|
||||
|
@ -137,8 +241,13 @@
|
|||
};
|
||||
|
||||
var startPlay = function (host, room, display) {
|
||||
$(".ff_second").each(function(i,e) {
|
||||
$(e).text(display);
|
||||
});
|
||||
|
||||
var url = 'webrtc://' + host + '/' + room + '/' + display + conf.query;
|
||||
$('#rtc_media_player').show();
|
||||
$('#player').show();
|
||||
|
||||
if (player) {
|
||||
player.close();
|
||||
|
@ -160,15 +269,38 @@
|
|||
});
|
||||
};
|
||||
|
||||
$('#rtc_media_publisher').hide();
|
||||
$('#rtc_media_player').hide();
|
||||
$("#btn_start").click(startDemo);
|
||||
|
||||
// Pass-by to SRS url.
|
||||
let conf = SrsRtcSignalingParse(window.location);
|
||||
$('#txt_host').val(conf.host);
|
||||
conf.room && $('#txt_room').val(conf.room);
|
||||
$('#txt_display').val(conf.display);
|
||||
|
||||
$(".ff_host").each(function(i,e) {
|
||||
$(e).text(conf.host);
|
||||
});
|
||||
$(".ff_app").each(function(i,e) {
|
||||
$(e).text($('#txt_room').val());
|
||||
});
|
||||
$('#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.
|
||||
$('ul.srs_nav').children('li').not('.srs_ignore').children('a').not("[href='#']").each(function (i, e) {
|
||||
$(e).attr('href', $(e).attr('href') + conf.rawQuery);
|
||||
});
|
||||
|
||||
$('#btn_apply').click(function () {
|
||||
if ($('#txt_wx_video_tcurl').val() !== '' && $('#txt_wx_video_stream').val() !== '') {
|
||||
$('#ff_wxvideo').text('"' + $('#txt_wx_video_tcurl').val() + $('#txt_wx_video_stream').val() + '"').show();
|
||||
$('#ff_output').hide();
|
||||
$('#ff_preview').parent().hide();
|
||||
} else {
|
||||
$('#ff_wxvideo').hide();
|
||||
$('#ff_output').show();
|
||||
$('#ff_preview').parent().show();
|
||||
}
|
||||
});
|
||||
|
||||
$("#btn_start").click(startDemo);
|
||||
if (conf.autostart) {
|
||||
startDemo();
|
||||
}
|
||||
|
|
212
trunk/3rdparty/signaling/www/demos/room.html
vendored
Normal file
212
trunk/3rdparty/signaling/www/demos/room.html
vendored
Normal file
|
@ -0,0 +1,212 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>SRS</title>
|
||||
<meta charset="utf-8">
|
||||
<style>
|
||||
body{
|
||||
padding-top: 30px;
|
||||
}
|
||||
</style>
|
||||
<link rel="stylesheet" type="text/css" href="css/bootstrap.min.css"/>
|
||||
<script type="text/javascript" src="js/jquery-1.10.2.min.js"></script>
|
||||
<script type="text/javascript" src="js/adapter-7.4.0.min.js"></script>
|
||||
<script type="text/javascript" src="js/srs.sdk.js"></script>
|
||||
<script type="text/javascript" src="js/srs.sig.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<img src='https://ossrs.net/gif/v1/sls.gif?site=ossrs.net&path=/player/room'/>
|
||||
<div class="navbar navbar-fixed-top">
|
||||
<div class="navbar-inner">
|
||||
<div class="container">
|
||||
<a class="brand" href="https://github.com/ossrs/srs">SRS</a>
|
||||
<div class="nav-collapse collapse">
|
||||
<ul class="nav srs_nav">
|
||||
<li><a href="one2one.html">一对一通话</a></li>
|
||||
<li class="active"><a href="#">多人通话</a></li>
|
||||
<li class="srs_ignore">
|
||||
<a href="https://github.com/ossrs/signaling">
|
||||
<img alt="GitHub Repo stars" src="https://img.shields.io/github/stars/ossrs/signaling?style=social">
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="container">
|
||||
<div class="form-inline">
|
||||
SRS:
|
||||
<input type="text" id="txt_host" class="input-medium" value="">
|
||||
Room:
|
||||
<input type="text" id="txt_room" class="input-small" value="live">
|
||||
Display:
|
||||
<input type="text" id="txt_display" class="input-small" value="">
|
||||
<button class="btn btn-primary" id="btn_start">加入房间</button>
|
||||
</div>
|
||||
|
||||
<div class="row srs_players">
|
||||
<div class="span4 hide" id="publisher">
|
||||
<label></label>
|
||||
<video id="rtc_media_publisher" width="310" autoplay muted controls></video>
|
||||
|
||||
<label></label>
|
||||
<span id='self'></span>
|
||||
</div>
|
||||
<div class="span4 hide" id="player">
|
||||
<label></label>
|
||||
<video id="rtc_media_player" width="310" autoplay muted controls></video>
|
||||
|
||||
<label></label>
|
||||
<span id='peer'></span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<script type="text/javascript">
|
||||
var sig = null;
|
||||
var publisher = null;
|
||||
var players = {}; // Key is display, value is a player object.
|
||||
$(function(){
|
||||
console.log('?wss=x to specify the websocket schema, ws or wss');
|
||||
console.log('?wsh=x to specify the websocket server ip');
|
||||
console.log('?wsp=x to specify the websocket server port');
|
||||
console.log('?host=x to specify the SRS server');
|
||||
console.log('?room=x to specify the room to join');
|
||||
console.log('?display=x to specify your nick name');
|
||||
|
||||
var startDemo = async function () {
|
||||
var host = $('#txt_host').val();
|
||||
var room = $('#txt_room').val();
|
||||
var display = $('#txt_display').val();
|
||||
|
||||
// Connect to signaling first.
|
||||
if (sig) {
|
||||
sig.close();
|
||||
}
|
||||
sig = new SrsRtcSignalingAsync();
|
||||
sig.onmessage = function (msg) {
|
||||
console.log('Notify: ', msg);
|
||||
|
||||
// Subscribe if new user start to publish.
|
||||
if (msg.event === 'publish') {
|
||||
if (msg.peer && msg.peer.publishing && msg.peer.display !== display) {
|
||||
startPlay(host, room, msg.peer.display);
|
||||
}
|
||||
}
|
||||
|
||||
// Remove dead players.
|
||||
if (msg.event === 'join' || msg.event === 'leave') {
|
||||
$.each(players, function(k, obj) {
|
||||
let stillAlive = false;
|
||||
msg.participants.forEach(function (participant) {
|
||||
if (participant.display === k) stillAlive = true;
|
||||
});
|
||||
|
||||
if (!stillAlive) {
|
||||
obj.player.close();
|
||||
obj.ui.remove();
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
await sig.connect(conf.wsSchema, conf.wsHost, room, display);
|
||||
|
||||
let r0 = await sig.send({action:'join', room:room, display:display});
|
||||
console.log('Signaling: join ok', r0);
|
||||
|
||||
// Start publish media if signaling is ok.
|
||||
await startPublish(host, room, display);
|
||||
let r1 = await sig.send({action:'publish', room:room, display:display});
|
||||
console.log('Signaling: publish ok', r1);
|
||||
|
||||
// Play the stream already in room.
|
||||
r0.participants.forEach(function(participant) {
|
||||
if (participant.display === display || !participant.publishing) return;
|
||||
startPlay(host, room, participant.display);
|
||||
});
|
||||
};
|
||||
|
||||
var startPublish = function (host, room, display) {
|
||||
$(".ff_first").each(function(i,e) {
|
||||
$(e).text(display);
|
||||
});
|
||||
|
||||
var url = 'webrtc://' + host + '/' + room + '/' + display + conf.query;
|
||||
$('#rtc_media_publisher').show();
|
||||
$('#publisher').show();
|
||||
|
||||
if (publisher) {
|
||||
publisher.close();
|
||||
}
|
||||
publisher = new SrsRtcPublisherAsync();
|
||||
publisher.onaddstream = function (event) {
|
||||
console.log('Start publish, event: ', event);
|
||||
$('#rtc_media_publisher').prop('srcObject', event.stream);
|
||||
};
|
||||
|
||||
return publisher.publish(url).then(function(session){
|
||||
$('#self').text('Self: ' + url);
|
||||
}).catch(function (reason) {
|
||||
publisher.close();
|
||||
$('#rtc_media_publisher').hide();
|
||||
console.error(reason);
|
||||
});
|
||||
};
|
||||
|
||||
var startPlay = function (host, room, display) {
|
||||
$(".ff_second").each(function(i,e) {
|
||||
$(e).text(display);
|
||||
});
|
||||
|
||||
// Remove exists.
|
||||
if (players[display]) {
|
||||
players[display].ui.remove();
|
||||
players[display].player.close();
|
||||
}
|
||||
|
||||
// Clone a player from template.
|
||||
let ui = $('#player').clone().attr('id', 'player-' + display);
|
||||
let video = ui.children('#rtc_media_player');
|
||||
console.log(video.length);
|
||||
let player = new SrsRtcPlayerAsync();
|
||||
|
||||
players[display] = {ui:ui, video:video, player:player};
|
||||
$('.srs_players').append(ui);
|
||||
|
||||
// Start play for this user.
|
||||
var url = 'webrtc://' + host + '/' + room + '/' + display + conf.query;
|
||||
video.show();
|
||||
ui.show();
|
||||
|
||||
player.onaddstream = function (event) {
|
||||
console.log('Start play, event: ', event);
|
||||
video.prop('srcObject', event.stream);
|
||||
};
|
||||
|
||||
player.play(url).then(function(session){
|
||||
ui.children('#peer').text('Peer: ' + url);
|
||||
video.prop('muted', false);
|
||||
}).catch(function (reason) {
|
||||
player.close();
|
||||
video.hide();
|
||||
console.error(reason);
|
||||
});
|
||||
};
|
||||
|
||||
// Pass-by to SRS url.
|
||||
let conf = SrsRtcSignalingParse(window.location);
|
||||
$('#txt_host').val(conf.host);
|
||||
conf.room && $('#txt_room').val(conf.room);
|
||||
$('#txt_display').val(conf.display);
|
||||
|
||||
// Update href for all navs.
|
||||
$('ul.srs_nav').children('li').not('.srs_ignore').children('a').not("[href='#']").each(function (i, e) {
|
||||
$(e).attr('href', $(e).attr('href') + conf.rawQuery);
|
||||
});
|
||||
|
||||
$("#btn_start").click(startDemo);
|
||||
if (conf.autostart) {
|
||||
startDemo();
|
||||
}
|
||||
});
|
||||
</script>
|
2
trunk/3rdparty/srs-bench/auto/sync_vnet.sh
vendored
2
trunk/3rdparty/srs-bench/auto/sync_vnet.sh
vendored
|
@ -27,7 +27,7 @@ go test -race ./...
|
|||
if [[ $? -ne 0 ]]; then echo "fail"; exit -1; fi
|
||||
|
||||
echo "golangci-lint run --skip-files conn_map_test.go,router_test.go" &&
|
||||
golangci-lint run --skip-files conn_map_test.go,a_test.go
|
||||
golangci-lint run --skip-files conn_map_test.go,router_test.go
|
||||
if [[ $? -ne 0 ]]; then echo "fail"; exit -1; fi
|
||||
|
||||
echo "OK"
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
package vnet
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net"
|
||||
)
|
||||
|
||||
|
@ -22,7 +23,7 @@ func (v *UDPProxy) Deliver(sourceAddr, destAddr net.Addr, b []byte) (nn int, err
|
|||
func (v *aUDPProxyWorker) Deliver(sourceAddr, destAddr net.Addr, b []byte) (nn int, err error) {
|
||||
addr, ok := sourceAddr.(*net.UDPAddr)
|
||||
if !ok {
|
||||
return 0, nil
|
||||
return 0, fmt.Errorf("invalid addr %v", sourceAddr) // nolint:goerr113
|
||||
}
|
||||
|
||||
// nolint:godox // TODO: Support deliver packet from real server to vnet.
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
// +build !wasm
|
||||
|
||||
package vnet
|
||||
|
||||
import (
|
||||
|
@ -17,7 +19,7 @@ import (
|
|||
// which proxy to real server:
|
||||
// 192.168.1.10:8000
|
||||
// We should get a reply if directly deliver to proxy.
|
||||
func TestUDPProxyDirectDeliver(t *testing.T) {
|
||||
func TestUDPProxyDirectDeliverTypical(t *testing.T) {
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
|
||||
var r0, r1, r2 error
|
||||
|
@ -164,3 +166,170 @@ func TestUDPProxyDirectDeliver(t *testing.T) {
|
|||
}
|
||||
}()
|
||||
}
|
||||
|
||||
// Error if deliver to invalid address.
|
||||
func TestUDPProxyDirectDeliverBadcase(t *testing.T) {
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
|
||||
var r0, r1, r2 error
|
||||
defer func() {
|
||||
if r0 != nil || r1 != nil || r2 != nil {
|
||||
t.Errorf("fail for ctx=%v, r0=%v, r1=%v, r2=%v", ctx.Err(), r0, r1, r2)
|
||||
}
|
||||
}()
|
||||
|
||||
var wg sync.WaitGroup
|
||||
defer wg.Wait()
|
||||
|
||||
// Timeout, fail
|
||||
wg.Add(1)
|
||||
go func() {
|
||||
defer wg.Done()
|
||||
defer cancel()
|
||||
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
case <-time.After(time.Duration(*testTimeout) * time.Millisecond):
|
||||
r2 = fmt.Errorf("timeout") // nolint:goerr113
|
||||
}
|
||||
}()
|
||||
|
||||
// For utest, we always proxy vnet packets to the random port we listen to.
|
||||
mockServer := NewMockUDPEchoServer()
|
||||
wg.Add(1)
|
||||
go func() {
|
||||
defer wg.Done()
|
||||
defer cancel()
|
||||
if err := mockServer.doMockUDPServer(ctx); err != nil {
|
||||
r0 = err
|
||||
}
|
||||
}()
|
||||
|
||||
// Create a vent and proxy.
|
||||
wg.Add(1)
|
||||
go func() {
|
||||
defer wg.Done()
|
||||
defer cancel()
|
||||
|
||||
// When real server is ready, start the vnet test.
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
return
|
||||
case <-mockServer.realServerReady.Done():
|
||||
}
|
||||
|
||||
doVnetProxy := func() error {
|
||||
router, err := NewRouter(&RouterConfig{
|
||||
CIDR: "0.0.0.0/0",
|
||||
LoggerFactory: logging.NewDefaultLoggerFactory(),
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
clientNetwork := NewNet(&NetConfig{
|
||||
StaticIP: "10.0.0.11",
|
||||
})
|
||||
if err = router.AddNet(clientNetwork); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err = router.Start(); err != nil {
|
||||
return err
|
||||
}
|
||||
defer router.Stop() // nolint:errcheck
|
||||
|
||||
proxy, err := NewProxy(router)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer proxy.Close() // nolint:errcheck
|
||||
|
||||
// For utest, mock the target real server.
|
||||
proxy.mockRealServerAddr = mockServer.realServerAddr
|
||||
|
||||
// The real server address to proxy to.
|
||||
// Note that for utest, we will proxy to a local address.
|
||||
serverAddr, err := net.ResolveUDPAddr("udp4", "192.168.1.10:8000")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err = proxy.Proxy(clientNetwork, serverAddr); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Now, all packets from client, will be proxy to real server, vice versa.
|
||||
client, err := clientNetwork.ListenPacket("udp4", "10.0.0.11:5787")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// When system quit, interrupt client.
|
||||
selfKill, selfKillCancel := context.WithCancel(context.Background())
|
||||
go func() {
|
||||
<-ctx.Done()
|
||||
selfKillCancel()
|
||||
_ = client.Close()
|
||||
}()
|
||||
|
||||
// Write by vnet client.
|
||||
if _, err = client.WriteTo([]byte("Hello"), serverAddr); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
buf := make([]byte, 1500)
|
||||
if n, addr, err := client.ReadFrom(buf); err != nil { // nolint:gocritic,govet
|
||||
if errors.Is(selfKill.Err(), context.Canceled) {
|
||||
return nil
|
||||
}
|
||||
return err
|
||||
} else if n != 5 || addr == nil {
|
||||
return fmt.Errorf("n=%v, addr=%v", n, addr) // nolint:goerr113
|
||||
} else if string(buf[:n]) != "Hello" { // nolint:goconst
|
||||
return fmt.Errorf("data %v", buf[:n]) // nolint:goerr113
|
||||
}
|
||||
|
||||
// BadCase: Invalid address, error and ignore.
|
||||
tcpAddr, err := net.ResolveTCPAddr("tcp4", "192.168.1.10:8000")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if _, err = proxy.Deliver(tcpAddr, serverAddr, []byte("Hello")); err == nil {
|
||||
return fmt.Errorf("should err") // nolint:goerr113
|
||||
}
|
||||
|
||||
// BadCase: Invalid target address, ignore.
|
||||
udpAddr, err := net.ResolveUDPAddr("udp4", "10.0.0.12:5788")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if nn, err := proxy.Deliver(udpAddr, serverAddr, []byte("Hello")); err != nil { // nolint:govet
|
||||
return err
|
||||
} else if nn != 0 {
|
||||
return fmt.Errorf("invalid %v", nn) // nolint:goerr113
|
||||
}
|
||||
|
||||
// BadCase: Write on closed socket, error and ignore.
|
||||
proxy.workers.Range(func(key, value interface{}) bool {
|
||||
value.(*aUDPProxyWorker).endpoints.Range(func(key, value interface{}) bool {
|
||||
_ = value.(*net.UDPConn).Close()
|
||||
return true
|
||||
})
|
||||
return true
|
||||
})
|
||||
|
||||
if _, err = proxy.Deliver(client.LocalAddr(), serverAddr, []byte("Hello")); err == nil {
|
||||
return fmt.Errorf("should error") // nolint:goerr113
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
if err := doVnetProxy(); err != nil {
|
||||
r1 = err
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
|
5
trunk/configure
vendored
5
trunk/configure
vendored
|
@ -583,8 +583,9 @@ install:
|
|||
@cp -f research/api-server/static-dir/index.html \$(__REAL_INSTALL)/objs/nginx/html
|
||||
@cp -f research/api-server/static-dir/crossdomain.xml \$(__REAL_INSTALL)/objs/nginx/html
|
||||
@cp -f research/api-server/static-dir/favicon.ico \$(__REAL_INSTALL)/objs/nginx/html
|
||||
@cp -Rf research/players \$(__REAL_INSTALL)/objs/nginx/html
|
||||
@cp -Rf research/console \$(__REAL_INSTALL)/objs/nginx/html
|
||||
@cp -Rf research/players \$(__REAL_INSTALL)/objs/nginx/html/
|
||||
@cp -Rf research/console \$(__REAL_INSTALL)/objs/nginx/html/
|
||||
@cp -Rf 3rdparty/signaling/www/demos \$(__REAL_INSTALL)/objs/nginx/html/
|
||||
@echo "Now copy binary files"
|
||||
@mkdir -p \$(__REAL_INSTALL)/objs
|
||||
@cp -f objs/srs \$(__REAL_INSTALL)/objs
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
<link rel="stylesheet" type="text/css" href="js/srs.console.css"/>
|
||||
<style>
|
||||
body {
|
||||
padding-top: 50px;
|
||||
padding-top: 30px;
|
||||
}
|
||||
</style>
|
||||
<script type="text/javascript" src="js/3rdparty/angular.min.js"></script>
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
<link rel="stylesheet" type="text/css" href="js/srs.console.css"/>
|
||||
<style>
|
||||
body {
|
||||
padding-top: 50px;
|
||||
padding-top: 30px;
|
||||
}
|
||||
</style>
|
||||
<script type="text/javascript" src="js/3rdparty/angular.min.js"></script>
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
<link rel="stylesheet" type="text/css" href="css/bootstrap.min.css"/>
|
||||
<style>
|
||||
body{
|
||||
padding-top: 55px;
|
||||
padding-top: 30px;
|
||||
}
|
||||
</style>
|
||||
<script type="text/javascript" src="js/jquery-1.10.2.min.js"></script>
|
||||
|
|
|
@ -57,7 +57,7 @@ function SrsRtcPublisherAsync() {
|
|||
self.pc.addTransceiver("video", {direction: "sendonly"});
|
||||
|
||||
var stream = await navigator.mediaDevices.getUserMedia(
|
||||
{audio: true, video: {height: {max: 320}}}
|
||||
{audio: true, video: {width: {max: 320}}}
|
||||
);
|
||||
// @see https://developer.mozilla.org/en-US/docs/Web/API/RTCPeerConnection/addStream#Migrating_to_addTrack
|
||||
stream.getTracks().forEach(function (track) {
|
||||
|
@ -69,7 +69,8 @@ function SrsRtcPublisherAsync() {
|
|||
var session = await new Promise(function (resolve, reject) {
|
||||
// @see https://github.com/rtcdn/rtcdn-draft
|
||||
var data = {
|
||||
api: conf.apiUrl, streamurl: conf.streamUrl, clientip: null, sdp: offer.sdp
|
||||
api: conf.apiUrl, tid: conf.tid, streamurl: conf.streamUrl,
|
||||
clientip: null, sdp: offer.sdp
|
||||
};
|
||||
console.log("Generated offer: ", data);
|
||||
|
||||
|
@ -101,7 +102,7 @@ function SrsRtcPublisherAsync() {
|
|||
|
||||
// Close the publisher.
|
||||
self.close = function () {
|
||||
self.pc.close();
|
||||
self.pc && self.pc.close();
|
||||
self.pc = null;
|
||||
};
|
||||
|
||||
|
@ -141,7 +142,10 @@ function SrsRtcPublisherAsync() {
|
|||
|
||||
var streamUrl = urlObject.url;
|
||||
|
||||
return {apiUrl: apiUrl, streamUrl: streamUrl, schema: schema, urlObject: urlObject, port: port};
|
||||
return {
|
||||
apiUrl: apiUrl, streamUrl: streamUrl, schema: schema, urlObject: urlObject, port: port,
|
||||
tid: new Date().getTime().toString(16)
|
||||
};
|
||||
},
|
||||
parse: function (url) {
|
||||
// @see: http://stackoverflow.com/questions/10469575/how-to-use-location-object-to-parse-url-without-redirecting-the-page-in-javascri
|
||||
|
@ -289,7 +293,8 @@ function SrsRtcPlayerAsync() {
|
|||
var session = await new Promise(function(resolve, reject) {
|
||||
// @see https://github.com/rtcdn/rtcdn-draft
|
||||
var data = {
|
||||
api: conf.apiUrl, streamurl: conf.streamUrl, clientip: null, sdp: offer.sdp
|
||||
api: conf.apiUrl, tid: conf.tid, streamurl: conf.streamUrl,
|
||||
clientip: null, sdp: offer.sdp
|
||||
};
|
||||
console.log("Generated offer: ", data);
|
||||
|
||||
|
@ -315,7 +320,7 @@ function SrsRtcPlayerAsync() {
|
|||
|
||||
// Close the player.
|
||||
self.close = function() {
|
||||
self.pc.close();
|
||||
self.pc && self.pc.close();
|
||||
self.pc = null;
|
||||
};
|
||||
|
||||
|
@ -354,7 +359,10 @@ function SrsRtcPlayerAsync() {
|
|||
|
||||
var streamUrl = urlObject.url;
|
||||
|
||||
return {apiUrl: apiUrl, streamUrl: streamUrl, schema: schema, urlObject: urlObject, port: port};
|
||||
return {
|
||||
apiUrl: apiUrl, streamUrl: streamUrl, schema: schema, urlObject: urlObject, port: port,
|
||||
tid: new Date().getTime().toString(16)
|
||||
};
|
||||
},
|
||||
parse: function (url) {
|
||||
// @see: http://stackoverflow.com/questions/10469575/how-to-use-location-object-to-parse-url-without-redirecting-the-page-in-javascri
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
<meta charset="utf-8">
|
||||
<style>
|
||||
body{
|
||||
padding-top: 55px;
|
||||
padding-top: 30px;
|
||||
}
|
||||
</style>
|
||||
<link rel="stylesheet" type="text/css" href="css/bootstrap.min.css"/>
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
<meta charset="utf-8">
|
||||
<style>
|
||||
body{
|
||||
padding-top: 55px;
|
||||
padding-top: 30px;
|
||||
}
|
||||
</style>
|
||||
<link rel="stylesheet" type="text/css" href="css/bootstrap.min.css"/>
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
<link rel="stylesheet" type="text/css" href="css/bootstrap.min.css"/>
|
||||
<style>
|
||||
body{
|
||||
padding-top: 55px;
|
||||
padding-top: 30px;
|
||||
}
|
||||
#main_modal {
|
||||
width: 700px;
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
<link rel="stylesheet" type="text/css" href="css/bootstrap.min.css"/>
|
||||
<style>
|
||||
body{
|
||||
padding-top: 55px;
|
||||
padding-top: 30px;
|
||||
}
|
||||
.accordion-group {
|
||||
width: 310px;
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
<link rel="stylesheet" type="text/css" href="css/bootstrap.min.css"/>
|
||||
<style>
|
||||
body{
|
||||
padding-top: 55px;
|
||||
padding-top: 30px;
|
||||
}
|
||||
#my_modal_footer {
|
||||
margin-top: -20px;
|
||||
|
|
|
@ -6,21 +6,7 @@
|
|||
<link rel="stylesheet" type="text/css" href="css/bootstrap.min.css"/>
|
||||
<style>
|
||||
body{
|
||||
padding-top: 55px;
|
||||
}
|
||||
#my_modal_footer {
|
||||
margin-top: -20px;
|
||||
padding-top: 3px;
|
||||
}
|
||||
#main_modal {
|
||||
margin-top: -60px;
|
||||
}
|
||||
.div_play_time {
|
||||
margin-top: 10px;
|
||||
}
|
||||
#pb_buffer_bg {
|
||||
margin-top: -4px;
|
||||
margin-bottom: 10px;
|
||||
padding-top: 30px;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
<link rel="stylesheet" type="text/css" href="css/bootstrap.min.css"/>
|
||||
<style>
|
||||
body{
|
||||
padding-top: 55px;
|
||||
padding-top: 30px;
|
||||
}
|
||||
#my_modal_footer {
|
||||
margin-top: -20px;
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
<link rel="stylesheet" type="text/css" href="css/bootstrap.min.css"/>
|
||||
<style>
|
||||
body{
|
||||
padding-top: 55px;
|
||||
padding-top: 30px;
|
||||
}
|
||||
.accordion-group {
|
||||
width: 310px;
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
<link rel="stylesheet" type="text/css" href="css/bootstrap.min.css"/>
|
||||
<style>
|
||||
body{
|
||||
padding-top: 55px;
|
||||
padding-top: 30px;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
|
@ -335,7 +335,7 @@
|
|||
$("#btn_publish").click(on_user_publish);
|
||||
|
||||
// for publish, we use randome stream name.
|
||||
$("#txt_url").val($("#txt_url").val() + "." + new Date().getTime());
|
||||
$("#txt_url").val($("#txt_url").val() + "." + Number(new Date().getTime() + parseInt(String(Math.random() * 10000000000))).toString(16));
|
||||
|
||||
// start the publisher.
|
||||
srs_publisher = new SrsPublisher("local_publisher", 430, 185);
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
<link rel="stylesheet" type="text/css" href="css/bootstrap.min.css"/>
|
||||
<style>
|
||||
body{
|
||||
padding-top: 55px;
|
||||
padding-top: 30px;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
#!/bin/bash
|
||||
|
||||
for file in $(git remote); do echo ""; git push $file; done
|
||||
for file in $(git remote); do echo ""; git push $file $@; done
|
||||
|
||||
|
|
|
@ -59,8 +59,6 @@ if [ $help = yes ]; then
|
|||
--pi for pi platform, configure/make/package.
|
||||
--x86-64 alias for --x86-x64.
|
||||
--jobs Set the configure and make jobs.
|
||||
|
||||
--console The path for https://github.com/ossrs/srs-console
|
||||
END
|
||||
exit 0
|
||||
fi
|
||||
|
|
|
@ -1012,6 +1012,10 @@ srs_error_t SrsRtcPublishStream::initialize(SrsRequest* r, SrsRtcStreamDescripti
|
|||
return srs_error_new(ERROR_SYSTEM_STREAM_BUSY, "rtmp stream %s busy", r->get_stream_url().c_str());
|
||||
}
|
||||
|
||||
// Disable GOP cache for RTC2RTMP bridger, to keep the streams in sync,
|
||||
// especially for stream merging.
|
||||
rtmp->set_cache(false);
|
||||
|
||||
SrsRtmpFromRtcBridger *bridger = new SrsRtmpFromRtcBridger(rtmp);
|
||||
if ((err = bridger->initialize(r)) != srs_success) {
|
||||
srs_freep(bridger);
|
||||
|
|
|
@ -26,6 +26,6 @@
|
|||
|
||||
#define VERSION_MAJOR 4
|
||||
#define VERSION_MINOR 0
|
||||
#define VERSION_REVISION 96
|
||||
#define VERSION_REVISION 98
|
||||
|
||||
#endif
|
||||
|
|
Loading…
Reference in a new issue