mirror of
https://github.com/Monibuca/plugin-gb28181.git
synced 2025-12-24 13:27:57 +08:00
Compare commits
18 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f00a5b11e9 | ||
|
|
5690be3b64 | ||
|
|
92c9876d82 | ||
|
|
e9353651aa | ||
|
|
26f452fad0 | ||
|
|
ec32f5db39 | ||
|
|
87f3849fe7 | ||
|
|
78e16b4746 | ||
|
|
6ab73cd8dd | ||
|
|
edffd7d470 | ||
|
|
70c06ebf84 | ||
|
|
d35b18f1a9 | ||
|
|
210f67b047 | ||
|
|
bee261a670 | ||
|
|
ce49463689 | ||
|
|
cbcaab61d4 | ||
|
|
f80916dcf9 | ||
|
|
35e916dd1c |
22
README.md
22
README.md
@@ -33,6 +33,7 @@ gb28181:
|
||||
port:
|
||||
sip: udp:5060 #sip服务器端口
|
||||
media: tcp:58200-59200 #媒体服务器端口,用于接收设备的流
|
||||
fdm: false #端口复用,单端口默认多路复用,多端口多路复用根据这个
|
||||
|
||||
removebaninterval: 10m #定时移除注册失败的设备黑名单,单位秒,默认10分钟(600秒)
|
||||
loglevel: info
|
||||
@@ -138,3 +139,24 @@ http 200 表示成功,404流不存在
|
||||
| id | 是 | 设备ID |
|
||||
| expires | 是 | 订阅周期(秒) |
|
||||
| interval | 是 | 订阅间隔(秒) |
|
||||
|
||||
### 预置位列表查询
|
||||
|
||||
`/gb28181/api/preset/list`
|
||||
|
||||
| 参数名 | 必传 | 含义 |
|
||||
| -------- | ---- | -------------- |
|
||||
| id | 是 | 设备ID |
|
||||
| channel | 是 | 通道编号 |
|
||||
|
||||
|
||||
### 预置位操作
|
||||
|
||||
`/gb28181/api/preset/control`
|
||||
|
||||
| 参数名 | 必传 | 含义 |
|
||||
| -------- | ---- |---------------------|
|
||||
| id | 是 | 设备ID |
|
||||
| channel | 是 | 通道编号 |
|
||||
| cmd | 是 | 操作指令 0=新增,1=删除,2=调用 |
|
||||
| point | 是 | 预置点位1-255 |
|
||||
|
||||
164
channel.go
164
channel.go
@@ -31,6 +31,7 @@ func (p *PullStream) CreateRequest(method sip.RequestMethod) (req sip.Request) {
|
||||
req = p.channel.CreateRequst(method)
|
||||
from, _ := res.From()
|
||||
to, _ := res.To()
|
||||
|
||||
callId, _ := res.CallID()
|
||||
req.ReplaceHeaders(from.Name(), []sip.Header{from})
|
||||
req.ReplaceHeaders(to.Name(), []sip.Header{to})
|
||||
@@ -40,9 +41,9 @@ func (p *PullStream) CreateRequest(method sip.RequestMethod) (req sip.Request) {
|
||||
|
||||
func (p *PullStream) Bye() int {
|
||||
req := p.CreateRequest(sip.BYE)
|
||||
resp, err := p.channel.device.SipRequestForResponse(req)
|
||||
resp, err := p.channel.Device.SipRequestForResponse(req)
|
||||
if p.opt.IsLive() {
|
||||
p.channel.status.Store(0)
|
||||
p.channel.State.Store(0)
|
||||
}
|
||||
if p.opt.recyclePort != nil {
|
||||
p.opt.recyclePort(p.opt.MediaPort)
|
||||
@@ -54,7 +55,7 @@ func (p *PullStream) Bye() int {
|
||||
}
|
||||
|
||||
func (p *PullStream) info(body string) int {
|
||||
d := p.channel.device
|
||||
d := p.channel.Device
|
||||
req := p.CreateRequest(sip.INFO)
|
||||
contentType := sip.ContentType("Application/MANSRTSP")
|
||||
req.AppendHeader(&contentType)
|
||||
@@ -73,45 +74,45 @@ func (p *PullStream) Pause() int {
|
||||
body := fmt.Sprintf(`PAUSE RTSP/1.0
|
||||
CSeq: %d
|
||||
PauseTime: now
|
||||
`, p.channel.device.sn)
|
||||
`, p.channel.Device.SN)
|
||||
return p.info(body)
|
||||
}
|
||||
|
||||
// 恢复播放
|
||||
func (p *PullStream) Resume() int {
|
||||
d := p.channel.device
|
||||
d := p.channel.Device
|
||||
body := fmt.Sprintf(`PLAY RTSP/1.0
|
||||
CSeq: %d
|
||||
Range: npt=now-
|
||||
`, d.sn)
|
||||
`, d.SN)
|
||||
return p.info(body)
|
||||
}
|
||||
|
||||
// 跳转到播放时间
|
||||
// second: 相对于起始点调整到第 sec 秒播放
|
||||
func (p *PullStream) PlayAt(second uint) int {
|
||||
d := p.channel.device
|
||||
d := p.channel.Device
|
||||
body := fmt.Sprintf(`PLAY RTSP/1.0
|
||||
CSeq: %d
|
||||
Range: npt=%d-
|
||||
`, d.sn, second)
|
||||
`, d.SN, second)
|
||||
return p.info(body)
|
||||
}
|
||||
|
||||
// 快进/快退播放
|
||||
// speed 取值: 0.25 0.5 1 2 4 或者其对应的负数表示倒放
|
||||
func (p *PullStream) PlayForward(speed float32) int {
|
||||
d := p.channel.device
|
||||
d := p.channel.Device
|
||||
body := fmt.Sprintf(`PLAY RTSP/1.0
|
||||
CSeq: %d
|
||||
Scale: %0.6f
|
||||
`, d.sn, speed)
|
||||
`, d.SN, speed)
|
||||
return p.info(body)
|
||||
}
|
||||
|
||||
type Channel struct {
|
||||
device *Device // 所属设备
|
||||
status atomic.Int32 // 通道状态,0:空闲,1:正在invite,2:正在播放
|
||||
Device *Device `json:"-" yaml:"-"` // 所属设备
|
||||
State atomic.Int32 `json:"-" yaml:"-"` // 通道状态,0:空闲,1:正在invite,2:正在播放/对讲
|
||||
LiveSubSP string // 实时子码流,通过rtsp
|
||||
GpsTime time.Time // gps时间
|
||||
Longitude string // 经度
|
||||
@@ -120,6 +121,11 @@ type Channel struct {
|
||||
ChannelInfo
|
||||
}
|
||||
|
||||
type PresetInfo struct {
|
||||
PresetID int `json:"-" yaml:"-"` //
|
||||
PresetName string `json:"-" yaml:"-"` //
|
||||
}
|
||||
|
||||
func (c *Channel) MarshalJSON() ([]byte, error) {
|
||||
m := map[string]any{
|
||||
"DeviceID": c.DeviceID,
|
||||
@@ -140,7 +146,7 @@ func (c *Channel) MarshalJSON() ([]byte, error) {
|
||||
"Latitude": c.Latitude,
|
||||
"GpsTime": c.GpsTime,
|
||||
"LiveSubSP": c.LiveSubSP,
|
||||
"LiveStatus": c.status.Load(),
|
||||
"LiveStatus": c.State.Load(),
|
||||
}
|
||||
return json.Marshal(m)
|
||||
}
|
||||
@@ -171,14 +177,14 @@ const (
|
||||
)
|
||||
|
||||
func (channel *Channel) CreateRequst(Method sip.RequestMethod) (req sip.Request) {
|
||||
d := channel.device
|
||||
d.sn++
|
||||
d := channel.Device
|
||||
d.SN++
|
||||
|
||||
callId := sip.CallID(utils.RandNumString(10))
|
||||
userAgent := sip.UserAgentHeader("Monibuca")
|
||||
maxForwards := sip.MaxForwards(70) //增加max-forwards为默认值 70
|
||||
cseq := sip.CSeq{
|
||||
SeqNo: uint32(d.sn),
|
||||
SeqNo: uint32(d.SN),
|
||||
MethodName: Method,
|
||||
}
|
||||
port := sip.Port(conf.SipPort)
|
||||
@@ -186,14 +192,14 @@ func (channel *Channel) CreateRequst(Method sip.RequestMethod) (req sip.Request)
|
||||
//DisplayName: sip.String{Str: d.serverConfig.Serial},
|
||||
Uri: &sip.SipUri{
|
||||
FUser: sip.String{Str: conf.Serial},
|
||||
FHost: d.sipIP,
|
||||
FHost: d.SipIP,
|
||||
FPort: &port,
|
||||
},
|
||||
Params: sip.NewParams().Add("tag", sip.String{Str: utils.RandNumString(9)}),
|
||||
}
|
||||
//非同一域的目标地址需要使用@host
|
||||
host := conf.Realm
|
||||
if channel.DeviceID[0:9] != host {
|
||||
if channel.DeviceID[0:10] != host {
|
||||
if channel.Port != 0 {
|
||||
deviceIp := d.NetAddr
|
||||
deviceIp = deviceIp[0:strings.LastIndex(deviceIp, ":")]
|
||||
@@ -231,7 +237,7 @@ func (channel *Channel) CreateRequst(Method sip.RequestMethod) (req sip.Request)
|
||||
}
|
||||
|
||||
func (channel *Channel) QueryRecord(startTime, endTime string) ([]*Record, error) {
|
||||
d := channel.device
|
||||
d := channel.Device
|
||||
request := d.CreateRequest(sip.MESSAGE)
|
||||
contentType := sip.ContentType("Application/MANSCDP+xml")
|
||||
request.AppendHeader(&contentType)
|
||||
@@ -247,10 +253,10 @@ func (channel *Channel) QueryRecord(startTime, endTime string) ([]*Record, error
|
||||
// </Query>`, d.sn, channel.DeviceID, startTime, endTime)
|
||||
start, _ := strconv.ParseInt(startTime, 10, 0)
|
||||
end, _ := strconv.ParseInt(endTime, 10, 0)
|
||||
body := BuildRecordInfoXML(d.sn, channel.DeviceID, start, end)
|
||||
body := BuildRecordInfoXML(d.SN, channel.DeviceID, start, end)
|
||||
request.SetBody(body, true)
|
||||
|
||||
resultCh := RecordQueryLink.WaitResult(d.ID, channel.DeviceID, d.sn, QUERY_RECORD_TIMEOUT)
|
||||
resultCh := RecordQueryLink.WaitResult(d.ID, channel.DeviceID, d.SN, QUERY_RECORD_TIMEOUT)
|
||||
resp, err := d.SipRequestForResponse(request)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("query error: %s", err)
|
||||
@@ -264,8 +270,43 @@ func (channel *Channel) QueryRecord(startTime, endTime string) ([]*Record, error
|
||||
return r.list, r.err
|
||||
}
|
||||
|
||||
func (channel *Channel) QueryPresetList() (sip.Response, error) {
|
||||
d := channel.Device
|
||||
request := d.CreateRequest(sip.MESSAGE)
|
||||
contentType := sip.ContentType("Application/MANSCDP+xml")
|
||||
request.AppendHeader(&contentType)
|
||||
|
||||
body := BuildPresetListXML(100, channel.DeviceID)
|
||||
request.SetBody(body, true)
|
||||
|
||||
resp, err := d.SipRequestForResponse(request)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("query error: %s", err)
|
||||
}
|
||||
if resp.StatusCode() != http.StatusOK {
|
||||
return nil, fmt.Errorf("query error, status=%d", resp.StatusCode())
|
||||
}
|
||||
return resp, nil
|
||||
}
|
||||
|
||||
func (channel *Channel) PresetControl(ptzCode int, point byte) int {
|
||||
cmd := byte(PresetSet)
|
||||
switch ptzCode {
|
||||
case PresetAddPoint:
|
||||
cmd = PresetSet
|
||||
case PresetDelPoint:
|
||||
cmd = PresetDel
|
||||
case PresetCallPoint:
|
||||
cmd = PresetCall
|
||||
default:
|
||||
|
||||
}
|
||||
PTZCmd := Pack(cmd, point)
|
||||
return channel.Control(PTZCmd)
|
||||
}
|
||||
|
||||
func (channel *Channel) Control(PTZCmd string) int {
|
||||
d := channel.device
|
||||
d := channel.Device
|
||||
request := d.CreateRequest(sip.MESSAGE)
|
||||
contentType := sip.ContentType("Application/MANSCDP+xml")
|
||||
request.AppendHeader(&contentType)
|
||||
@@ -275,7 +316,7 @@ func (channel *Channel) Control(PTZCmd string) int {
|
||||
<SN>%d</SN>
|
||||
<DeviceID>%s</DeviceID>
|
||||
<PTZCmd>%s</PTZCmd>
|
||||
</Control>`, d.sn, channel.DeviceID, PTZCmd)
|
||||
</Control>`, d.SN, channel.DeviceID, PTZCmd)
|
||||
request.SetBody(body, true)
|
||||
resp, err := d.SipRequestForResponse(request)
|
||||
if err != nil {
|
||||
@@ -333,13 +374,13 @@ f字段中视、音频参数段之间不需空格分割。
|
||||
|
||||
func (channel *Channel) Invite(opt *InviteOptions) (code int, err error) {
|
||||
if opt.IsLive() {
|
||||
if !channel.status.CompareAndSwap(0, 1) {
|
||||
if !channel.State.CompareAndSwap(0, 1) {
|
||||
return 304, nil
|
||||
}
|
||||
defer func() {
|
||||
if err != nil {
|
||||
GB28181Plugin.Error("Invite", zap.Error(err))
|
||||
channel.status.Store(0)
|
||||
GB28181Plugin.Error("InviteRetryInit", zap.Error(err))
|
||||
channel.State.Store(0)
|
||||
if conf.InviteMode == 1 {
|
||||
// 5秒后重试
|
||||
time.AfterFunc(time.Second*5, func() {
|
||||
@@ -347,11 +388,12 @@ func (channel *Channel) Invite(opt *InviteOptions) (code int, err error) {
|
||||
})
|
||||
}
|
||||
} else {
|
||||
channel.status.Store(2)
|
||||
channel.State.Store(2)
|
||||
}
|
||||
}()
|
||||
}
|
||||
d := channel.device
|
||||
|
||||
d := channel.Device
|
||||
streamPath := fmt.Sprintf("%s/%s", d.ID, channel.DeviceID)
|
||||
s := "Play"
|
||||
opt.CreateSSRC()
|
||||
@@ -361,6 +403,8 @@ func (channel *Channel) Invite(opt *InviteOptions) (code int, err error) {
|
||||
}
|
||||
if opt.StreamPath != "" {
|
||||
streamPath = opt.StreamPath
|
||||
} else if channel.DeviceID == "" {
|
||||
streamPath = "gb28181/" + d.ID
|
||||
} else {
|
||||
opt.StreamPath = streamPath
|
||||
}
|
||||
@@ -369,20 +413,21 @@ func (channel *Channel) Invite(opt *InviteOptions) (code int, err error) {
|
||||
}
|
||||
protocol := ""
|
||||
networkType := "udp"
|
||||
reusePort := true
|
||||
|
||||
// 根据配置文件判断是否多路复用
|
||||
reusePort := conf.Port.Fdm
|
||||
|
||||
if conf.IsMediaNetworkTCP() {
|
||||
networkType = "tcp"
|
||||
protocol = "TCP/"
|
||||
if conf.tcpPorts.Valid {
|
||||
opt.MediaPort, err = conf.tcpPorts.GetPort()
|
||||
opt.recyclePort = conf.tcpPorts.Recycle
|
||||
reusePort = false
|
||||
}
|
||||
} else {
|
||||
if conf.udpPorts.Valid {
|
||||
opt.MediaPort, err = conf.udpPorts.GetPort()
|
||||
opt.recyclePort = conf.udpPorts.Recycle
|
||||
reusePort = false
|
||||
}
|
||||
}
|
||||
if err != nil {
|
||||
@@ -390,23 +435,25 @@ func (channel *Channel) Invite(opt *InviteOptions) (code int, err error) {
|
||||
}
|
||||
if opt.MediaPort == 0 {
|
||||
opt.MediaPort = conf.MediaPort
|
||||
// 单端口默认多路复用
|
||||
reusePort = true
|
||||
}
|
||||
|
||||
sdpInfo := []string{
|
||||
"v=0",
|
||||
fmt.Sprintf("o=%s 0 0 IN IP4 %s", channel.DeviceID, d.mediaIP),
|
||||
fmt.Sprintf("o=%s 0 0 IN IP4 %s", channel.DeviceID, d.MediaIP),
|
||||
"s=" + s,
|
||||
"u=" + channel.DeviceID + ":0",
|
||||
"c=IN IP4 " + d.mediaIP,
|
||||
"c=IN IP4 " + d.MediaIP,
|
||||
opt.String(),
|
||||
fmt.Sprintf("m=video %d %sRTP/AVP 96", opt.MediaPort, protocol),
|
||||
"a=recvonly",
|
||||
"a=rtpmap:96 PS/90000",
|
||||
"y=" + opt.ssrc,
|
||||
}
|
||||
if conf.IsMediaNetworkTCP() {
|
||||
sdpInfo = append(sdpInfo, "a=setup:passive", "a=connection:new")
|
||||
}
|
||||
sdpInfo = append(sdpInfo, "y="+opt.ssrc)
|
||||
invite := channel.CreateRequst(sip.INVITE)
|
||||
contentType := sip.ContentType("application/sdp")
|
||||
invite.AppendHeader(&contentType)
|
||||
@@ -419,7 +466,10 @@ func (channel *Channel) Invite(opt *InviteOptions) (code int, err error) {
|
||||
invite.AppendHeader(&subject)
|
||||
inviteRes, err := d.SipRequestForResponse(invite)
|
||||
if err != nil {
|
||||
channel.Error("invite", zap.Error(err), zap.String("msg", invite.String()))
|
||||
if opt.recyclePort != nil {
|
||||
opt.recyclePort(opt.MediaPort)
|
||||
}
|
||||
channel.Error("inviteRequestError", zap.Error(err), zap.String("msg", invite.String()))
|
||||
return http.StatusInternalServerError, err
|
||||
}
|
||||
code = int(inviteRes.StatusCode())
|
||||
@@ -450,29 +500,39 @@ func (channel *Channel) Invite(opt *InviteOptions) (code int, err error) {
|
||||
}
|
||||
var psPuber ps.PSPublisher
|
||||
err = psPuber.Receive(streamPath, opt.dump, fmt.Sprintf("%s:%d", networkType, opt.MediaPort), opt.SSRC, reusePort)
|
||||
if err == nil {
|
||||
if !opt.IsLive() {
|
||||
// 10秒无数据关闭
|
||||
if psPuber.Stream.DelayCloseTimeout == 0 {
|
||||
psPuber.Stream.DelayCloseTimeout = time.Second * 10
|
||||
}
|
||||
if psPuber.Stream.IdleTimeout == 0 {
|
||||
psPuber.Stream.IdleTimeout = time.Second * 10
|
||||
}
|
||||
if err != nil {
|
||||
if opt.recyclePort != nil {
|
||||
opt.recyclePort(opt.MediaPort)
|
||||
}
|
||||
PullStreams.Store(streamPath, &PullStream{
|
||||
opt: opt,
|
||||
channel: channel,
|
||||
inviteRes: inviteRes,
|
||||
})
|
||||
err = srv.Send(sip.NewAckRequest("", invite, inviteRes, "", nil))
|
||||
channel.Error("inviteTcpCreateError", zap.Error(err))
|
||||
return http.StatusInternalServerError, err
|
||||
}
|
||||
|
||||
if !opt.IsLive() {
|
||||
// 10秒无数据关闭
|
||||
if psPuber.Stream.DelayCloseTimeout == 0 {
|
||||
psPuber.Stream.DelayCloseTimeout = time.Second * 10
|
||||
}
|
||||
if psPuber.Stream.IdleTimeout == 0 {
|
||||
psPuber.Stream.IdleTimeout = time.Second * 10
|
||||
}
|
||||
}
|
||||
PullStreams.Store(streamPath, &PullStream{
|
||||
opt: opt,
|
||||
channel: channel,
|
||||
inviteRes: inviteRes,
|
||||
})
|
||||
err = srv.Send(sip.NewAckRequest("", invite, inviteRes, "", nil))
|
||||
} else {
|
||||
if opt.recyclePort != nil {
|
||||
opt.recyclePort(opt.MediaPort)
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (channel *Channel) Bye(streamPath string) int {
|
||||
d := channel.device
|
||||
d := channel.Device
|
||||
if streamPath == "" {
|
||||
streamPath = fmt.Sprintf("%s/%s", d.ID, channel.DeviceID)
|
||||
}
|
||||
@@ -538,7 +598,7 @@ func (channel *Channel) TryAutoInvite(opt *InviteOptions) {
|
||||
}
|
||||
|
||||
func (channel *Channel) CanInvite() bool {
|
||||
if channel.status.Load() != 0 || len(channel.DeviceID) != 20 || channel.Status == ChannelOffStatus {
|
||||
if channel.State.Load() != 0 || len(channel.DeviceID) != 20 || channel.Status == ChannelOffStatus {
|
||||
return false
|
||||
}
|
||||
|
||||
|
||||
47
device.go
47
device.go
@@ -54,7 +54,6 @@ const (
|
||||
)
|
||||
|
||||
type Device struct {
|
||||
//*transaction.Core `json:"-" yaml:"-"`
|
||||
ID string
|
||||
Name string
|
||||
Manufacturer string
|
||||
@@ -64,10 +63,10 @@ type Device struct {
|
||||
UpdateTime time.Time
|
||||
LastKeepaliveAt time.Time
|
||||
Status DeviceStatus
|
||||
sn int
|
||||
addr sip.Address
|
||||
sipIP string //设备对应网卡的服务器ip
|
||||
mediaIP string //设备对应网卡的服务器ip
|
||||
SN int
|
||||
Addr sip.Address `json:"-" yaml:"-"`
|
||||
SipIP string //设备对应网卡的服务器ip
|
||||
MediaIP string //设备对应网卡的服务器ip
|
||||
NetAddr string
|
||||
channelMap sync.Map
|
||||
subscriber struct {
|
||||
@@ -97,7 +96,7 @@ func (d *Device) MarshalJSON() ([]byte, error) {
|
||||
}
|
||||
func (c *GB28181Config) RecoverDevice(d *Device, req sip.Request) {
|
||||
from, _ := req.From()
|
||||
d.addr = sip.Address{
|
||||
d.Addr = sip.Address{
|
||||
DisplayName: from.DisplayName,
|
||||
Uri: from.Address,
|
||||
}
|
||||
@@ -123,8 +122,8 @@ func (c *GB28181Config) RecoverDevice(d *Device, req sip.Request) {
|
||||
}
|
||||
d.Info("RecoverDevice", zap.String("deviceIp", deviceIp), zap.String("servIp", servIp), zap.String("sipIP", sipIP), zap.String("mediaIp", mediaIp))
|
||||
d.Status = DeviceRegisterStatus
|
||||
d.sipIP = sipIP
|
||||
d.mediaIP = mediaIp
|
||||
d.SipIP = sipIP
|
||||
d.MediaIP = mediaIp
|
||||
d.NetAddr = deviceIp
|
||||
d.UpdateTime = time.Now()
|
||||
}
|
||||
@@ -140,7 +139,7 @@ func (c *GB28181Config) StoreDevice(id string, req sip.Request) (d *Device) {
|
||||
d = _d.(*Device)
|
||||
d.UpdateTime = time.Now()
|
||||
d.NetAddr = deviceIp
|
||||
d.addr = deviceAddr
|
||||
d.Addr = deviceAddr
|
||||
d.Debug("UpdateDevice", zap.String("netaddr", d.NetAddr))
|
||||
} else {
|
||||
servIp := req.Recipient().Host()
|
||||
@@ -167,9 +166,9 @@ func (c *GB28181Config) StoreDevice(id string, req sip.Request) (d *Device) {
|
||||
RegisterTime: time.Now(),
|
||||
UpdateTime: time.Now(),
|
||||
Status: DeviceRegisterStatus,
|
||||
addr: deviceAddr,
|
||||
sipIP: sipIP,
|
||||
mediaIP: mediaIp,
|
||||
Addr: deviceAddr,
|
||||
SipIP: sipIP,
|
||||
MediaIP: mediaIp,
|
||||
NetAddr: deviceIp,
|
||||
Logger: GB28181Plugin.With(zap.String("id", id)),
|
||||
}
|
||||
@@ -214,11 +213,11 @@ func (d *Device) addOrUpdateChannel(info ChannelInfo) (c *Channel) {
|
||||
c.ChannelInfo = info
|
||||
} else {
|
||||
c = &Channel{
|
||||
device: d,
|
||||
Device: d,
|
||||
ChannelInfo: info,
|
||||
Logger: d.Logger.With(zap.String("channel", info.DeviceID)),
|
||||
}
|
||||
if s := engine.Streams.Get(fmt.Sprintf("%s/%s/rtsp", c.device.ID, c.DeviceID)); s != nil {
|
||||
if s := engine.Streams.Get(fmt.Sprintf("%s/%s/rtsp", c.Device.ID, c.DeviceID)); s != nil {
|
||||
c.LiveSubSP = s.Path
|
||||
} else {
|
||||
c.LiveSubSP = ""
|
||||
@@ -234,7 +233,7 @@ func (d *Device) deleteChannel(DeviceID string) {
|
||||
|
||||
func (d *Device) UpdateChannels(list ...ChannelInfo) {
|
||||
for _, c := range list {
|
||||
if _, ok := conf.Ignores[c.DeviceID]; ok {
|
||||
if _, ok := conf.ignores[c.DeviceID]; ok {
|
||||
continue
|
||||
}
|
||||
//当父设备非空且存在时、父设备节点增加通道
|
||||
@@ -269,13 +268,13 @@ func (d *Device) UpdateChannels(list ...ChannelInfo) {
|
||||
}
|
||||
|
||||
func (d *Device) CreateRequest(Method sip.RequestMethod) (req sip.Request) {
|
||||
d.sn++
|
||||
d.SN++
|
||||
|
||||
callId := sip.CallID(utils.RandNumString(10))
|
||||
userAgent := sip.UserAgentHeader("Monibuca")
|
||||
maxForwards := sip.MaxForwards(70) //增加max-forwards为默认值 70
|
||||
cseq := sip.CSeq{
|
||||
SeqNo: uint32(d.sn),
|
||||
SeqNo: uint32(d.SN),
|
||||
MethodName: Method,
|
||||
}
|
||||
port := sip.Port(conf.SipPort)
|
||||
@@ -283,7 +282,7 @@ func (d *Device) CreateRequest(Method sip.RequestMethod) (req sip.Request) {
|
||||
//DisplayName: sip.String{Str: d.config.Serial},
|
||||
Uri: &sip.SipUri{
|
||||
FUser: sip.String{Str: conf.Serial},
|
||||
FHost: d.sipIP,
|
||||
FHost: d.SipIP,
|
||||
FPort: &port,
|
||||
},
|
||||
Params: sip.NewParams().Add("tag", sip.String{Str: utils.RandNumString(9)}),
|
||||
@@ -291,11 +290,11 @@ func (d *Device) CreateRequest(Method sip.RequestMethod) (req sip.Request) {
|
||||
req = sip.NewRequest(
|
||||
"",
|
||||
Method,
|
||||
d.addr.Uri,
|
||||
d.Addr.Uri,
|
||||
"SIP/2.0",
|
||||
[]sip.Header{
|
||||
serverAddr.AsFromHeader(),
|
||||
d.addr.AsToHeader(),
|
||||
d.Addr.AsToHeader(),
|
||||
&callId,
|
||||
&userAgent,
|
||||
&cseq,
|
||||
@@ -346,7 +345,7 @@ func (d *Device) Subscribe() int {
|
||||
request.AppendHeader(&contentType)
|
||||
request.AppendHeader(&expires)
|
||||
|
||||
request.SetBody(BuildCatalogXML(d.sn, d.ID), true)
|
||||
request.SetBody(BuildCatalogXML(d.SN, d.ID), true)
|
||||
|
||||
response, err := d.SipRequestForResponse(request)
|
||||
if err == nil && response != nil {
|
||||
@@ -370,7 +369,7 @@ func (d *Device) Catalog() int {
|
||||
|
||||
request.AppendHeader(&contentType)
|
||||
request.AppendHeader(&expires)
|
||||
request.SetBody(BuildCatalogXML(d.sn, d.ID), true)
|
||||
request.SetBody(BuildCatalogXML(d.SN, d.ID), true)
|
||||
// 输出Sip请求设备通道信息信令
|
||||
GB28181Plugin.Sugar().Debugf("SIP->Catalog:%s", request)
|
||||
resp, err := d.SipRequestForResponse(request)
|
||||
@@ -390,7 +389,7 @@ func (d *Device) QueryDeviceInfo() {
|
||||
request := d.CreateRequest(sip.MESSAGE)
|
||||
contentType := sip.ContentType("Application/MANSCDP+xml")
|
||||
request.AppendHeader(&contentType)
|
||||
request.SetBody(BuildDeviceInfoXML(d.sn, d.ID), true)
|
||||
request.SetBody(BuildDeviceInfoXML(d.SN, d.ID), true)
|
||||
|
||||
response, _ := d.SipRequestForResponse(request)
|
||||
if response != nil {
|
||||
@@ -425,7 +424,7 @@ func (d *Device) MobilePositionSubscribe(id string, expires time.Duration, inter
|
||||
mobilePosition.AppendHeader(&contentType)
|
||||
mobilePosition.AppendHeader(&expiresHeader)
|
||||
|
||||
mobilePosition.SetBody(BuildDevicePositionXML(d.sn, id, int(interval/time.Second)), true)
|
||||
mobilePosition.SetBody(BuildDevicePositionXML(d.SN, id, int(interval/time.Second)), true)
|
||||
|
||||
response, err := d.SipRequestForResponse(mobilePosition)
|
||||
if err == nil && response != nil {
|
||||
|
||||
28
go.mod
28
go.mod
@@ -3,21 +3,22 @@ module m7s.live/plugin/gb28181/v4
|
||||
go 1.19
|
||||
|
||||
require (
|
||||
github.com/ghettovoice/gosip v0.0.0-20230903092020-b059959586db
|
||||
github.com/ghettovoice/gosip v0.0.0-20231227123312-6b80e2d3e6f7
|
||||
github.com/goccy/go-json v0.10.2
|
||||
github.com/husanpao/ip v0.0.0-20220711082147-73160bb611a8
|
||||
github.com/logrusorgru/aurora/v4 v4.0.0
|
||||
github.com/pion/rtp v1.8.1
|
||||
github.com/pion/rtp v1.8.3
|
||||
go.uber.org/zap v1.26.0
|
||||
golang.org/x/net v0.15.0
|
||||
golang.org/x/text v0.13.0
|
||||
m7s.live/engine/v4 v4.13.12
|
||||
golang.org/x/net v0.19.0
|
||||
golang.org/x/text v0.14.0
|
||||
m7s.live/engine/v4 v4.15.2
|
||||
m7s.live/plugin/ps/v4 v4.1.3
|
||||
)
|
||||
|
||||
require (
|
||||
github.com/bluenviron/mediacommon v1.3.0 // indirect
|
||||
github.com/cnotch/ipchub v1.1.0 // indirect
|
||||
github.com/bluenviron/gortsplib/v4 v4.6.2 // indirect
|
||||
github.com/bluenviron/mediacommon v1.5.1 // indirect
|
||||
github.com/deepch/vdk v0.0.27 // indirect
|
||||
github.com/denisbrodbeck/machineid v1.0.1 // indirect
|
||||
github.com/discoviking/fsm v0.0.0-20150126104936-f4a273feecca // indirect
|
||||
github.com/fsnotify/fsnotify v1.6.0 // indirect
|
||||
@@ -25,10 +26,10 @@ require (
|
||||
github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 // indirect
|
||||
github.com/gobwas/httphead v0.1.0 // indirect
|
||||
github.com/gobwas/pool v0.2.1 // indirect
|
||||
github.com/gobwas/ws v1.3.0 // indirect
|
||||
github.com/gobwas/ws v1.3.1 // indirect
|
||||
github.com/golang/mock v1.6.0 // indirect
|
||||
github.com/google/pprof v0.0.0-20230912144702-c363fe2c2ed8 // indirect
|
||||
github.com/google/uuid v1.3.1 // indirect
|
||||
github.com/google/uuid v1.4.0 // indirect
|
||||
github.com/lufia/plan9stats v0.0.0-20230326075908-cb1d2100619a // indirect
|
||||
github.com/mattn/go-colorable v0.1.13 // indirect
|
||||
github.com/mattn/go-isatty v0.0.19 // indirect
|
||||
@@ -37,9 +38,10 @@ require (
|
||||
github.com/onsi/ginkgo/v2 v2.12.1 // indirect
|
||||
github.com/pion/randutil v0.1.0 // indirect
|
||||
github.com/pion/webrtc/v3 v3.2.20 // indirect
|
||||
github.com/pkg/errors v0.9.1 // indirect
|
||||
github.com/power-devops/perfstat v0.0.0-20221212215047-62379fc7944b // indirect
|
||||
github.com/q191201771/naza v0.30.48 // indirect
|
||||
github.com/quic-go/qtls-go1-20 v0.3.4 // indirect
|
||||
github.com/quic-go/qtls-go1-20 v0.3.3 // indirect
|
||||
github.com/quic-go/quic-go v0.38.1 // indirect
|
||||
github.com/satori/go.uuid v1.2.1-0.20181028125025-b2ce2384e17b // indirect
|
||||
github.com/shirou/gopsutil/v3 v3.23.8 // indirect
|
||||
@@ -52,12 +54,12 @@ require (
|
||||
github.com/yapingcat/gomedia v0.0.0-20230905155010-55b9713fcec1 // indirect
|
||||
github.com/yusufpapurcu/wmi v1.2.3 // indirect
|
||||
go.uber.org/multierr v1.11.0 // indirect
|
||||
golang.org/x/crypto v0.13.0 // indirect
|
||||
golang.org/x/crypto v0.16.0 // indirect
|
||||
golang.org/x/exp v0.0.0-20230905200255-921286631fa9 // indirect
|
||||
golang.org/x/mod v0.12.0 // indirect
|
||||
golang.org/x/sync v0.3.0 // indirect
|
||||
golang.org/x/sys v0.12.0 // indirect
|
||||
golang.org/x/term v0.12.0 // indirect
|
||||
golang.org/x/sys v0.15.0 // indirect
|
||||
golang.org/x/term v0.15.0 // indirect
|
||||
golang.org/x/tools v0.13.0 // indirect
|
||||
google.golang.org/protobuf v1.31.0 // indirect
|
||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||
|
||||
76
go.sum
76
go.sum
@@ -1,28 +1,22 @@
|
||||
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
||||
github.com/bluenviron/mediacommon v1.3.0 h1:2ttKdlvEXJSzHTd1+7x4TmJDTqEhLAAPP9QfdnYWo8U=
|
||||
github.com/bluenviron/mediacommon v1.3.0/go.mod h1:/vlOVSebDwzdRtQONOKLua0fOSJg1tUDHpP+h9a0uqM=
|
||||
github.com/cnotch/apirouter v0.0.0-20200731232942-89e243a791f3/go.mod h1:5deJPLON/x/s2dLOQfuKS0lenhOIT4xX0pvtN/OEIuY=
|
||||
github.com/cnotch/ipchub v1.1.0 h1:hH0lh2mU3AZXPiqMwA0pdtqrwo7PFIMRGush9OobMUs=
|
||||
github.com/cnotch/ipchub v1.1.0/go.mod h1:2PbeBs2q2VxxTVCn1eYCDwpAWuVXbq1+N0FU7GimOH4=
|
||||
github.com/cnotch/loader v0.0.0-20200405015128-d9d964d09439/go.mod h1:oWpDagHB6p+Kqqq7RoRZKyC4XAXft50hR8pbTxdbYYs=
|
||||
github.com/cnotch/queue v0.0.0-20200326024423-6e88bdbf2ad4/go.mod h1:zOssjAlNusOxvtaqT+EMA+Iyi8rrtKr4/XfzN1Fgoeg=
|
||||
github.com/cnotch/queue v0.0.0-20201224060551-4191569ce8f6/go.mod h1:zOssjAlNusOxvtaqT+EMA+Iyi8rrtKr4/XfzN1Fgoeg=
|
||||
github.com/cnotch/scheduler v0.0.0-20200522024700-1d2da93eefc5/go.mod h1:F4GE3SZkJZ8an1Y0ZCqvSM3jeozNuKzoC67erG1PhIo=
|
||||
github.com/cnotch/xlog v0.0.0-20201208005456-cfda439cd3a0/go.mod h1:RW9oHsR79ffl3sR3yMGgxYupMn2btzdtJUwoxFPUE5E=
|
||||
github.com/bluenviron/gortsplib/v4 v4.6.2 h1:CGIsxpnUFvSlIxnSFS0oFSSfwsHMmBCmYcrGAtIcwXc=
|
||||
github.com/bluenviron/gortsplib/v4 v4.6.2/go.mod h1:dN1YjyPNMfy/NwC17Ga6MiIMiUoQfg5GL7LGsVHa0Jo=
|
||||
github.com/bluenviron/mediacommon v1.5.1 h1:yYVF+ebqZOJh8yH+EeuPcAtTmWR66BqbJGmStxkScoI=
|
||||
github.com/bluenviron/mediacommon v1.5.1/go.mod h1:Ij/kE1LEucSjryNBVTyPL/gBI0d6/Css3f5PyrM957w=
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/deepch/vdk v0.0.27 h1:j/SHaTiZhA47wRpaue8NRp7P9xwOOO/lunxrDJBwcao=
|
||||
github.com/deepch/vdk v0.0.27/go.mod h1:JlgGyR2ld6+xOIHa7XAxJh+stSDBAkdNvIPkUIdIywk=
|
||||
github.com/denisbrodbeck/machineid v1.0.1 h1:geKr9qtkB876mXguW2X6TU4ZynleN6ezuMSRhl4D7AQ=
|
||||
github.com/denisbrodbeck/machineid v1.0.1/go.mod h1:dJUwb7PTidGDeYyUBmXZ2GphQBbjJCrnectwCyxcUSI=
|
||||
github.com/discoviking/fsm v0.0.0-20150126104936-f4a273feecca h1:cTTdXpkQ1aVbOOmHwdwtYuwUZcQtcMrleD1UXLWhAq8=
|
||||
github.com/discoviking/fsm v0.0.0-20150126104936-f4a273feecca/go.mod h1:W+3LQaEkN8qAwwcw0KC546sUEnX86GIT8CcMLZC4mG0=
|
||||
github.com/emitter-io/address v1.0.0/go.mod h1:GfZb5+S/o8694B1GMGK2imUYQyn2skszMvGNA5D84Ug=
|
||||
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
|
||||
github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
|
||||
github.com/fsnotify/fsnotify v1.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4HY=
|
||||
github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbSClcnxKAGw=
|
||||
github.com/ghettovoice/gosip v0.0.0-20230903092020-b059959586db h1:qelpTmyJjcdeMcFKl+iZm5L8EIdV99Qz/3MIUbAm/xk=
|
||||
github.com/ghettovoice/gosip v0.0.0-20230903092020-b059959586db/go.mod h1:rlD1yLOErWYohWTryG/2bTTpmzB79p52ntLA/uIFXeI=
|
||||
github.com/ghettovoice/gosip v0.0.0-20231227123312-6b80e2d3e6f7 h1:2ENInMa9XHho+1mUM8RZMZomAnfz+qR5v6AS0+TrM8w=
|
||||
github.com/ghettovoice/gosip v0.0.0-20231227123312-6b80e2d3e6f7/go.mod h1:rlD1yLOErWYohWTryG/2bTTpmzB79p52ntLA/uIFXeI=
|
||||
github.com/go-logr/logr v1.2.4 h1:g01GSCwiDw2xSZfjJ2/T9M+S6pFdcNtFYsp+Y43HYDQ=
|
||||
github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0=
|
||||
github.com/go-ole/go-ole v1.3.0 h1:Dt6ye7+vXGIKZ7Xtk4s6/xVdGDQynvom7xCFEdWr6uE=
|
||||
@@ -35,8 +29,8 @@ github.com/gobwas/httphead v0.1.0/go.mod h1:O/RXo79gxV8G+RqlR/otEwx4Q36zl9rqC5u1
|
||||
github.com/gobwas/pool v0.2.1 h1:xfeeEhW7pwmX8nuLVlqbzVc7udMDrwetjEv+TZIz1og=
|
||||
github.com/gobwas/pool v0.2.1/go.mod h1:q8bcK0KcYlCgd9e7WYLm9LpyS+YeLd8JVDW6WezmKEw=
|
||||
github.com/gobwas/ws v1.1.0-rc.1/go.mod h1:nzvNcVha5eUziGrbxFCo6qFIojQHjJV5cLYIbezhfL0=
|
||||
github.com/gobwas/ws v1.3.0 h1:sbeU3Y4Qzlb+MOzIe6mQGf7QR4Hkv6ZD0qhGkBFL2O0=
|
||||
github.com/gobwas/ws v1.3.0/go.mod h1:hRKAFb8wOxFROYNsT1bqfWnhX+b5MFeJM9r2ZSwg/KY=
|
||||
github.com/gobwas/ws v1.3.1 h1:Qi34dfLMWJbiKaNbDVzM9x27nZBjmkaW6i4+Ku+pGVU=
|
||||
github.com/gobwas/ws v1.3.1/go.mod h1:hRKAFb8wOxFROYNsT1bqfWnhX+b5MFeJM9r2ZSwg/KY=
|
||||
github.com/goccy/go-json v0.10.2 h1:CrxCmQqYDkv1z7lO7Wbh2HN93uovUHgrECaO5ZrCXAU=
|
||||
github.com/goccy/go-json v0.10.2/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I=
|
||||
github.com/golang/mock v1.6.0 h1:ErTB+efbowRARo13NNdxyJji2egdxLGQhRaY+DUumQc=
|
||||
@@ -60,15 +54,12 @@ github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38=
|
||||
github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
||||
github.com/google/pprof v0.0.0-20230912144702-c363fe2c2ed8 h1:gpptm606MZYGaMHMsB4Srmb6EbW/IVHnt04rcMXnkBQ=
|
||||
github.com/google/pprof v0.0.0-20230912144702-c363fe2c2ed8/go.mod h1:czg5+yv1E0ZGTi6S6vVK1mke0fV+FaUhNGcd6VRS9Ik=
|
||||
github.com/google/uuid v1.3.1 h1:KjJaJ9iWZ3jOFZIf1Lqf4laDRCasjl0BCmnEGxkdLb4=
|
||||
github.com/google/uuid v1.3.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
|
||||
github.com/google/uuid v1.4.0 h1:MtMxsa51/r9yyhkyLsVeVt0B+BGQZzpQiTQ4eHZ8bc4=
|
||||
github.com/google/uuid v1.4.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
|
||||
github.com/husanpao/ip v0.0.0-20220711082147-73160bb611a8 h1:4Jk58quTZmzJcTrLlbB5L1Q6qXu49EIjCReWxcBFWKo=
|
||||
github.com/husanpao/ip v0.0.0-20220711082147-73160bb611a8/go.mod h1:medl9/CfYoQlqAXtAARmMW5dAX2UOdwwkhaszYPk0AM=
|
||||
github.com/kelindar/process v0.0.0-20170730150328-69a29e249ec3/go.mod h1:+lTCLnZFXOkqwD8sLPl6u4erAc0cP8wFegQHfipz7KE=
|
||||
github.com/kelindar/rate v1.0.0/go.mod h1:AjT4G+hTItNwt30lucEGZIz8y7Uk5zPho6vurIZ+1Es=
|
||||
github.com/kelindar/tcp v1.0.0/go.mod h1:JB5hj1cshLU60XrLij2BBxW3JQ4hOye8vqbyvuKb52k=
|
||||
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
||||
github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
||||
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
|
||||
@@ -99,7 +90,6 @@ github.com/nxadm/tail v1.4.5/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI
|
||||
github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE=
|
||||
github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU=
|
||||
github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
|
||||
github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
|
||||
github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk=
|
||||
github.com/onsi/ginkgo v1.14.2/go.mod h1:iSB4RoI2tjJc9BBv4NKIKWKya62Rps+oPG/Lv9klQyY=
|
||||
github.com/onsi/ginkgo v1.16.4/go.mod h1:dX+/inL/fNMqNlz0e9LfyB9TswhZpCVdJM/Z6Vvnwo0=
|
||||
@@ -107,7 +97,6 @@ github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE=
|
||||
github.com/onsi/ginkgo v1.16.5/go.mod h1:+E8gABHa3K6zRBolWtd+ROzc/U5bkGt0FwiG042wbpU=
|
||||
github.com/onsi/ginkgo/v2 v2.12.1 h1:uHNEO1RP2SpuZApSkel9nEh1/Mu+hmQe7Q+Pepg5OYA=
|
||||
github.com/onsi/ginkgo/v2 v2.12.1/go.mod h1:TE309ZR8s5FsKKpuB1YAQYBzCaAfUgatB/xlT/ETL/o=
|
||||
github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
|
||||
github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY=
|
||||
github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo=
|
||||
github.com/onsi/gomega v1.10.4/go.mod h1:g/HbgYopi++010VEqkFgJHKC09uJiW9UkXvMUuKHUCQ=
|
||||
@@ -122,9 +111,9 @@ github.com/pion/mdns v0.0.8/go.mod h1:hYE72WX8WDveIhg7fmXgMKivD3Puklk0Ymzog0lSya
|
||||
github.com/pion/randutil v0.1.0 h1:CFG1UdESneORglEsnimhUjf33Rwjubwj6xfiOXBa3mA=
|
||||
github.com/pion/randutil v0.1.0/go.mod h1:XcJrSMMbbMRhASFVOlj/5hQial/Y8oH/HVo7TBZq+j8=
|
||||
github.com/pion/rtcp v1.2.10/go.mod h1:ztfEwXZNLGyF1oQDttz/ZKIBaeeg/oWbRYqzBM9TL1I=
|
||||
github.com/pion/rtp v1.6.2/go.mod h1:bDb5n+BFZxXx0Ea7E5qe+klMuqiBrP+w8XSjiWtCUko=
|
||||
github.com/pion/rtp v1.8.1 h1:26OxTc6lKg/qLSGir5agLyj0QKaOv8OP5wps2SFnVNQ=
|
||||
github.com/pion/rtp v1.8.1/go.mod h1:pBGHaFt/yW7bf1jjWAoUjpSNoDnw98KTMg+jWWvziqU=
|
||||
github.com/pion/rtp v1.8.3 h1:VEHxqzSVQxCkKDSHro5/4IUUG1ea+MFdqR2R3xSpNU8=
|
||||
github.com/pion/rtp v1.8.3/go.mod h1:pBGHaFt/yW7bf1jjWAoUjpSNoDnw98KTMg+jWWvziqU=
|
||||
github.com/pion/sctp v1.8.5/go.mod h1:SUFFfDpViyKejTAdwD1d/HQsCu+V/40cCs2nZIvC3s0=
|
||||
github.com/pion/sctp v1.8.8/go.mod h1:igF9nZBrjh5AtmKc7U30jXltsFHicFCXSmWA2GWRaWs=
|
||||
github.com/pion/sdp/v3 v3.0.6/go.mod h1:iiFWFpQO8Fy3S5ldclBkpXqmWy02ns78NOKoLLL0YQw=
|
||||
@@ -137,7 +126,8 @@ github.com/pion/transport/v2 v2.2.3/go.mod h1:q2U/tf9FEfnSBGSW6w5Qp5PFWRLRj3NjLh
|
||||
github.com/pion/turn/v2 v2.1.3/go.mod h1:huEpByKKHix2/b9kmTAM3YoX6MKP+/D//0ClgUYR2fY=
|
||||
github.com/pion/webrtc/v3 v3.2.20 h1:BQJiXQsJq9LgLp3op7rLy1y8d2WD+LtiS9cpY0uQ22A=
|
||||
github.com/pion/webrtc/v3 v3.2.20/go.mod h1:vVURQTBOG5BpWKOJz3nlr23NfTDeyKVmubRNqzQp+Tg=
|
||||
github.com/pixelbender/go-sdp v1.1.0/go.mod h1:6IBlz9+BrUHoFTea7gcp4S54khtOhjCW/nVDLhmZBAs=
|
||||
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
|
||||
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c/go.mod h1:OmDBASR4679mdNQnz2pUhc2G8CO2JrUAVFDRBDP/hJE=
|
||||
@@ -145,8 +135,8 @@ github.com/power-devops/perfstat v0.0.0-20221212215047-62379fc7944b h1:0LFwY6Q3g
|
||||
github.com/power-devops/perfstat v0.0.0-20221212215047-62379fc7944b/go.mod h1:OmDBASR4679mdNQnz2pUhc2G8CO2JrUAVFDRBDP/hJE=
|
||||
github.com/q191201771/naza v0.30.48 h1:lbYUaa7A15kJKYwOiU4AbFS1Zo8oQwppl2tLEbJTqnw=
|
||||
github.com/q191201771/naza v0.30.48/go.mod h1:n+dpJjQSh90PxBwxBNuifOwQttywvSIN5TkWSSYCeBk=
|
||||
github.com/quic-go/qtls-go1-20 v0.3.4 h1:MfFAPULvst4yoMgY9QmtpYmfij/em7O8UUi+bNVm7Cg=
|
||||
github.com/quic-go/qtls-go1-20 v0.3.4/go.mod h1:X9Nh97ZL80Z+bX/gUXMbipO6OxdiDi58b/fMC9mAL+k=
|
||||
github.com/quic-go/qtls-go1-20 v0.3.3 h1:17/glZSLI9P9fDAeyCHBFSWSqJcwx1byhLwP5eUIDCM=
|
||||
github.com/quic-go/qtls-go1-20 v0.3.3/go.mod h1:X9Nh97ZL80Z+bX/gUXMbipO6OxdiDi58b/fMC9mAL+k=
|
||||
github.com/quic-go/quic-go v0.38.1 h1:M36YWA5dEhEeT+slOu/SwMEucbYd0YFidxG3KlGPZaE=
|
||||
github.com/quic-go/quic-go v0.38.1/go.mod h1:ijnZM7JsFIkp4cRyjxJNIzdSfCLmUMg9wdyhGmg+SN4=
|
||||
github.com/satori/go.uuid v1.2.1-0.20181028125025-b2ce2384e17b h1:gQZ0qzfKHQIybLANtM3mBXNUtOfsCFXeTsnBqCsx1KM=
|
||||
@@ -161,7 +151,6 @@ github.com/shoenig/test v0.6.4/go.mod h1:byHiCGXqrVaflBLAMq/srcZIHynQPQgeyvkvXnj
|
||||
github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
|
||||
github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ=
|
||||
github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
|
||||
github.com/sqs/goreturns v0.0.0-20181028201513-538ac6014518/go.mod h1:CKI4AZ4XmGV240rTHfO0hfE83S6/a3/Q1siZJ/vXf7A=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
|
||||
@@ -200,14 +189,13 @@ go.uber.org/zap v1.26.0/go.mod h1:dtElttAiwGvoJ/vj4IwHBS/gXsEu/pZ50mUIRWuG0so=
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/crypto v0.0.0-20201221181555-eec23a3978ad/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I=
|
||||
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
||||
golang.org/x/crypto v0.8.0/go.mod h1:mRqEX+O9/h5TFCrQhkgjo2yKi0yYA+9ecGkdQoHrywE=
|
||||
golang.org/x/crypto v0.10.0/go.mod h1:o4eNf7Ede1fv+hwOwZsTHl9EsPFO6q6ZvYR8vYfY45I=
|
||||
golang.org/x/crypto v0.11.0/go.mod h1:xgJhtzW8F9jGdVFWZESrid1U1bjeNy4zgy5cRr/CIio=
|
||||
golang.org/x/crypto v0.12.0/go.mod h1:NF0Gs7EO5K4qLn+Ylc+fih8BSTeIjAP05siRnAh98yw=
|
||||
golang.org/x/crypto v0.13.0 h1:mvySKfSWJ+UKUii46M40LOvyWfN0s2U+46/jDd0e6Ck=
|
||||
golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliYc=
|
||||
golang.org/x/crypto v0.16.0 h1:mMMrFzRSCF0GvB7Ne27XVtVAaXLrPmgPC7/v0tkwHaY=
|
||||
golang.org/x/crypto v0.16.0/go.mod h1:gCAAfMLgwOJRpTjQ2zCCt2OcSfYMTeZVSRtQlPC7Nq4=
|
||||
golang.org/x/exp v0.0.0-20230905200255-921286631fa9 h1:GoHiUyI/Tp2nVkLI2mCxVkOjsbSXD66ic0XW0js0R9g=
|
||||
golang.org/x/exp v0.0.0-20230905200255-921286631fa9/go.mod h1:S2oDrQGGwySpoQPVqRShND87VCbxmc6bL1Yd2oYrm6k=
|
||||
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
@@ -233,8 +221,8 @@ golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg=
|
||||
golang.org/x/net v0.11.0/go.mod h1:2L/ixqYpgIVXmeoSA/4Lu7BzTG4KIyPIryS4IsOd1oQ=
|
||||
golang.org/x/net v0.13.0/go.mod h1:zEVYFnQC7m/vmpQFELhcD1EWkZlX69l4oqgmer6hfKA=
|
||||
golang.org/x/net v0.14.0/go.mod h1:PpSgVXXLK0OxS0F31C1/tv6XNguvCrnXIDrFMspZIUI=
|
||||
golang.org/x/net v0.15.0 h1:ugBLEUaxABaB5AJqW9enI0ACdci2RUd4eP51NTBvuJ8=
|
||||
golang.org/x/net v0.15.0/go.mod h1:idbUs1IY1+zTqbi8yxTbhexhEEk5ur9LInksu6HrEpk=
|
||||
golang.org/x/net v0.19.0 h1:zTwKpTd2XuCqf8huc7Fo2iSy+4RHPd10s4KzeTnVr1c=
|
||||
golang.org/x/net v0.19.0/go.mod h1:CfAk/cbD4CthTvqiEl8NpboMuiuOYsAr/7NOjZJtv1U=
|
||||
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=
|
||||
@@ -251,7 +239,6 @@ golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7w
|
||||
golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200519105757-fe76b779f299/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
@@ -278,9 +265,8 @@ golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.9.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.10.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.12.0 h1:CM0HF96J0hcLAwsHPJZjfdNzs0gftsLfgKt57wWHJ0o=
|
||||
golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
|
||||
golang.org/x/sys v0.15.0 h1:h48lPFYpsTvQJZF4EKyI4aLHaev3CxivZmv7yZig9pc=
|
||||
golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
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=
|
||||
golang.org/x/term v0.1.0/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||
@@ -290,8 +276,8 @@ golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo=
|
||||
golang.org/x/term v0.9.0/go.mod h1:M6DEAAIenWoTxdKrOltXcmDY3rSplQUkrvaDU5FcQyo=
|
||||
golang.org/x/term v0.10.0/go.mod h1:lpqdcUyK/oCiQxvxVrppt5ggO2KCZ5QblwqPnfZ6d5o=
|
||||
golang.org/x/term v0.11.0/go.mod h1:zC9APTIj3jG3FdV/Ons+XE1riIZXG4aZ4GTHiPZJPIU=
|
||||
golang.org/x/term v0.12.0 h1:/ZfYdc3zq+q02Rv9vGqTeSItdzZTSNDmfTi0mBAuidU=
|
||||
golang.org/x/term v0.12.0/go.mod h1:owVbMEjm3cBLCHdkQu9b1opXd4ETQWc3BhuQGKgXgvU=
|
||||
golang.org/x/term v0.15.0 h1:y/Oo/a/q3IXu26lQgl04j/gjuBDOBlx7X6Om1j2CPW4=
|
||||
golang.org/x/term v0.15.0/go.mod h1:BDl952bC7+uMoWR75FIrCDx79TPU9oHkTZ9yRbYOrX0=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
|
||||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
@@ -303,8 +289,8 @@ golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
|
||||
golang.org/x/text v0.10.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
|
||||
golang.org/x/text v0.11.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
|
||||
golang.org/x/text v0.12.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
|
||||
golang.org/x/text v0.13.0 h1:ablQoSUd0tRdKxZewP80B+BaqeKJuVhuRxj/dkrun3k=
|
||||
golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
|
||||
golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ=
|
||||
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
|
||||
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=
|
||||
@@ -332,10 +318,8 @@ gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8
|
||||
gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f h1:BLraFXnmrev5lT+xlilqcH8XK9/i0At2xKjWk4p6zsU=
|
||||
gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
|
||||
gopkg.in/natefinch/lumberjack.v2 v2.0.0/go.mod h1:l0ndWWf7gzL7RNwBG7wST/UCcT4T24xpD6X8LsfU/+k=
|
||||
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ=
|
||||
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
|
||||
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
@@ -343,7 +327,7 @@ gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
|
||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
m7s.live/engine/v4 v4.13.12 h1:GYdIPlvwkS57DbZGvQxgMJIKL+hyYZpOv/8qNjGbY6E=
|
||||
m7s.live/engine/v4 v4.13.12/go.mod h1:cRR/WOZbPSAQfYxIHuCkj1YMg+C54CYlFpOJ88q+OG4=
|
||||
m7s.live/engine/v4 v4.15.2 h1:Uws658Ict2B8JojBG7fNmd2G2i63MlomsQ4npgNzF3g=
|
||||
m7s.live/engine/v4 v4.15.2/go.mod h1:uKxjmsjU1WARUNowEkP83BSrJMUjGwkJrX5nPi6DGmE=
|
||||
m7s.live/plugin/ps/v4 v4.1.3 h1:Lbvu3ZlX/s3w9lcOwF0SCOCvxtxongPexCIn6x4yukw=
|
||||
m7s.live/plugin/ps/v4 v4.1.3/go.mod h1:RAb507iNmPG43I5kUA6ewF1fTRHDRsKbIVkIdLdKeeI=
|
||||
|
||||
32
handle.go
32
handle.go
@@ -7,10 +7,10 @@ import (
|
||||
"fmt"
|
||||
"strconv"
|
||||
|
||||
"go.uber.org/zap"
|
||||
"m7s.live/plugin/gb28181/v4/utils"
|
||||
|
||||
"github.com/ghettovoice/gosip/sip"
|
||||
"go.uber.org/zap"
|
||||
. "m7s.live/engine/v4"
|
||||
"m7s.live/plugin/gb28181/v4/utils"
|
||||
|
||||
"net/http"
|
||||
"time"
|
||||
@@ -55,7 +55,7 @@ func (a *Authorization) getDigest(raw string) string {
|
||||
func (c *GB28181Config) OnRegister(req sip.Request, tx sip.ServerTransaction) {
|
||||
from, ok := req.From()
|
||||
if !ok || from.Address == nil || from.Address.User() == nil {
|
||||
GB28181Plugin.Error("OnMessage", zap.String("error", "no id"))
|
||||
GB28181Plugin.Error("OnRegister", zap.String("error", "no id"))
|
||||
return
|
||||
}
|
||||
id := from.Address.User().String()
|
||||
@@ -195,6 +195,11 @@ func (d *Device) syncChannels() {
|
||||
}
|
||||
}
|
||||
|
||||
type MessageEvent struct {
|
||||
Type string
|
||||
Device *Device
|
||||
}
|
||||
|
||||
func (c *GB28181Config) OnMessage(req sip.Request, tx sip.ServerTransaction) {
|
||||
from, ok := req.From()
|
||||
if !ok || from.Address == nil || from.Address.User() == nil {
|
||||
@@ -267,13 +272,20 @@ func (c *GB28181Config) OnMessage(req sip.Request, tx sip.ServerTransaction) {
|
||||
case "Alarm":
|
||||
d.Status = DeviceAlarmedStatus
|
||||
body = BuildAlarmResponseXML(d.ID)
|
||||
case "Broadcast":
|
||||
GB28181Plugin.Info("broadcast message", zap.String("body", req.Body()))
|
||||
case "PresetQuery":
|
||||
GB28181Plugin.Info("PresetQuery message", zap.String("body", req.Body()))
|
||||
default:
|
||||
d.Warn("Not supported CmdType", zap.String("CmdType", temp.CmdType), zap.String("body", req.Body()))
|
||||
response := sip.NewResponseFromRequest("", req, http.StatusBadRequest, "", "")
|
||||
tx.Respond(response)
|
||||
return
|
||||
}
|
||||
|
||||
EmitEvent(MessageEvent{
|
||||
Type: temp.CmdType,
|
||||
Device: d,
|
||||
})
|
||||
tx.Respond(sip.NewResponseFromRequest("", req, http.StatusOK, "OK", body))
|
||||
} else {
|
||||
GB28181Plugin.Debug("Unauthorized message, device not found", zap.String("id", id))
|
||||
@@ -283,6 +295,8 @@ func (c *GB28181Config) OnBye(req sip.Request, tx sip.ServerTransaction) {
|
||||
tx.Respond(sip.NewResponseFromRequest("", req, http.StatusOK, "OK", ""))
|
||||
}
|
||||
|
||||
type NotifyEvent MessageEvent
|
||||
|
||||
// OnNotify 订阅通知处理
|
||||
func (c *GB28181Config) OnNotify(req sip.Request, tx sip.ServerTransaction) {
|
||||
from, ok := req.From()
|
||||
@@ -323,15 +337,17 @@ func (c *GB28181Config) OnNotify(req sip.Request, tx sip.ServerTransaction) {
|
||||
case "MobilePosition":
|
||||
//更新channel的坐标
|
||||
d.UpdateChannelPosition(temp.DeviceID, temp.Time, temp.Longitude, temp.Latitude)
|
||||
// case "Alarm":
|
||||
// //报警事件通知 TODO
|
||||
case "Alarm":
|
||||
d.Status = DeviceAlarmedStatus
|
||||
default:
|
||||
d.Warn("Not supported CmdType", zap.String("CmdType", temp.CmdType), zap.String("body", req.Body()))
|
||||
response := sip.NewResponseFromRequest("", req, http.StatusBadRequest, "", "")
|
||||
tx.Respond(response)
|
||||
return
|
||||
}
|
||||
|
||||
EmitEvent(NotifyEvent{
|
||||
Type: temp.CmdType,
|
||||
Device: d})
|
||||
tx.Respond(sip.NewResponseFromRequest("", req, http.StatusOK, "OK", body))
|
||||
}
|
||||
}
|
||||
|
||||
83
main.go
83
main.go
@@ -6,6 +6,7 @@ import (
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/ghettovoice/gosip/sip"
|
||||
myip "github.com/husanpao/ip"
|
||||
"go.uber.org/zap"
|
||||
. "m7s.live/engine/v4"
|
||||
@@ -13,55 +14,52 @@ import (
|
||||
)
|
||||
|
||||
type GB28181PositionConfig struct {
|
||||
AutosubPosition bool //是否自动订阅定位
|
||||
Expires time.Duration `default:"3600s"` //订阅周期(单位:秒)
|
||||
Interval time.Duration `default:"6s"` //订阅间隔(单位:秒)
|
||||
AutosubPosition bool `desc:"是否自动订阅定位"` //是否自动订阅定位
|
||||
Expires time.Duration `default:"3600s" desc:"订阅周期"` //订阅周期
|
||||
Interval time.Duration `default:"6s" desc:"订阅间隔"` //订阅间隔
|
||||
}
|
||||
|
||||
type GB28181Config struct {
|
||||
InviteMode int `default:"1"` //邀请模式,0:手动拉流,1:预拉流,2:按需拉流
|
||||
InviteIDs string //按照国标gb28181协议允许邀请的设备类型:132 摄像机 NVR
|
||||
ListenAddr string `default:"0.0.0.0"`
|
||||
InviteMode int `default:"1" desc:"拉流模式" enum:"0:手动拉流,1:预拉流,2:按需拉流"` //邀请模式,0:手动拉流,1:预拉流,2:按需拉流
|
||||
InviteIDs string `default:"131,132" desc:"允许邀请的设备类型( 11~13位是设备类型编码),逗号分割"` //按照国标gb28181协议允许邀请的设备类型:132 摄像机 NVR
|
||||
ListenAddr string `default:"0.0.0.0" desc:"监听IP地址"` //监听地址
|
||||
//sip服务器的配置
|
||||
SipNetwork string `default:"udp"` //传输协议,默认UDP,可选TCP
|
||||
SipIP string //sip 服务器公网IP
|
||||
SipPort uint16 `default:"5060"` //sip 服务器端口,默认 5060
|
||||
Serial string `default:"34020000002000000001"` //sip 服务器 id, 默认 34020000002000000001
|
||||
Realm string `default:"3402000000"` //sip 服务器域,默认 3402000000
|
||||
Username string //sip 服务器账号
|
||||
Password string //sip 服务器密码
|
||||
SipNetwork string `default:"udp" desc:"废弃,请使用 Port"` //传输协议,默认UDP,可选TCP
|
||||
SipIP string `desc:"sip 服务IP地址"` //sip 服务器公网IP
|
||||
SipPort sip.Port `default:"5060" desc:"废弃,请使用 Port"` //sip 服务器端口,默认 5060
|
||||
Serial string `default:"34020000002000000001" desc:"sip 服务 id"` //sip 服务器 id, 默认 34020000002000000001
|
||||
Realm string `default:"3402000000" desc:"sip 服务域"` //sip 服务器域,默认 3402000000
|
||||
Username string `desc:"sip 服务账号"` //sip 服务器账号
|
||||
Password string `desc:"sip 服务密码"` //sip 服务器密码
|
||||
Port struct { // 新配置方式
|
||||
Sip string `default:"udp:5060"`
|
||||
Media string `default:"tcp:58200-59200"`
|
||||
Sip string `default:"udp:5060" desc:"sip服务端口号"`
|
||||
Media string `default:"tcp:58200-59200" desc:"媒体服务端口号"`
|
||||
Fdm bool `default:"false" desc:"多路复用"`
|
||||
}
|
||||
// AckTimeout uint16 //sip 服务应答超时,单位秒
|
||||
RegisterValidity time.Duration `default:"3600s"` //注册有效期,单位秒,默认 3600
|
||||
// RegisterInterval int //注册间隔,单位秒,默认 60
|
||||
HeartbeatInterval time.Duration `default:"60s"` //心跳间隔,单位秒,默认 60
|
||||
// HeartbeatRetry int //心跳超时次数,默认 3
|
||||
RegisterValidity time.Duration `default:"3600s" desc:"注册有效期"` //注册有效期,单位秒,默认 3600
|
||||
HeartbeatInterval time.Duration `default:"60s" desc:"心跳间隔"` //心跳间隔,单位秒,默认 60
|
||||
|
||||
//媒体服务器配置
|
||||
MediaIP string //媒体服务器地址
|
||||
MediaPort uint16 `default:"58200"` //媒体服务器端口
|
||||
MediaNetwork string `default:"tcp"` //媒体传输协议,默认UDP,可选TCP
|
||||
MediaPortMin uint16 `default:"58200"`
|
||||
MediaPortMax uint16 `default:"59200"`
|
||||
// MediaIdleTimeout uint16 //推流超时时间,超过则断开链接,让设备重连
|
||||
MediaIP string `desc:"媒体服务IP地址"` //媒体服务器地址
|
||||
MediaPort uint16 `default:"58200" desc:"废弃,请使用 Port"` //媒体服务器端口
|
||||
MediaNetwork string `default:"tcp" desc:"废弃,请使用 Port"` //媒体传输协议,默认UDP,可选TCP
|
||||
MediaPortMin uint16 `default:"58200" desc:"废弃,请使用 Port"`
|
||||
MediaPortMax uint16 `default:"59200" desc:"废弃,请使用 Port"`
|
||||
|
||||
// WaitKeyFrame bool //是否等待关键帧,如果等待,则在收到第一个关键帧之前,忽略所有媒体流
|
||||
RemoveBanInterval time.Duration `default:"600s"` //移除禁止设备间隔
|
||||
// UdpCacheSize int //udp缓存大小
|
||||
LogLevel string `default:"info"` //trace, debug, info, warn, error, fatal, panic
|
||||
routes map[string]string
|
||||
DumpPath string //dump PS流本地文件路径
|
||||
Ignores map[string]struct{}
|
||||
tcpPorts PortManager
|
||||
udpPorts PortManager
|
||||
RemoveBanInterval time.Duration `default:"600s" desc:"移除禁止设备间隔"` //移除禁止设备间隔
|
||||
routes map[string]string
|
||||
DumpPath string `desc:"dump PS流本地文件路径"` //dump PS流本地文件路径
|
||||
Ignores []string `desc:"忽略的设备ID"` //忽略的设备ID
|
||||
ignores map[string]struct{}
|
||||
tcpPorts PortManager
|
||||
udpPorts PortManager
|
||||
|
||||
Position GB28181PositionConfig //关于定位的配置参数
|
||||
|
||||
}
|
||||
|
||||
var SipUri *sip.SipUri
|
||||
|
||||
func (c *GB28181Config) initRoutes() {
|
||||
c.routes = make(map[string]string)
|
||||
tempIps := myip.LocalAndInternalIPs()
|
||||
@@ -80,7 +78,7 @@ func (c *GB28181Config) OnEvent(event any) {
|
||||
if c.Port.Sip != "udp:5060" {
|
||||
protocol, ports := util.Conf2Listener(c.Port.Sip)
|
||||
c.SipNetwork = protocol
|
||||
c.SipPort = ports[0]
|
||||
c.SipPort = sip.Port(ports[0])
|
||||
}
|
||||
if c.Port.Media != "tcp:58200-59200" {
|
||||
protocol, ports := util.Conf2Listener(c.Port.Media)
|
||||
@@ -89,13 +87,24 @@ func (c *GB28181Config) OnEvent(event any) {
|
||||
c.MediaPortMin = ports[0]
|
||||
c.MediaPortMax = ports[1]
|
||||
} else {
|
||||
c.MediaPortMin = 0
|
||||
c.MediaPortMin = 0
|
||||
c.MediaPortMax = 0
|
||||
c.MediaPort = ports[0]
|
||||
}
|
||||
}
|
||||
if len(c.Ignores) > 0 {
|
||||
c.ignores = make(map[string]struct{})
|
||||
for _, v := range c.Ignores {
|
||||
c.ignores[v] = util.Null
|
||||
}
|
||||
}
|
||||
os.MkdirAll(c.DumpPath, 0766)
|
||||
c.ReadDevices()
|
||||
SipUri = &sip.SipUri{
|
||||
FUser: sip.String{Str: c.Serial},
|
||||
FHost: c.SipIP,
|
||||
FPort: &conf.SipPort,
|
||||
}
|
||||
go c.initRoutes()
|
||||
c.startServer()
|
||||
case InvitePublish:
|
||||
|
||||
25
manscdp.go
25
manscdp.go
@@ -1,12 +1,23 @@
|
||||
package gb28181
|
||||
|
||||
import (
|
||||
"encoding/xml"
|
||||
"fmt"
|
||||
"strconv"
|
||||
"time"
|
||||
)
|
||||
|
||||
var (
|
||||
// 获取预置位列表
|
||||
PresentListXML = `
|
||||
<?xml version="1.0"?>
|
||||
<Query>
|
||||
<CmdType>PresetQuery</CmdType>
|
||||
<SN>%d</SN>
|
||||
<DeviceID>%s</DeviceID>
|
||||
</Query>
|
||||
`
|
||||
|
||||
// CatalogXML 获取设备列表xml样式
|
||||
CatalogXML = `<?xml version="1.0"?><Query>
|
||||
<CmdType>Catalog</CmdType>
|
||||
@@ -65,6 +76,10 @@ func BuildCatalogXML(sn int, id string) string {
|
||||
return fmt.Sprintf(CatalogXML, sn, id)
|
||||
}
|
||||
|
||||
func BuildPresetListXML(sn int, id string) string {
|
||||
return fmt.Sprintf(PresentListXML, sn, id)
|
||||
}
|
||||
|
||||
// BuildRecordInfoXML 获取录像文件列表指令
|
||||
func BuildRecordInfoXML(sn int, id string, start, end int64) string {
|
||||
return fmt.Sprintf(RecordInfoXML, sn, id, intTotime(start).Format("2006-01-02T15:04:05"), intTotime(end).Format("2006-01-02T15:04:05"))
|
||||
@@ -90,3 +105,13 @@ var (
|
||||
func BuildAlarmResponseXML(id string) string {
|
||||
return fmt.Sprintf(AlarmResponseXML, id)
|
||||
}
|
||||
|
||||
func XmlEncode(v interface{}) (string, error) {
|
||||
xmlData, err := xml.MarshalIndent(v, "", " ")
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
xml := string(xmlData)
|
||||
xml = `<?xml version="1.0" ?>` + "\n" + xml + "\n"
|
||||
return xml, err
|
||||
}
|
||||
|
||||
@@ -1,15 +1,21 @@
|
||||
package gb28181
|
||||
|
||||
import "io"
|
||||
import (
|
||||
"errors"
|
||||
)
|
||||
|
||||
var ErrNoAvailablePorts = errors.New("no available ports")
|
||||
|
||||
type PortManager struct {
|
||||
recycle chan uint16
|
||||
start uint16
|
||||
max uint16
|
||||
pos uint16
|
||||
Valid bool
|
||||
}
|
||||
|
||||
func (pm *PortManager) Init(start, end uint16) {
|
||||
pm.start = start
|
||||
pm.pos = start - 1
|
||||
pm.max = end
|
||||
if pm.pos > 0 && pm.max > pm.pos {
|
||||
@@ -27,7 +33,7 @@ func (pm *PortManager) Recycle(p uint16) (err error) {
|
||||
case pm.recycle <- p:
|
||||
return nil
|
||||
default:
|
||||
return io.EOF //TODO: 换一个Error
|
||||
return ErrNoAvailablePorts
|
||||
}
|
||||
}
|
||||
|
||||
@@ -41,7 +47,12 @@ func (pm *PortManager) GetPort() (p uint16, err error) {
|
||||
p = pm.pos
|
||||
return
|
||||
} else {
|
||||
return 0, io.EOF //TODO: 换一个Error
|
||||
if conf.Port.Fdm == false {
|
||||
return 0, ErrNoAvailablePorts
|
||||
}
|
||||
pm.pos = pm.start - 1
|
||||
p = pm.pos
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
62
ptz.go
62
ptz.go
@@ -1,6 +1,10 @@
|
||||
package gb28181
|
||||
|
||||
import "fmt"
|
||||
import (
|
||||
"encoding/hex"
|
||||
"encoding/xml"
|
||||
"fmt"
|
||||
)
|
||||
|
||||
var (
|
||||
name2code = map[string]uint8{
|
||||
@@ -18,6 +22,35 @@ var (
|
||||
}
|
||||
)
|
||||
|
||||
type PresetCmd byte
|
||||
|
||||
const (
|
||||
PresetAddPoint = 0
|
||||
PresetDelPoint = 1
|
||||
PresetCallPoint = 2
|
||||
)
|
||||
|
||||
const DeviceControl = "DeviceControl"
|
||||
const PTZFirstByte = 0xA5
|
||||
const (
|
||||
PresetSet = 0x81
|
||||
PresetCall = 0x82
|
||||
PresetDel = 0x83
|
||||
)
|
||||
|
||||
type MessagePtz struct {
|
||||
XMLName xml.Name `xml:"Control"`
|
||||
CmdType string `xml:"CmdType"`
|
||||
SN int `xml:"SN"`
|
||||
DeviceID string `xml:"DeviceID"`
|
||||
PTZCmd string `xml:"PTZCmd"`
|
||||
}
|
||||
|
||||
type Preset struct {
|
||||
CMD byte
|
||||
Point byte
|
||||
}
|
||||
|
||||
func toPtzStrByCmdName(cmdName string, horizontalSpeed, verticalSpeed, zoomSpeed uint8) (string, error) {
|
||||
c, err := toPtzCode(cmdName)
|
||||
if err != nil {
|
||||
@@ -45,3 +78,30 @@ func toPtzCode(cmd string) (uint8, error) {
|
||||
return 0, fmt.Errorf("invalid ptz cmd %q", cmd)
|
||||
}
|
||||
}
|
||||
|
||||
func getVerificationCode(ptz []byte) {
|
||||
sum := uint8(0)
|
||||
for i := 0; i < len(ptz)-1; i++ {
|
||||
sum += ptz[i]
|
||||
}
|
||||
ptz[len(ptz)-1] = sum
|
||||
}
|
||||
|
||||
func getAssembleCode() uint8 {
|
||||
return (PTZFirstByte>>4 + PTZFirstByte&0xF + 0) % 16
|
||||
}
|
||||
|
||||
func Pack(cmd, point byte) string {
|
||||
buf := make([]byte, 8)
|
||||
buf[0] = PTZFirstByte
|
||||
buf[1] = getAssembleCode()
|
||||
buf[2] = 0
|
||||
|
||||
buf[3] = cmd
|
||||
|
||||
buf[4] = 0
|
||||
buf[5] = point
|
||||
buf[6] = 0
|
||||
getVerificationCode(buf)
|
||||
return hex.EncodeToString(buf)
|
||||
}
|
||||
|
||||
43
restful.go
43
restful.go
@@ -122,7 +122,7 @@ func (c *GB28181Config) API_invite(w http.ResponseWriter, r *http.Request) {
|
||||
opt.Validate(startTime, endTime)
|
||||
if c := FindChannel(id, channel); c == nil {
|
||||
util.ReturnError(util.APIErrorNotFound, fmt.Sprintf("device %q channel %q not found", id, channel), w, r)
|
||||
} else if opt.IsLive() && c.status.Load() > 0 {
|
||||
} else if opt.IsLive() && c.State.Load() > 0 {
|
||||
util.ReturnError(util.APIErrorQueryParse, "live stream already exists", w, r)
|
||||
} else if code, err := c.Invite(&opt); err == nil {
|
||||
if code == 200 {
|
||||
@@ -230,6 +230,47 @@ func (c *GB28181Config) API_position(w http.ResponseWriter, r *http.Request) {
|
||||
}
|
||||
}
|
||||
|
||||
func (c *GB28181Config) API_preset_list(w http.ResponseWriter, r *http.Request) {
|
||||
query := r.URL.Query()
|
||||
//设备id
|
||||
id := query.Get("id")
|
||||
//获取通道
|
||||
channel := query.Get("channel")
|
||||
if c := FindChannel(id, channel); c != nil {
|
||||
res, err := c.QueryPresetList()
|
||||
if err == nil {
|
||||
util.ReturnValue(res, w, r)
|
||||
} else {
|
||||
util.ReturnError(util.APIErrorInternal, err.Error(), w, r)
|
||||
}
|
||||
} else {
|
||||
util.ReturnError(util.APIErrorNotFound, fmt.Sprintf("device %q channel %q not found", id, channel), w, r)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func (c *GB28181Config) API_preset_control(w http.ResponseWriter, r *http.Request) {
|
||||
//CORS(w, r)
|
||||
query := r.URL.Query()
|
||||
//设备id
|
||||
id := query.Get("id")
|
||||
//获取通道
|
||||
channel := query.Get("channel")
|
||||
//获取cmd
|
||||
ptzCmd := query.Get("cmd")
|
||||
//获取点
|
||||
point := query.Get("point")
|
||||
|
||||
if c := FindChannel(id, channel); c != nil {
|
||||
_ptzCmd, _ := strconv.ParseInt(ptzCmd, 10, 16)
|
||||
_point, _ := strconv.ParseInt(point, 10, 8)
|
||||
code := c.PresetControl(int(_ptzCmd), byte(_point))
|
||||
util.ReturnError(code, "device received", w, r)
|
||||
} else {
|
||||
util.ReturnError(util.APIErrorNotFound, fmt.Sprintf("device %q channel %q not found", id, channel), w, r)
|
||||
}
|
||||
}
|
||||
|
||||
type DevicePosition struct {
|
||||
ID string
|
||||
GpsTime time.Time //gps时间
|
||||
|
||||
10
server.go
10
server.go
@@ -7,13 +7,13 @@ import (
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/logrusorgru/aurora/v4"
|
||||
"go.uber.org/zap"
|
||||
"m7s.live/plugin/gb28181/v4/utils"
|
||||
|
||||
"github.com/ghettovoice/gosip"
|
||||
"github.com/ghettovoice/gosip/log"
|
||||
"github.com/ghettovoice/gosip/sip"
|
||||
"github.com/logrusorgru/aurora/v4"
|
||||
"go.uber.org/zap"
|
||||
. "m7s.live/engine/v4"
|
||||
"m7s.live/plugin/gb28181/v4/utils"
|
||||
)
|
||||
|
||||
var srv gosip.Server
|
||||
@@ -119,7 +119,7 @@ func (c *GB28181Config) startServer() {
|
||||
addr := c.ListenAddr + ":" + strconv.Itoa(int(c.SipPort))
|
||||
|
||||
logger := utils.NewZapLogger(GB28181Plugin.Logger, "GB SIP Server", nil)
|
||||
logger.SetLevel(uint32(levelMap[c.LogLevel]))
|
||||
logger.SetLevel(uint32(levelMap[EngineConfig.LogLevel]))
|
||||
// logger := log.NewDefaultLogrusLogger().WithPrefix("GB SIP Server")
|
||||
srvConf := gosip.ServerConfig{}
|
||||
if c.SipIP != "" {
|
||||
|
||||
Reference in New Issue
Block a user