mirror of
https://github.com/gowvp/gb28181.git
synced 2026-04-22 23:17:19 +08:00
修改端口范围,支持自动心跳检测
This commit is contained in:
@@ -130,8 +130,8 @@ services:
|
||||
- 10000:10000/udp
|
||||
- 8000:8000/udp
|
||||
- 9000:9000/udp
|
||||
- 20050-20100:20050-20100
|
||||
- 20050-20100:20050-20100/udp
|
||||
- 20000-20300:20000-20300
|
||||
- 20000-20300:20000-20300/udp
|
||||
volumes:
|
||||
- ./configs:/opt/media/conf
|
||||
|
||||
@@ -214,6 +214,7 @@ services:
|
||||
- [x] 按需拉流,节省流量
|
||||
- [x] 视频支持播放 H264 和 H265
|
||||
- [x] 音频支持 g711a/g711u/aac
|
||||
- [x] 与设备侧超时同步,例如设备侧填写超时 3 秒,次数 3 次,则 9+x 秒左右收不到心跳认为离线,x 是检测间隔周期
|
||||
- [ ] 设备云台控制
|
||||
- [ ] 录像回放
|
||||
- [ ] 报警事件订阅
|
||||
|
||||
@@ -4,11 +4,11 @@ go 1.24
|
||||
|
||||
require (
|
||||
github.com/DATA-DOG/go-sqlmock v1.5.2
|
||||
github.com/gin-contrib/gzip v1.2.0
|
||||
github.com/gin-contrib/gzip v1.2.2
|
||||
github.com/gin-gonic/gin v1.10.0
|
||||
github.com/glebarez/sqlite v1.11.0
|
||||
github.com/google/wire v0.6.0
|
||||
github.com/ixugo/goweb v1.0.19
|
||||
github.com/ixugo/goweb v1.0.21
|
||||
github.com/jinzhu/copier v0.4.0
|
||||
github.com/pelletier/go-toml/v2 v2.2.3
|
||||
github.com/shirou/gopsutil v3.21.11+incompatible
|
||||
@@ -17,9 +17,9 @@ require (
|
||||
)
|
||||
|
||||
require (
|
||||
github.com/bytedance/sonic v1.12.7 // indirect
|
||||
github.com/bytedance/sonic/loader v0.2.2 // indirect
|
||||
github.com/cloudwego/base64x v0.1.4 // indirect
|
||||
github.com/bytedance/sonic v1.13.2 // indirect
|
||||
github.com/bytedance/sonic/loader v0.2.4 // indirect
|
||||
github.com/cloudwego/base64x v0.1.5 // indirect
|
||||
github.com/dustin/go-humanize v1.0.1 // indirect
|
||||
github.com/gabriel-vasile/mimetype v1.4.8 // indirect
|
||||
github.com/gin-contrib/sse v1.0.0 // indirect
|
||||
@@ -27,8 +27,8 @@ require (
|
||||
github.com/go-ole/go-ole v1.2.6 // indirect
|
||||
github.com/go-playground/locales v0.14.1 // indirect
|
||||
github.com/go-playground/universal-translator v0.18.1 // indirect
|
||||
github.com/go-playground/validator/v10 v10.24.0 // indirect
|
||||
github.com/goccy/go-json v0.10.4 // indirect
|
||||
github.com/go-playground/validator/v10 v10.25.0 // indirect
|
||||
github.com/goccy/go-json v0.10.5 // indirect
|
||||
github.com/gofrs/uuid v4.4.0+incompatible
|
||||
github.com/golang-jwt/jwt/v4 v4.5.1 // indirect
|
||||
github.com/google/uuid v1.6.0 // indirect
|
||||
@@ -39,7 +39,7 @@ require (
|
||||
github.com/jinzhu/inflection v1.0.0 // indirect
|
||||
github.com/jinzhu/now v1.1.5 // indirect
|
||||
github.com/json-iterator/go v1.1.12 // indirect
|
||||
github.com/klauspost/cpuid/v2 v2.2.9 // indirect
|
||||
github.com/klauspost/cpuid/v2 v2.2.10 // indirect
|
||||
github.com/leodido/go-urn v1.4.0 // indirect
|
||||
github.com/lestrrat-go/file-rotatelogs v2.4.0+incompatible // indirect
|
||||
github.com/lestrrat-go/strftime v1.1.0 // indirect
|
||||
@@ -58,15 +58,15 @@ require (
|
||||
go.uber.org/multierr v1.11.0 // indirect
|
||||
go.uber.org/zap v1.27.0 // indirect
|
||||
go.uber.org/zap/exp v0.3.0 // indirect
|
||||
golang.org/x/arch v0.13.0 // indirect
|
||||
golang.org/x/crypto v0.32.0 // indirect
|
||||
golang.org/x/arch v0.15.0 // indirect
|
||||
golang.org/x/crypto v0.36.0 // indirect
|
||||
golang.org/x/exp v0.0.0-20241217172543-b2144cdd0a67 // indirect
|
||||
golang.org/x/net v0.34.0 // indirect
|
||||
golang.org/x/sync v0.10.0 // indirect
|
||||
golang.org/x/sys v0.29.0 // indirect
|
||||
golang.org/x/text v0.21.0
|
||||
golang.org/x/net v0.38.0 // indirect
|
||||
golang.org/x/sync v0.12.0 // indirect
|
||||
golang.org/x/sys v0.31.0 // indirect
|
||||
golang.org/x/text v0.23.0
|
||||
golang.org/x/time v0.8.0 // indirect
|
||||
google.golang.org/protobuf v1.36.2 // indirect
|
||||
google.golang.org/protobuf v1.36.6 // indirect
|
||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||
modernc.org/libc v1.61.5 // indirect
|
||||
modernc.org/mathutil v1.7.1 // indirect
|
||||
|
||||
@@ -2,11 +2,17 @@ github.com/DATA-DOG/go-sqlmock v1.5.2 h1:OcvFkGmslmlZibjAjaHm3L//6LiuBgolP7Oputl
|
||||
github.com/DATA-DOG/go-sqlmock v1.5.2/go.mod h1:88MAG/4G7SMwSE3CeA0ZKzrT5CiOU3OJ+JlNzwDqpNU=
|
||||
github.com/bytedance/sonic v1.12.7 h1:CQU8pxOy9HToxhndH0Kx/S1qU/CuS9GnKYrGioDcU1Q=
|
||||
github.com/bytedance/sonic v1.12.7/go.mod h1:tnbal4mxOMju17EGfknm2XyYcpyCnIROYOEYuemj13I=
|
||||
github.com/bytedance/sonic v1.13.2 h1:8/H1FempDZqC4VqjptGo14QQlJx8VdZJegxs6wwfqpQ=
|
||||
github.com/bytedance/sonic v1.13.2/go.mod h1:o68xyaF9u2gvVBuGHPlUVCy+ZfmNNO5ETf1+KgkJhz4=
|
||||
github.com/bytedance/sonic/loader v0.1.1/go.mod h1:ncP89zfokxS5LZrJxl5z0UJcsk4M4yY2JpfqGeCtNLU=
|
||||
github.com/bytedance/sonic/loader v0.2.2 h1:jxAJuN9fOot/cyz5Q6dUuMJF5OqQ6+5GfA8FjjQ0R4o=
|
||||
github.com/bytedance/sonic/loader v0.2.2/go.mod h1:N8A3vUdtUebEY2/VQC0MyhYeKUFosQU6FxH2JmUe6VI=
|
||||
github.com/bytedance/sonic/loader v0.2.4 h1:ZWCw4stuXUsn1/+zQDqeE7JKP+QO47tz7QCNan80NzY=
|
||||
github.com/bytedance/sonic/loader v0.2.4/go.mod h1:N8A3vUdtUebEY2/VQC0MyhYeKUFosQU6FxH2JmUe6VI=
|
||||
github.com/cloudwego/base64x v0.1.4 h1:jwCgWpFanWmN8xoIUHa2rtzmkd5J2plF/dnLS6Xd/0Y=
|
||||
github.com/cloudwego/base64x v0.1.4/go.mod h1:0zlkT4Wn5C6NdauXdJRhSKRlJvmclQ1hhJgA0rcu/8w=
|
||||
github.com/cloudwego/base64x v0.1.5 h1:XPciSp1xaq2VCSt6lF0phncD4koWyULpl5bUxbfCyP4=
|
||||
github.com/cloudwego/base64x v0.1.5/go.mod h1:0zlkT4Wn5C6NdauXdJRhSKRlJvmclQ1hhJgA0rcu/8w=
|
||||
github.com/cloudwego/iasm v0.2.0/go.mod h1:8rXZaNYT2n95jn+zTI1sDr+IgcD2GVs0nlbbQPiEFhY=
|
||||
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=
|
||||
@@ -17,6 +23,8 @@ github.com/gabriel-vasile/mimetype v1.4.8 h1:FfZ3gj38NjllZIeJAmMhr+qKL8Wu+nOoI3G
|
||||
github.com/gabriel-vasile/mimetype v1.4.8/go.mod h1:ByKUIKGjh1ODkGM1asKUbQZOLGrPjydw3hYPU2YU9t8=
|
||||
github.com/gin-contrib/gzip v1.2.0 h1:JzN6DT3/xYL5zAdviN1ORNzKeklrwafXCIDKIR+qmUA=
|
||||
github.com/gin-contrib/gzip v1.2.0/go.mod h1:C1a5cacjlDsS20cKnHlZRCPUu57D3qH6B2pV0rl+Y/s=
|
||||
github.com/gin-contrib/gzip v1.2.2 h1:iUU/EYCM8ENfkjmZaVrxbjF/ZC267Iqv5S0MMCMEliI=
|
||||
github.com/gin-contrib/gzip v1.2.2/go.mod h1:C1a5cacjlDsS20cKnHlZRCPUu57D3qH6B2pV0rl+Y/s=
|
||||
github.com/gin-contrib/sse v1.0.0 h1:y3bT1mUWUxDpW4JLQg/HnTqV4rozuW4tC9eFKTxYI9E=
|
||||
github.com/gin-contrib/sse v1.0.0/go.mod h1:zNuFdwarAygJBht0NTKiSi3jRf6RbqeILZ9Sp6Slhe0=
|
||||
github.com/gin-gonic/gin v1.10.0 h1:nTuyha1TYqgedzytsKYqna+DfLos46nTv2ygFy86HFU=
|
||||
@@ -35,8 +43,12 @@ github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJn
|
||||
github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY=
|
||||
github.com/go-playground/validator/v10 v10.24.0 h1:KHQckvo8G6hlWnrPX4NJJ+aBfWNAE/HH+qdL2cBpCmg=
|
||||
github.com/go-playground/validator/v10 v10.24.0/go.mod h1:GGzBIJMuE98Ic/kJsBXbz1x/7cByt++cQ+YOuDM5wus=
|
||||
github.com/go-playground/validator/v10 v10.25.0 h1:5Dh7cjvzR7BRZadnsVOzPhWsrwUr0nmsZJxEAnFLNO8=
|
||||
github.com/go-playground/validator/v10 v10.25.0/go.mod h1:GGzBIJMuE98Ic/kJsBXbz1x/7cByt++cQ+YOuDM5wus=
|
||||
github.com/goccy/go-json v0.10.4 h1:JSwxQzIqKfmFX1swYPpUThQZp/Ka4wzJdK0LWVytLPM=
|
||||
github.com/goccy/go-json v0.10.4/go.mod h1:oq7eo15ShAhp70Anwd5lgX2pLfOS3QCiwU/PULtXL6M=
|
||||
github.com/goccy/go-json v0.10.5 h1:Fq85nIqj+gXn/S5ahsiTlK3TmC85qgirsdTP/+DeaC4=
|
||||
github.com/goccy/go-json v0.10.5/go.mod h1:oq7eo15ShAhp70Anwd5lgX2pLfOS3QCiwU/PULtXL6M=
|
||||
github.com/gofrs/uuid v4.4.0+incompatible h1:3qXRTX8/NbyulANqlc0lchS1gqAVxRgsuW1YrTJupqA=
|
||||
github.com/gofrs/uuid v4.4.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM=
|
||||
github.com/golang-jwt/jwt/v4 v4.5.1 h1:JdqV9zKUdtaa9gdPlywC3aeoEsR681PlKC+4F5gQgeo=
|
||||
@@ -54,6 +66,8 @@ github.com/google/wire v0.6.0 h1:HBkoIh4BdSxoyo9PveV8giw7ZsaBOvzWKfcg/6MrVwI=
|
||||
github.com/google/wire v0.6.0/go.mod h1:F4QhpQ9EDIdJ1Mbop/NZBRB+5yrR6qg3BnctaoUk6NA=
|
||||
github.com/ixugo/goweb v1.0.19 h1:q5pIAANBNxZdCSZfRamekqJByt1U3BCHXA0mcCFiioE=
|
||||
github.com/ixugo/goweb v1.0.19/go.mod h1:iBwaaazAtvEuuODjnoCR/5bssvTi49Eft6x8ULg/jsg=
|
||||
github.com/ixugo/goweb v1.0.21 h1:Bi437yjO+6hJupm+rRXI0u344LIwDDXUCoSNX+oG8Mg=
|
||||
github.com/ixugo/goweb v1.0.21/go.mod h1:6bUJpmDB6SGMdLyYF5EouHCmHKVYA8Od675JX6twaA4=
|
||||
github.com/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsIM=
|
||||
github.com/jackc/pgpassfile v1.0.0/go.mod h1:CEx0iS5ambNFdcRtxPj5JhEz+xB6uRky5eyVu/W2HEg=
|
||||
github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 h1:iCEnooe7UlwOQYpKFhBabPMi4aNAfoODPEFNiAnClxo=
|
||||
@@ -76,6 +90,8 @@ github.com/kisielk/sqlstruct v0.0.0-20201105191214-5f3e10d3ab46/go.mod h1:yyMNCy
|
||||
github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg=
|
||||
github.com/klauspost/cpuid/v2 v2.2.9 h1:66ze0taIn2H33fBvCkXuv9BmCwDfafmiIVpKV9kKGuY=
|
||||
github.com/klauspost/cpuid/v2 v2.2.9/go.mod h1:rqkxqrZ1EhYM9G+hXH7YdowN5R5RGN6NK4QwQ3WMXF8=
|
||||
github.com/klauspost/cpuid/v2 v2.2.10 h1:tBs3QSyvjDyFTq3uoc/9xFpCuOsJQFNPiAhYdw2skhE=
|
||||
github.com/klauspost/cpuid/v2 v2.2.10/go.mod h1:hqwkgyIinND0mEev00jJYCxPNVRVXFQeu1XKlok6oO0=
|
||||
github.com/knz/go-libedit v1.10.1/go.mod h1:MZTVkCWyz0oBc7JOWP3wNAzd002ZbM/5hgShxwh4x8M=
|
||||
github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0=
|
||||
github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk=
|
||||
@@ -145,12 +161,16 @@ go.uber.org/zap/exp v0.3.0 h1:6JYzdifzYkGmTdRR59oYH+Ng7k49H9qVpWwNSsGJj3U=
|
||||
go.uber.org/zap/exp v0.3.0/go.mod h1:5I384qq7XGxYyByIhHm6jg5CHkGY0nsTfbDLgDDlgJQ=
|
||||
golang.org/x/arch v0.13.0 h1:KCkqVVV1kGg0X87TFysjCJ8MxtZEIU4Ja/yXGeoECdA=
|
||||
golang.org/x/arch v0.13.0/go.mod h1:FEVrYAQjsQXMVJ1nsMoVVXPZg6p2JE2mx8psSWTDQys=
|
||||
golang.org/x/arch v0.15.0 h1:QtOrQd0bTUnhNVNndMpLHNWrDmYzZ2KDqSrEymqInZw=
|
||||
golang.org/x/arch v0.15.0/go.mod h1:JmwW7aLIoRUKgaTzhkiEFxvcEiQGyOg9BMonBJUS7EE=
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
||||
golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliYc=
|
||||
golang.org/x/crypto v0.18.0/go.mod h1:R0j02AL6hcrfOiy9T4ZYp/rcWeMxM3L6QYxlOuEG1mg=
|
||||
golang.org/x/crypto v0.32.0 h1:euUpcYgM8WcP71gNpTqQCn6rC2t6ULUPiOzfWaXVVfc=
|
||||
golang.org/x/crypto v0.32.0/go.mod h1:ZnnJkOaASj8g0AjIduWNlq2NRxL0PlBrbKVyZ6V/Ugc=
|
||||
golang.org/x/crypto v0.36.0 h1:AnAEvhDddvBdpY+uR+MyHmuZzzNqXSe/GvuDeob5L34=
|
||||
golang.org/x/crypto v0.36.0/go.mod h1:Y4J0ReaxCR1IMaabaSMugxJES1EpwhBHhv2bDHklZvc=
|
||||
golang.org/x/exp v0.0.0-20241217172543-b2144cdd0a67 h1:1UoZQm6f0P/ZO0w1Ri+f+ifG/gXhegadRdwBIXEFWDo=
|
||||
golang.org/x/exp v0.0.0-20241217172543-b2144cdd0a67/go.mod h1:qj5a5QZpwLU2NLQudwIN5koi3beDhSAlJwa67PuM98c=
|
||||
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
|
||||
@@ -168,6 +188,8 @@ golang.org/x/net v0.15.0/go.mod h1:idbUs1IY1+zTqbi8yxTbhexhEEk5ur9LInksu6HrEpk=
|
||||
golang.org/x/net v0.20.0/go.mod h1:z8BVo6PvndSri0LbOE3hAn0apkU+1YvI6E70E9jsnvY=
|
||||
golang.org/x/net v0.34.0 h1:Mb7Mrk043xzHgnRM88suvJFwzVrRfHEHJEl5/71CKw0=
|
||||
golang.org/x/net v0.34.0/go.mod h1:di0qlW3YNM5oh6GqDGQr92MyTozJPmybPK4Ev/Gm31k=
|
||||
golang.org/x/net v0.38.0 h1:vRMAPTMaeGqVhG5QyLJHqNDwecKTomGeqbnfZyKlBI8=
|
||||
golang.org/x/net v0.38.0/go.mod h1:ivrbrMbzFq5J41QOQh0siUuly180yBYtLp+CKbEaFx8=
|
||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
@@ -175,6 +197,8 @@ golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y=
|
||||
golang.org/x/sync v0.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
||||
golang.org/x/sync v0.10.0 h1:3NQrjDixjgGwUOCaF8w2+VYHv0Ve/vGYSbdkTa98gmQ=
|
||||
golang.org/x/sync v0.10.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
||||
golang.org/x/sync v0.12.0 h1:MHc5BpPuC30uJk597Ri8TV3CNZcTLu6B6z4lJy+g6Jw=
|
||||
golang.org/x/sync v0.12.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA=
|
||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
@@ -188,6 +212,8 @@ golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.16.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/sys v0.29.0 h1:TPYlXGxvx1MGTn2GiZDhnjPA9wZzZeGKHHmKhHYvgaU=
|
||||
golang.org/x/sys v0.29.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/sys v0.31.0 h1:ioabZlmFYtWhL+TRYpcnNlLwhyxaM9kWTDEmfnprqik=
|
||||
golang.org/x/sys v0.31.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
|
||||
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.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
|
||||
@@ -203,6 +229,8 @@ golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
|
||||
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
|
||||
golang.org/x/text v0.21.0 h1:zyQAAkrwaneQ066sspRyJaG9VNi/YJ1NfzcGB3hZ/qo=
|
||||
golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ=
|
||||
golang.org/x/text v0.23.0 h1:D71I7dUrlY+VX0gQShAThNGHFxZ13dGLBHQLVl1mJlY=
|
||||
golang.org/x/text v0.23.0/go.mod h1:/BLNzu4aZCJ1+kcD0DNRotWKage4q2rGVAg4o22unh4=
|
||||
golang.org/x/time v0.8.0 h1:9i3RxcPv3PZnitoVGMPDKZSq1xW1gK1Xy3ArNOGZfEg=
|
||||
golang.org/x/time v0.8.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM=
|
||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
@@ -216,6 +244,8 @@ golang.org/x/tools v0.28.0/go.mod h1:dcIOrVd3mfQKTgrDVQHqCPMWy6lnhfhtX3hLXYVLfRw
|
||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
google.golang.org/protobuf v1.36.2 h1:R8FeyR1/eLmkutZOM5CWghmo5itiG9z0ktFlTVLuTmU=
|
||||
google.golang.org/protobuf v1.36.2/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE=
|
||||
google.golang.org/protobuf v1.36.6 h1:z1NpPI8ku2WgiWnf+t9wTPsn6eP1L7ksHUlkfLvd9xY=
|
||||
google.golang.org/protobuf v1.36.6/go.mod h1:jduwjTPXsFjZGTmRluh+L6NjiWu7pchiJ2/5YcXBHnY=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
|
||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
|
||||
|
||||
@@ -56,6 +56,11 @@ func (c *Cache) LoadDeviceToMemory(conn sip.Connection) {
|
||||
|
||||
dev := gbs.NewDevice(conn, d)
|
||||
if dev != nil {
|
||||
if err := dev.CheckConnection(); err != nil {
|
||||
slog.Warn("检查设备连接失败", "err", err, "device_id", d.DeviceID, "to", dev.To())
|
||||
continue
|
||||
}
|
||||
|
||||
slog.Debug("load device to memory", "device_id", d.DeviceID, "to", dev.To())
|
||||
channels := make([]*gb28181.Channel, 0, 8)
|
||||
_, err := c.Storer.Channel().Find(context.TODO(), &channels, web.NewPagerFilterMaxSize(), orm.Where("device_id=?", d.DeviceID))
|
||||
|
||||
@@ -126,7 +126,7 @@ func (n *NodeManager) connection(server *MediaServer, serverPort int) {
|
||||
|
||||
log.Info("ZLM 服务节点连接中")
|
||||
|
||||
for i := range 10 {
|
||||
for i := range 5 {
|
||||
resp, err := engine.GetServerConfig()
|
||||
if err != nil {
|
||||
log.Error("ZLM 服务节点连接失败", "err", err, "retry", i)
|
||||
|
||||
@@ -0,0 +1,138 @@
|
||||
package gbs
|
||||
|
||||
import (
|
||||
"encoding/hex"
|
||||
"encoding/xml"
|
||||
"log/slog"
|
||||
"math"
|
||||
|
||||
"github.com/gowvp/gb28181/pkg/gbs/sip"
|
||||
)
|
||||
|
||||
// 配置参数类型常量定义
|
||||
const (
|
||||
// basicParam 基本参数配置
|
||||
basicParam = "BasicParam"
|
||||
// videoParamOpt 视频参数范围配置
|
||||
// videoParamOpt = "VideoParamOpt"
|
||||
// // SVACEncodeConfig SVAC编码配置
|
||||
// SVACEncodeConfig = "SVACEncodeConfig"
|
||||
// // SVACDecodeConfig SVAC解码配置
|
||||
// SVACDecodeConfig = "SVACDecodeConfig"
|
||||
// // videoParamAttribute 视频参数属性配置
|
||||
// videoParamAttribute = "VideoParamAttribute"
|
||||
// // videoRecordPlan 录像计划
|
||||
// videoRecordPlan = "VideoRecordPlan"
|
||||
// // videoAlarmRecord 报警录像
|
||||
// videoAlarmRecord = "VideoAlarmRecord"
|
||||
// // pictureMask 视频画面遮挡
|
||||
// pictureMask = "PictureMask"
|
||||
// // frameMirror 画面翻转
|
||||
// frameMirror = "FrameMirror"
|
||||
// // AlarmReport 报警上报开关
|
||||
// AlarmReport = "AlarmReport"
|
||||
// // OSDConfig 前端OSD设置
|
||||
// OSDConfig = "OSDConfig"
|
||||
// // SnapShotConfig 图像抓拍配置
|
||||
// SnapShotConfig = "SnapShotConfig"
|
||||
)
|
||||
|
||||
type ConfigDownloadRequest struct {
|
||||
XMLName xml.Name `xml:"Query"`
|
||||
CmdType string `xml:"CmdType"` // 命令类型:设备配置查询(必选)
|
||||
SN int32 `xml:"SN"` // 命令序列号(必选)
|
||||
DeviceID string `xml:"DeviceID"` // 目标设备编码(必选)
|
||||
ConfigType string `xml:"ConfigType"` // 查询配置参数类型(必选)
|
||||
}
|
||||
|
||||
type ConfigDownloadResponse struct {
|
||||
XMLName xml.Name `xml:"Response"`
|
||||
CmdType string `xml:"CmdType"`
|
||||
SN int `xml:"SN"`
|
||||
DeviceID string `xml:"DeviceID"`
|
||||
Result string `xml:"Result"`
|
||||
BasicParam *BasicParam `xml:"BasicParam"`
|
||||
// VideoParamOpt *VideoParamOpt `xml:"VideoParamOpt"`
|
||||
// SVACEncodeConfig *SVACEncodeConfig `xml:"SVACEncodeConfig"`
|
||||
// SVACDecodeConfig *SVACDecodeConfig `xml:"SVACDecodeConfig"`
|
||||
// VideoParamAttribute *VideoParamAttribute `xml:"VideoParamAttribute"`
|
||||
// VideoRecordPlan *VideoRecordPlan `xml:"VideoRecordPlan"`
|
||||
// VideoAlarmRecord *VideoAlarmRecord `xml:"VideoAlarmRecord"`
|
||||
// PictureMask *PictureMask `xml:"PictureMask"`
|
||||
// FrameMirror *FrameMirror `xml:"FrameMirror"`
|
||||
// AlarmReport *AlarmReport `xml:"AlarmReport"`
|
||||
// OSDConfig *OSDConfig `xml:"OSDConfig"`
|
||||
// SnapShot *SnapShot `xml:"SnapShot"`
|
||||
}
|
||||
|
||||
// BasicParam 设备基本参数配置
|
||||
type BasicParam struct {
|
||||
Name string `xml:"Name"` // 设备名称
|
||||
Expiration int `xml:"Expiration"` // 注册过期时间
|
||||
HeartBeatInterval int `xml:"HeartBeatInterval"` // 心跳间隔时间
|
||||
HeartBeatCount int `xml:"HeartBeatCount"` // 心跳超时次数
|
||||
}
|
||||
|
||||
func NewConfigDownloadRequest(sn int32, deviceID string, configType string) []byte {
|
||||
c := ConfigDownloadRequest{
|
||||
CmdType: "ConfigDownload",
|
||||
SN: sn,
|
||||
DeviceID: deviceID,
|
||||
ConfigType: configType,
|
||||
}
|
||||
xmlData, _ := sip.XMLEncode(c)
|
||||
return xmlData
|
||||
}
|
||||
|
||||
func (g *GB28181API) QueryConfigDownloadBasic(deviceID, configType string) error {
|
||||
slog.Debug("QueryConfigDownloadBasic", "deviceID", deviceID)
|
||||
ipc, ok := g.svr.memoryStorer.Load(deviceID)
|
||||
if !ok {
|
||||
return ErrDeviceOffline
|
||||
}
|
||||
|
||||
tx, err := g.svr.wrapRequest(ipc, sip.MethodMessage, &sip.ContentTypeXML, NewConfigDownloadRequest(1, deviceID, configType))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
_, err = sipResponse(tx)
|
||||
return err
|
||||
}
|
||||
|
||||
func (g *GB28181API) sipMessageConfigDownload(ctx *sip.Context) {
|
||||
slog.Debug("sipMessageConfigDownload", "deviceID", ctx.DeviceID)
|
||||
|
||||
var msg ConfigDownloadResponse
|
||||
if err := sip.XMLDecode(ctx.Request.Body(), &msg); err != nil {
|
||||
ctx.Log.Error("sipMessageConfigDownload", "err", err, "body", hex.EncodeToString(ctx.Request.Body()))
|
||||
ctx.String(400, ErrXMLDecode.Error())
|
||||
return
|
||||
}
|
||||
|
||||
if msg.BasicParam != nil {
|
||||
ipc, ok := g.svr.memoryStorer.Load(ctx.DeviceID)
|
||||
if !ok {
|
||||
ctx.Log.Debug("sipMessageConfigDownload", "deviceID", ctx.DeviceID, "err", "device offline")
|
||||
return
|
||||
}
|
||||
|
||||
// 确保 HeartBeatCount 在合法范围内
|
||||
if msg.BasicParam.HeartBeatCount > math.MaxUint16 {
|
||||
msg.BasicParam.HeartBeatCount = math.MaxUint16
|
||||
}
|
||||
if msg.BasicParam.HeartBeatInterval > math.MaxUint16 {
|
||||
msg.BasicParam.HeartBeatInterval = math.MaxUint16
|
||||
}
|
||||
if msg.BasicParam.HeartBeatCount <= 0 {
|
||||
msg.BasicParam.HeartBeatCount = 1
|
||||
}
|
||||
// 计算设备离线超时时间
|
||||
if msg.BasicParam.HeartBeatInterval*msg.BasicParam.HeartBeatCount > 0 {
|
||||
ipc.keepaliveInterval = uint16(msg.BasicParam.HeartBeatInterval) // nolint
|
||||
ipc.keepaliveTimeout = uint16(msg.BasicParam.HeartBeatCount) // nolint
|
||||
ctx.Log.Debug("sipMessageConfigDownload update", "deviceID", ctx.DeviceID, "keepaliveInterval", ipc.keepaliveInterval, "keepaliveTimeout", ipc.keepaliveTimeout)
|
||||
}
|
||||
}
|
||||
|
||||
ctx.String(200, "OK")
|
||||
}
|
||||
@@ -38,6 +38,9 @@ type Device struct {
|
||||
LastKeepaliveAt time.Time
|
||||
LastRegisterAt time.Time
|
||||
Expires int
|
||||
|
||||
keepaliveInterval uint16
|
||||
keepaliveTimeout uint16
|
||||
}
|
||||
|
||||
func NewDevice(conn sip.Connection, d *gb28181.Device) *Device {
|
||||
@@ -70,6 +73,22 @@ func NewDevice(conn sip.Connection, d *gb28181.Device) *Device {
|
||||
return &c
|
||||
}
|
||||
|
||||
// CheckConnection 检查 udp 设备能否通信
|
||||
func (d *Device) CheckConnection() error {
|
||||
const timeout = 2 * time.Second
|
||||
|
||||
if d.source.Network() == "tcp" {
|
||||
return nil
|
||||
}
|
||||
// 创建临时UDP连接进行检查
|
||||
tempConn, err := net.DialTimeout("udp", d.source.String(), timeout)
|
||||
if err != nil {
|
||||
return fmt.Errorf("UDP连接失败: %w", err)
|
||||
}
|
||||
defer tempConn.Close()
|
||||
return nil
|
||||
}
|
||||
|
||||
func (d *Device) LoadChannels(channels ...*gb28181.Channel) {
|
||||
for _, channel := range channels {
|
||||
ch := Channel{
|
||||
|
||||
+3
-1
@@ -1,6 +1,8 @@
|
||||
package gbs
|
||||
|
||||
import (
|
||||
"encoding/hex"
|
||||
|
||||
"github.com/gowvp/gb28181/internal/core/gb28181"
|
||||
"github.com/gowvp/gb28181/pkg/gbs/sip"
|
||||
)
|
||||
@@ -36,7 +38,7 @@ type MessageDeviceInfoResponse struct {
|
||||
func (g GB28181API) sipMessageDeviceInfo(ctx *sip.Context) {
|
||||
var msg MessageDeviceInfoResponse
|
||||
if err := sip.XMLDecode(ctx.Request.Body(), &msg); err != nil {
|
||||
ctx.Log.Error("sipMessageDeviceInfo", "err", err)
|
||||
ctx.Log.Error("sipMessageDeviceInfo", "err", err, "body", hex.EncodeToString(ctx.Request.Body()))
|
||||
ctx.String(400, ErrXMLDecode.Error())
|
||||
return
|
||||
}
|
||||
|
||||
+145
-147
@@ -1,11 +1,9 @@
|
||||
package gbs
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"net"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/gowvp/gb28181/internal/core/gb28181"
|
||||
"github.com/gowvp/gb28181/internal/core/sms"
|
||||
@@ -202,167 +200,167 @@ func (g *GB28181API) sipPlayPush2(ch *Channel, in *PlayInput, port int, stream *
|
||||
}
|
||||
|
||||
// sip 请求播放
|
||||
func SipPlay(data *Streams) (*Streams, error) {
|
||||
channel := Channels{ChannelID: data.ChannelID}
|
||||
// if err := db.Get(db.DBClient, &channel); err != nil {
|
||||
// if db.RecordNotFound(err) {
|
||||
// return nil, errors.New("通道不存在")
|
||||
// }
|
||||
// return nil, err
|
||||
// }
|
||||
// func SipPlay(data *Streams) (*Streams, error) {
|
||||
// channel := Channels{ChannelID: data.ChannelID}
|
||||
// // if err := db.Get(db.DBClient, &channel); err != nil {
|
||||
// // if db.RecordNotFound(err) {
|
||||
// // return nil, errors.New("通道不存在")
|
||||
// // }
|
||||
// // return nil, err
|
||||
// // }
|
||||
|
||||
data.DeviceID = channel.DeviceID
|
||||
data.StreamType = channel.StreamType
|
||||
// 使用通道的播放模式进行处理
|
||||
switch channel.StreamType {
|
||||
case m.StreamTypePull:
|
||||
// 拉流
|
||||
// data.DeviceID = channel.DeviceID
|
||||
// data.StreamType = channel.StreamType
|
||||
// // 使用通道的播放模式进行处理
|
||||
// switch channel.StreamType {
|
||||
// case m.StreamTypePull:
|
||||
// // 拉流
|
||||
|
||||
default:
|
||||
// 推流模式要求设备在线且活跃
|
||||
if time.Now().Unix()-channel.Active > 30*60 || channel.Status != m.DeviceStatusON {
|
||||
return nil, errors.New("通道已离线")
|
||||
}
|
||||
user, ok := _activeDevices.Get(channel.DeviceID)
|
||||
if !ok {
|
||||
return nil, errors.New("设备已离线")
|
||||
}
|
||||
// GB28181推流
|
||||
if data.StreamID == "" {
|
||||
ssrcLock.Lock()
|
||||
// data.ssrc =g. getSSRC(data.T)
|
||||
data.StreamID = ssrc2stream(data.ssrc)
|
||||
// default:
|
||||
// // 推流模式要求设备在线且活跃
|
||||
// if time.Now().Unix()-channel.Active > 30*60 || channel.Status != m.DeviceStatusON {
|
||||
// return nil, errors.New("通道已离线")
|
||||
// }
|
||||
// user, ok := _activeDevices.Get(channel.DeviceID)
|
||||
// if !ok {
|
||||
// return nil, errors.New("设备已离线")
|
||||
// }
|
||||
// // GB28181推流
|
||||
// if data.StreamID == "" {
|
||||
// ssrcLock.Lock()
|
||||
// // data.ssrc =g. getSSRC(data.T)
|
||||
// data.StreamID = ssrc2stream(data.ssrc)
|
||||
|
||||
// 成功后保存
|
||||
// db.Create(db.DBClient, data)
|
||||
ssrcLock.Unlock()
|
||||
}
|
||||
// // 成功后保存
|
||||
// // db.Create(db.DBClient, data)
|
||||
// ssrcLock.Unlock()
|
||||
// }
|
||||
|
||||
var err error
|
||||
data, err = sipPlayPush(data, channel, user)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("获取视频失败:%v", err)
|
||||
}
|
||||
}
|
||||
// var err error
|
||||
// data, err = sipPlayPush(data, channel, user)
|
||||
// if err != nil {
|
||||
// return nil, fmt.Errorf("获取视频失败:%v", err)
|
||||
// }
|
||||
// }
|
||||
|
||||
data.HTTP = fmt.Sprintf("%s/rtp/%s/hls.m3u8", config.Media.HTTP, data.StreamID)
|
||||
data.RTMP = fmt.Sprintf("%s/rtp/%s", config.Media.RTMP, data.StreamID)
|
||||
data.RTSP = fmt.Sprintf("%s/rtp/%s", config.Media.RTSP, data.StreamID)
|
||||
data.WSFLV = fmt.Sprintf("%s/rtp/%s.live.flv", config.Media.WS, data.StreamID)
|
||||
// data.HTTP = fmt.Sprintf("%s/rtp/%s/hls.m3u8", config.Media.HTTP, data.StreamID)
|
||||
// data.RTMP = fmt.Sprintf("%s/rtp/%s", config.Media.RTMP, data.StreamID)
|
||||
// data.RTSP = fmt.Sprintf("%s/rtp/%s", config.Media.RTSP, data.StreamID)
|
||||
// data.WSFLV = fmt.Sprintf("%s/rtp/%s.live.flv", config.Media.WS, data.StreamID)
|
||||
|
||||
data.Ext = time.Now().Unix() + 2*60 // 2分钟等待时间
|
||||
StreamList.Response.Store(data.StreamID, data)
|
||||
if data.T == 0 {
|
||||
StreamList.Succ.Store(data.ChannelID, data)
|
||||
}
|
||||
// db.Save(db.DBClient, data)
|
||||
return data, nil
|
||||
}
|
||||
// data.Ext = time.Now().Unix() + 2*60 // 2分钟等待时间
|
||||
// StreamList.Response.Store(data.StreamID, data)
|
||||
// if data.T == 0 {
|
||||
// StreamList.Succ.Store(data.ChannelID, data)
|
||||
// }
|
||||
// // db.Save(db.DBClient, data)
|
||||
// return data, nil
|
||||
// }
|
||||
|
||||
var ssrcLock *sync.Mutex
|
||||
|
||||
func sipPlayPush(data *Streams, channel Channels, device Devices) (*Streams, error) {
|
||||
var (
|
||||
s sdp.Session
|
||||
b []byte
|
||||
)
|
||||
name := "Play"
|
||||
protocal := "TCP/RTP/AVP"
|
||||
if data.T == 1 {
|
||||
name = "Playback"
|
||||
protocal = "RTP/RTCP"
|
||||
}
|
||||
// func sipPlayPush(data *Streams, channel Channels, device Devices) (*Streams, error) {
|
||||
// var (
|
||||
// s sdp.Session
|
||||
// b []byte
|
||||
// )
|
||||
// name := "Play"
|
||||
// protocal := "TCP/RTP/AVP"
|
||||
// if data.T == 1 {
|
||||
// name = "Playback"
|
||||
// protocal = "RTP/RTCP"
|
||||
// }
|
||||
|
||||
video := sdp.Media{
|
||||
Description: sdp.MediaDescription{
|
||||
Type: "video",
|
||||
Port: _sysinfo.MediaServerRtpPort,
|
||||
Formats: []string{"96", "98", "97"},
|
||||
Protocol: protocal,
|
||||
},
|
||||
}
|
||||
video.AddAttribute("recvonly")
|
||||
if data.T == 0 {
|
||||
video.AddAttribute("setup", "passive")
|
||||
video.AddAttribute("connection", "new")
|
||||
}
|
||||
video.AddAttribute("rtpmap", "96", "PS/90000")
|
||||
video.AddAttribute("rtpmap", "98", "H264/90000")
|
||||
video.AddAttribute("rtpmap", "97", "MPEG4/90000")
|
||||
// video := sdp.Media{
|
||||
// Description: sdp.MediaDescription{
|
||||
// Type: "video",
|
||||
// Port: _sysinfo.MediaServerRtpPort,
|
||||
// Formats: []string{"96", "98", "97"},
|
||||
// Protocol: protocal,
|
||||
// },
|
||||
// }
|
||||
// video.AddAttribute("recvonly")
|
||||
// if data.T == 0 {
|
||||
// video.AddAttribute("setup", "passive")
|
||||
// video.AddAttribute("connection", "new")
|
||||
// }
|
||||
// video.AddAttribute("rtpmap", "96", "PS/90000")
|
||||
// video.AddAttribute("rtpmap", "98", "H264/90000")
|
||||
// video.AddAttribute("rtpmap", "97", "MPEG4/90000")
|
||||
|
||||
// defining message
|
||||
msg := &sdp.Message{
|
||||
Origin: sdp.Origin{
|
||||
Username: _serverDevices.DeviceID, // 媒体服务器id
|
||||
Address: _sysinfo.MediaServerRtpIP.String(),
|
||||
},
|
||||
Name: name,
|
||||
Connection: sdp.ConnectionData{
|
||||
IP: _sysinfo.MediaServerRtpIP,
|
||||
TTL: 0,
|
||||
},
|
||||
Timing: []sdp.Timing{
|
||||
{
|
||||
Start: data.S,
|
||||
End: data.E,
|
||||
},
|
||||
},
|
||||
Medias: []sdp.Media{video},
|
||||
SSRC: data.ssrc,
|
||||
}
|
||||
if data.T == 1 {
|
||||
msg.URI = fmt.Sprintf("%s:0", channel.ChannelID)
|
||||
}
|
||||
// // defining message
|
||||
// msg := &sdp.Message{
|
||||
// Origin: sdp.Origin{
|
||||
// Username: _serverDevices.DeviceID, // 媒体服务器id
|
||||
// Address: _sysinfo.MediaServerRtpIP.String(),
|
||||
// },
|
||||
// Name: name,
|
||||
// Connection: sdp.ConnectionData{
|
||||
// IP: _sysinfo.MediaServerRtpIP,
|
||||
// TTL: 0,
|
||||
// },
|
||||
// Timing: []sdp.Timing{
|
||||
// {
|
||||
// Start: data.S,
|
||||
// End: data.E,
|
||||
// },
|
||||
// },
|
||||
// Medias: []sdp.Media{video},
|
||||
// SSRC: data.ssrc,
|
||||
// }
|
||||
// if data.T == 1 {
|
||||
// msg.URI = fmt.Sprintf("%s:0", channel.ChannelID)
|
||||
// }
|
||||
|
||||
// appending message to session
|
||||
s = msg.Append(s)
|
||||
// appending session to byte buffer
|
||||
b = s.AppendTo(b)
|
||||
uri, _ := sip.ParseURI(channel.URIStr)
|
||||
channel.addr = &sip.Address{URI: uri}
|
||||
_serverDevices.addr.Params.Add("tag", sip.String{Str: sip.RandString(20)})
|
||||
hb := sip.NewHeaderBuilder().SetTo(channel.addr).SetFrom(_serverDevices.addr).AddVia(&sip.ViaHop{
|
||||
Params: sip.NewParams().Add("branch", sip.String{Str: sip.GenerateBranch()}),
|
||||
}).SetContentType(&sip.ContentTypeSDP).SetMethod(sip.MethodInvite).SetContact(_serverDevices.addr)
|
||||
req := sip.NewRequest("", sip.MethodInvite, channel.addr.URI, sip.DefaultSipVersion, hb.Build(), b)
|
||||
req.SetDestination(device.source)
|
||||
req.AppendHeader(&sip.GenericHeader{HeaderName: "Subject", Contents: fmt.Sprintf("%s:%s,%s:%s", channel.ChannelID, data.StreamID, _serverDevices.DeviceID, data.StreamID)})
|
||||
req.SetRecipient(channel.addr.URI)
|
||||
tx, err := svr.Request(req)
|
||||
if err != nil {
|
||||
// logrus.Warningln("sipPlayPush fail.id:", device.DeviceID, channel.ChannelID, "err:", err)
|
||||
return data, err
|
||||
}
|
||||
// response
|
||||
response, err := sipResponse(tx)
|
||||
if err != nil {
|
||||
// logrus.Warningln("sipPlayPush response fail.id:", device.DeviceID, channel.ChannelID, "err:", err)
|
||||
return data, err
|
||||
}
|
||||
data.Resp = response
|
||||
// ACK
|
||||
tx.Request(sip.NewRequestFromResponse(sip.MethodACK, response))
|
||||
// // appending message to session
|
||||
// s = msg.Append(s)
|
||||
// // appending session to byte buffer
|
||||
// b = s.AppendTo(b)
|
||||
// uri, _ := sip.ParseURI(channel.URIStr)
|
||||
// channel.addr = &sip.Address{URI: uri}
|
||||
// _serverDevices.addr.Params.Add("tag", sip.String{Str: sip.RandString(20)})
|
||||
// hb := sip.NewHeaderBuilder().SetTo(channel.addr).SetFrom(_serverDevices.addr).AddVia(&sip.ViaHop{
|
||||
// Params: sip.NewParams().Add("branch", sip.String{Str: sip.GenerateBranch()}),
|
||||
// }).SetContentType(&sip.ContentTypeSDP).SetMethod(sip.MethodInvite).SetContact(_serverDevices.addr)
|
||||
// req := sip.NewRequest("", sip.MethodInvite, channel.addr.URI, sip.DefaultSipVersion, hb.Build(), b)
|
||||
// req.SetDestination(device.source)
|
||||
// req.AppendHeader(&sip.GenericHeader{HeaderName: "Subject", Contents: fmt.Sprintf("%s:%s,%s:%s", channel.ChannelID, data.StreamID, _serverDevices.DeviceID, data.StreamID)})
|
||||
// req.SetRecipient(channel.addr.URI)
|
||||
// tx, err := svr.Request(req)
|
||||
// if err != nil {
|
||||
// // logrus.Warningln("sipPlayPush fail.id:", device.DeviceID, channel.ChannelID, "err:", err)
|
||||
// return data, err
|
||||
// }
|
||||
// // response
|
||||
// response, err := sipResponse(tx)
|
||||
// if err != nil {
|
||||
// // logrus.Warningln("sipPlayPush response fail.id:", device.DeviceID, channel.ChannelID, "err:", err)
|
||||
// return data, err
|
||||
// }
|
||||
// data.Resp = response
|
||||
// // ACK
|
||||
// tx.Request(sip.NewRequestFromResponse(sip.MethodACK, response))
|
||||
|
||||
callid, _ := response.CallID()
|
||||
data.CallID = string(*callid)
|
||||
// callid, _ := response.CallID()
|
||||
// data.CallID = string(*callid)
|
||||
|
||||
cseq, _ := response.CSeq()
|
||||
if cseq != nil {
|
||||
data.CseqNo = cseq.SeqNo
|
||||
}
|
||||
// cseq, _ := response.CSeq()
|
||||
// if cseq != nil {
|
||||
// data.CseqNo = cseq.SeqNo
|
||||
// }
|
||||
|
||||
// from, _ := response.From()
|
||||
// to, _ := response.To()
|
||||
// for k, v := range to.Params.Items() {
|
||||
// data.Ttag[k] = v.String()
|
||||
// }
|
||||
// for k, v := range from.Params.Items() {
|
||||
// data.Ftag[k] = v.String()
|
||||
// }
|
||||
data.Status = 0
|
||||
// // from, _ := response.From()
|
||||
// // to, _ := response.To()
|
||||
// // for k, v := range to.Params.Items() {
|
||||
// // data.Ttag[k] = v.String()
|
||||
// // }
|
||||
// // for k, v := range from.Params.Items() {
|
||||
// // data.Ftag[k] = v.String()
|
||||
// // }
|
||||
// data.Status = 0
|
||||
|
||||
return data, err
|
||||
}
|
||||
// return data, err
|
||||
// }
|
||||
|
||||
// sip 停止播放
|
||||
func SipStopPlay(ssrc string) {
|
||||
|
||||
+6
-4
@@ -36,7 +36,7 @@ func NewGB28181API(cfg *conf.Bootstrap, store gb28181.GB28181, sms *sms.NodeMana
|
||||
cfg: &cfg.Sip,
|
||||
core: store,
|
||||
sms: sms,
|
||||
catalog: sip.NewCollector[Channels](func(c1, c2 *Channels) bool {
|
||||
catalog: sip.NewCollector(func(c1, c2 *Channels) bool {
|
||||
return c1.ChannelID == c2.ChannelID
|
||||
}),
|
||||
streams: &conc.Map[string, *Streams]{},
|
||||
@@ -141,15 +141,17 @@ func (g *GB28181API) handlerRegister(ctx *sip.Context) {
|
||||
}
|
||||
g.login(ctx, expire)
|
||||
|
||||
conn := ctx.Request.GetConnection()
|
||||
fmt.Printf(">>> %p\n", conn)
|
||||
// conn := ctx.Request.GetConnection()
|
||||
// fmt.Printf(">>> %p\n", conn)
|
||||
|
||||
ctx.Log.Info("设备注册成功")
|
||||
// ctx.Log.Debug("device info", "source", ctx.Source, "host", ctx.Host)
|
||||
|
||||
respFn()
|
||||
|
||||
g.QueryDeviceInfo(ctx)
|
||||
g.QueryCatalog(dev.DeviceID)
|
||||
_ = g.QueryCatalog(dev.DeviceID)
|
||||
_ = g.QueryConfigDownloadBasic(dev.DeviceID, basicParam)
|
||||
}
|
||||
|
||||
func (g GB28181API) login(ctx *sip.Context, expire string) {
|
||||
|
||||
+9
-3
@@ -58,6 +58,7 @@ func NewServer(cfg *conf.Bootstrap, store gb28181.GB28181, sc sms.Core) (*Server
|
||||
msg.Handle("Keepalive", api.sipMessageKeepalive)
|
||||
msg.Handle("Catalog", api.sipMessageCatalog)
|
||||
msg.Handle("DeviceInfo", api.sipMessageDeviceInfo)
|
||||
msg.Handle("ConfigDownload", api.sipMessageConfigDownload)
|
||||
|
||||
// msg.Handle("RecordInfo", api.handlerMessage)
|
||||
|
||||
@@ -88,12 +89,17 @@ func NewServer(cfg *conf.Bootstrap, store gb28181.GB28181, sc sms.Core) (*Server
|
||||
func (s *Server) startTickerCheck() {
|
||||
conc.Timer(context.Background(), 60*time.Second, time.Second, func() {
|
||||
now := time.Now()
|
||||
s.memoryStorer.RangeDevices(func(key string, value *Device) bool {
|
||||
if !value.IsOnline {
|
||||
s.memoryStorer.RangeDevices(func(key string, ipc *Device) bool {
|
||||
if !ipc.IsOnline {
|
||||
return true
|
||||
}
|
||||
|
||||
if sub := now.Sub(value.LastKeepaliveAt); sub >= 3*60*time.Second || value.conn == nil {
|
||||
timeout := time.Duration(ipc.keepaliveTimeout) * time.Duration(ipc.keepaliveInterval) * time.Second
|
||||
if timeout <= 0 {
|
||||
timeout = 3 * 60 * time.Second
|
||||
}
|
||||
|
||||
if sub := now.Sub(ipc.LastKeepaliveAt); sub >= timeout || ipc.conn == nil {
|
||||
s.gb.logout(key, func(d *gb28181.Device) {
|
||||
d.IsOnline = false
|
||||
})
|
||||
|
||||
@@ -3,6 +3,7 @@ package sip
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"io"
|
||||
"log/slog"
|
||||
"strconv"
|
||||
"strings"
|
||||
@@ -583,7 +584,12 @@ func (p *parser) start() {
|
||||
packet = <-p.in
|
||||
startLine, err := packet.nextLine()
|
||||
if err != nil {
|
||||
slog.Error("start nextLine", "err", err, "line", startLine)
|
||||
if err != io.EOF {
|
||||
slog.Error("start nextLine", "err", err, "line", startLine)
|
||||
}
|
||||
continue
|
||||
}
|
||||
if len(startLine) == 0 {
|
||||
continue
|
||||
}
|
||||
if isRequest(startLine) {
|
||||
@@ -601,7 +607,7 @@ func (p *parser) start() {
|
||||
termErr = NewError(err, "parserMessage", "ParseStatusLine", startLine)
|
||||
}
|
||||
} else {
|
||||
slog.Error("start unknown", "err", err, "line", startLine)
|
||||
slog.Error("start unknown", "line", startLine)
|
||||
continue
|
||||
}
|
||||
if termErr != nil {
|
||||
|
||||
@@ -20,7 +20,7 @@ var bufferSize uint16 = 65535 - 20 - 8 // IPv4 max size - IPv4 Header size - UDP
|
||||
|
||||
// Server sip
|
||||
type Server struct {
|
||||
udpaddr net.Addr
|
||||
// udpaddr net.Addr
|
||||
udpConn Connection
|
||||
|
||||
txs *transacionts
|
||||
@@ -248,21 +248,18 @@ func (s *Server) handlerListen(msgs chan Message) {
|
||||
case *Request:
|
||||
req := tmsg
|
||||
|
||||
dst := s.udpaddr
|
||||
// dst := s.udpaddr
|
||||
if req.conn.Network() == "tcp" {
|
||||
dst = s.tcpaddr
|
||||
req.SetDestination(s.tcpaddr)
|
||||
}
|
||||
|
||||
req.SetDestination(dst)
|
||||
s.handlerRequest(req)
|
||||
case *Response:
|
||||
resp := tmsg
|
||||
|
||||
dst := s.udpaddr
|
||||
if resp.conn.Network() == "tcp" {
|
||||
dst = s.tcpaddr
|
||||
resp.SetDestination(s.tcpaddr)
|
||||
}
|
||||
resp.SetDestination(dst)
|
||||
s.handlerResponse(resp)
|
||||
default:
|
||||
// logrus.Errorln("undefind msg type,", tmsg, msg.String())
|
||||
|
||||
@@ -186,6 +186,17 @@ func xmlDecode(data []byte, v interface{}) error {
|
||||
return decoder.Decode(v)
|
||||
}
|
||||
|
||||
// XMLEncode XML编码器
|
||||
func XMLEncode(data any) ([]byte, error) {
|
||||
b, err := xml.Marshal(data)
|
||||
if err != nil {
|
||||
slog.Error("MarshalIndent", "err", err)
|
||||
return nil, err
|
||||
}
|
||||
xmlHeader := "<?xml version=\"1.0\" encoding=\"GB2312\"?>\n"
|
||||
return Utf8ToGbk([]byte(xmlHeader + string(b)))
|
||||
}
|
||||
|
||||
// Max Max
|
||||
func Max(a, b int64) int64 {
|
||||
if a > b {
|
||||
|
||||
Reference in New Issue
Block a user