Browse Source

Merge remote-tracking branch 'origin/v4' into v4

# Conflicts:
#	README.md
v4
fajiao 2 years ago
parent
commit
a70c75c888
  1. 6
      README.md
  2. 4
      batcher.go
  3. 4
      go.mod
  4. 9
      go.sum
  5. 23
      main.go
  6. 55
      publish.html
  7. 4
      publisher.go

6
README.md

@ -34,7 +34,6 @@ webrtc:
## API
### 播放地址
`/webrtc/play/[streamPath]`
Body: `SDP`
@ -53,8 +52,11 @@ Content-Type: `application/sdp`
Response Body: `SDP`
## WHIP
### 推流测试页面
`/webrtc/test/publish`
## WHIP
WebRTC-HTTP ingestion protocol
用于WebRTC交换SDP信息的规范

4
batcher.go

@ -80,7 +80,7 @@ func (suber *WebRTCBatcher) Start() (err error) {
}
} else {
go func() {
ticker := time.NewTicker(time.Millisecond * webrtcConfig.PLI)
ticker := time.NewTicker(webrtcConfig.PLI)
for {
select {
case <-ticker.C:
@ -92,7 +92,7 @@ func (suber *WebRTCBatcher) Start() (err error) {
}
}
}()
puber.VideoTrack = NewH264(puber.Stream)
puber.VideoTrack = NewH264(puber.Stream, byte(codec.PayloadType))
for {
b := make([]byte, 1460)
if i, _, err := track.Read(b); err == nil {

4
go.mod

@ -48,9 +48,9 @@ require (
golang.org/x/crypto v0.3.0 // indirect
golang.org/x/exp v0.0.0-20221126150942-6ab00d035af9 // indirect
golang.org/x/mod v0.7.0 // indirect
golang.org/x/net v0.2.0 // indirect
golang.org/x/net v0.7.0 // indirect
golang.org/x/sync v0.1.0 // indirect
golang.org/x/sys v0.2.0 // indirect
golang.org/x/sys v0.5.0 // indirect
golang.org/x/tools v0.3.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
)

9
go.sum

@ -196,8 +196,8 @@ golang.org/x/net v0.0.0-20220425223048-2871e0cb64e4/go.mod h1:CfG3xpIq0wQ8r1q4Su
golang.org/x/net v0.0.0-20220531201128-c960675eff93/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
golang.org/x/net v0.1.0/go.mod h1:Cx3nUiGt4eDBEyega/BKRp+/AlGL8hYe7U9odMt2Cco=
golang.org/x/net v0.2.0 h1:sZfSu1wtKLGlWI4ZZayP0ck9Y73K1ynO6gqzTdBVdPU=
golang.org/x/net v0.2.0/go.mod h1:KqCZLdyyvdV855qA2rE3GC2aiw5xGR5TEjj8smXukLY=
golang.org/x/net v0.7.0 h1:rJrUqqhjsgNp7KqAIc25s9pZnjU7TUcSY7HcVZjdn1g=
golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
@ -230,8 +230,9 @@ golang.org/x/sys v0.0.0-20220608164250-635b8c9b7f68/go.mod h1:oPkhp1MJrh7nUepCBc
golang.org/x/sys v0.0.0-20220622161953-175b2fd9d664/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.2.0 h1:ljd4t30dBnAvMZaQCevtY0xLLD0A+bRZXbgLMLU1F/A=
golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.5.0 h1:MUK/U/4lj1t1oPg0HfuXDN/Z1wv31ZJ/YcPiGccS4DU=
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
@ -240,8 +241,8 @@ golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
golang.org/x/text v0.4.0 h1:BrVqGRd7+k1DiOgtnFvAkoQEWQvBc25ouMJM6429SFg=
golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
golang.org/x/text v0.7.0 h1:4BRB4x83lYWy72KwLD/qYDuTu7q9PjSagHvijDw7cLo=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=

23
main.go

@ -10,8 +10,9 @@ import (
"go.uber.org/zap"
"m7s.live/engine/v4"
"github.com/pion/interceptor"
_ "embed"
"github.com/pion/interceptor"
. "github.com/pion/webrtc/v3"
"m7s.live/engine/v4/config"
"m7s.live/plugin/webrtc/v4/webrtc"
@ -43,6 +44,10 @@ import (
// conn *net.UDPConn
// port int
// }
//go:embed publish.html
var publishHTML []byte
var (
reg_level = regexp.MustCompile("profile-level-id=(4.+f)")
)
@ -55,10 +60,10 @@ type WebRTCConfig struct {
PortMin uint16
PortMax uint16
InvitePortFixed bool
IceUdpMux int
InvitePortFixed bool `default:"true"` // 设备将流发送的端口,是否固定 on 发送流到多路复用端口 如9000 off 自动从 mix_port - max_port 之间的值中 选一个可以用的端口
IceUdpMux int `default:"9000"` // 接收设备端rtp流的多路复用端口
PLI time.Duration
PLI time.Duration `default:"2s"` // 视频流丢包后,发送PLI请求
m MediaEngine
s SettingEngine
api *API
@ -168,13 +173,13 @@ func (conf *WebRTCConfig) Push_(w http.ResponseWriter, r *http.Request) {
}
}
var webrtcConfig = &WebRTCConfig{
InvitePortFixed: true, // 设备将流发送的端口,是否固定 on 发送流到多路复用端口 如9000 off 自动从 mix_port - max_port 之间的值中 选一个可以用的端口
IceUdpMux: 9000, // 接收设备端rtp流的多路复用端口
PLI: time.Second * 2,
func (conf *WebRTCConfig) Test_Publish(w http.ResponseWriter, r *http.Request) {
w.Write(publishHTML)
}
var WebRTCPlugin = engine.InstallPlugin(webrtcConfig)
var webrtcConfig WebRTCConfig
var WebRTCPlugin = engine.InstallPlugin(&webrtcConfig)
func (conf *WebRTCConfig) Batch(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/sdp")

55
publish.html

@ -0,0 +1,55 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>测试WebRTC推流</title>
</head>
<body>
<video id="video" width="640" height="480" autoplay muted />
</body>
<script>
(async () => {
const mediaStream = await navigator.mediaDevices.getUserMedia({
video: true,
audio: true,
});
document.getElementById('video').srcObject = mediaStream;
const pc = new RTCPeerConnection();
pc.addTransceiver('video', { direction: 'sendonly' });
pc.addTransceiver('audio', { direction: 'sendonly' });
pc.oniceconnectionstatechange = () => {
console.log('oniceconnectionstatechange', pc.iceConnectionState);
};
pc.onicecandidate = (e) => {
console.log('onicecandidate', e.candidate);
};
mediaStream.getTracks().forEach((t) => {
pc.addTrack(t, mediaStream);
});
const offer = await pc.createOffer();
await pc.setLocalDescription(offer);
const result = await fetch(
`/webrtc/push/live/webrtc`,
{
method: 'POST',
mode: 'cors',
cache: 'no-cache',
credentials: 'include',
redirect: 'follow',
referrerPolicy: 'no-referrer',
headers: { 'Content-Type': 'application/sdp' },
body: offer.sdp,
},
);
const remoteSdp = await result.text();
await pc.setRemoteDescription(
new RTCSessionDescription({ type: 'answer', sdp: remoteSdp }),
);
})()
</script>
</html>

4
publisher.go

@ -48,7 +48,7 @@ func (puber *WebRTCPublisher) OnEvent(event any) {
}
} else {
go func() {
ticker := time.NewTicker(time.Millisecond * webrtcConfig.PLI)
ticker := time.NewTicker(webrtcConfig.PLI)
for {
select {
case <-ticker.C:
@ -61,7 +61,7 @@ func (puber *WebRTCPublisher) OnEvent(event any) {
}
}()
if puber.Equal(v) {
puber.VideoTrack = NewH264(puber.Stream)
puber.VideoTrack = NewH264(puber.Stream, byte(codec.PayloadType))
}
for {
b := make([]byte, 1460)

Loading…
Cancel
Save