genserver.GET("/cctv", pkgstream.GetCCTVIndex)
- genserver.GET("/cctv/turn/address", pkgstream.GetCCTVTurnServeAddr)
+ genserver.POST("/cctv/create", pkgstream.PostCCTVCreate)
- genserver.POST("/cctv/offer", pkgstream.PostCCTVOffer)
+ // cctv local
+
+ genserver.GET("/cctv/local", pkgstream.GetCCTVLocalIndex)
+
+ genserver.GET("/cctv/local/turn/address", pkgstream.GetCCTVLocalTurnServeAddr)
+
+ genserver.POST("/cctv/local/offer", pkgstream.PostCCTVLocalOffer)
// video
require (
github.com/gin-gonic/gin v1.10.0
+ github.com/gorilla/websocket v1.5.3
github.com/pion/rtcp v1.2.14
- github.com/pion/webrtc/v4 v4.0.0-beta.19
+ github.com/pion/webrtc/v4 v4.0.0-beta.20
github.com/wimspaargaren/yolov3 v0.3.1
gocv.io/x/gocv v0.37.0
+ gopkg.in/yaml.v3 v3.0.1
)
require (
- github.com/bytedance/sonic v1.11.6 // indirect
+ github.com/bytedance/sonic v1.11.8 // indirect
github.com/bytedance/sonic/loader v0.1.1 // indirect
github.com/cloudwego/base64x v0.1.4 // indirect
github.com/cloudwego/iasm v0.2.0 // indirect
- github.com/gabriel-vasile/mimetype v1.4.3 // indirect
+ github.com/gabriel-vasile/mimetype v1.4.4 // indirect
github.com/gin-contrib/sse v0.1.0 // 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.20.0 // indirect
- github.com/goccy/go-json v0.10.2 // indirect
+ github.com/go-playground/validator/v10 v10.22.0 // indirect
+ github.com/goccy/go-json v0.10.3 // indirect
github.com/google/uuid v1.6.0 // indirect
+ github.com/hashicorp/errwrap v1.1.0 // indirect
+ github.com/hashicorp/go-multierror v1.1.0 // indirect
github.com/json-iterator/go v1.1.12 // indirect
- github.com/klauspost/cpuid/v2 v2.2.7 // indirect
+ github.com/klauspost/cpuid/v2 v2.2.8 // indirect
github.com/leodido/go-urn v1.4.0 // indirect
github.com/mattn/go-isatty v0.0.20 // indirect
+ github.com/mitchellh/mapstructure v1.4.1 // indirect
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
github.com/modern-go/reflect2 v1.0.2 // indirect
github.com/pelletier/go-toml/v2 v2.2.2 // indirect
github.com/pion/datachannel v1.5.6 // indirect
- github.com/pion/dtls/v2 v2.2.10 // indirect
+ github.com/pion/dtls/v2 v2.2.11 // indirect
github.com/pion/ice/v3 v3.0.7 // indirect
github.com/pion/interceptor v0.1.29 // indirect
github.com/pion/logging v0.2.2 // indirect
github.com/pion/sdp/v3 v3.0.9 // indirect
github.com/pion/srtp/v3 v3.0.1 // indirect
github.com/pion/stun/v2 v2.0.0 // indirect
- github.com/pion/transport/v2 v2.2.4 // indirect
+ github.com/pion/transport/v2 v2.2.5 // indirect
github.com/pion/transport/v3 v3.0.2 // indirect
github.com/pion/turn/v3 v3.0.3 // indirect
+ github.com/pkg/errors v0.9.1 // indirect
github.com/rogpeppe/go-internal v1.12.0 // indirect
+ github.com/sirupsen/logrus v1.9.3 // indirect
github.com/twitchyliquid64/golang-asm v0.15.1 // indirect
github.com/ugorji/go/codec v1.2.12 // indirect
+ github.com/yutopp/go-amf0 v0.1.0 // indirect
+ github.com/yutopp/go-flv v0.3.1 // indirect
+ github.com/yutopp/go-rtmp v0.0.6 // indirect
golang.org/x/arch v0.8.0 // indirect
- golang.org/x/crypto v0.23.0 // indirect
- golang.org/x/net v0.25.0 // indirect
- golang.org/x/sys v0.20.0 // indirect
- golang.org/x/text v0.15.0 // indirect
- google.golang.org/protobuf v1.34.1 // indirect
- gopkg.in/yaml.v3 v3.0.1 // indirect
+ golang.org/x/crypto v0.24.0 // indirect
+ golang.org/x/net v0.26.0 // indirect
+ golang.org/x/sys v0.21.0 // indirect
+ golang.org/x/text v0.16.0 // indirect
+ google.golang.org/protobuf v1.34.2 // indirect
)
github.com/bytedance/sonic v1.11.6 h1:oUp34TzMlL+OY1OUWxHqsdkgC/Zfc85zGqw9siXjrc0=
github.com/bytedance/sonic v1.11.6/go.mod h1:LysEHSvpvDySVdC2f87zGWf6CIKJcAvqab1ZaiQtds4=
+github.com/bytedance/sonic v1.11.8 h1:Zw/j1KfiS+OYTi9lyB3bb0CFxPJVkM17k1wyDG32LRA=
+github.com/bytedance/sonic v1.11.8/go.mod h1:LysEHSvpvDySVdC2f87zGWf6CIKJcAvqab1ZaiQtds4=
github.com/bytedance/sonic/loader v0.1.1 h1:c+e5Pt1k/cy5wMveRDyk2X4B9hF4g7an8N3zCYjJFNM=
github.com/bytedance/sonic/loader v0.1.1/go.mod h1:ncP89zfokxS5LZrJxl5z0UJcsk4M4yY2JpfqGeCtNLU=
github.com/cloudwego/base64x v0.1.4 h1:jwCgWpFanWmN8xoIUHa2rtzmkd5J2plF/dnLS6Xd/0Y=
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/fortytw2/leaktest v1.2.0/go.mod h1:jDsjWgpAGjm2CA7WthBh/CdZYEPF31XHquHwclZch5g=
github.com/gabriel-vasile/mimetype v1.4.3 h1:in2uUcidCuFcDKtdcBxlR0rJ1+fsokWf+uqxgUFjbI0=
github.com/gabriel-vasile/mimetype v1.4.3/go.mod h1:d8uq/6HKRL6CGdk+aubisF/M5GcPfT7nKyLpA0lbSSk=
+github.com/gabriel-vasile/mimetype v1.4.4 h1:QjV6pZ7/XZ7ryI2KuyeEDE8wnh7fHP9YnQy+R0LnH8I=
+github.com/gabriel-vasile/mimetype v1.4.4/go.mod h1:JwLei5XPtWdGiMFB5Pjle1oEeoSeEuJfJE+TtfvdB/s=
github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE=
github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI=
github.com/gin-gonic/gin v1.10.0 h1:nTuyha1TYqgedzytsKYqna+DfLos46nTv2ygFy86HFU=
github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY=
github.com/go-playground/validator/v10 v10.20.0 h1:K9ISHbSaI0lyB2eWMPJo+kOS/FBExVwjEviJTixqxL8=
github.com/go-playground/validator/v10 v10.20.0/go.mod h1:dbuPbCMFw/DrkbEynArYaCwl3amGuJotoKCe95atGMM=
+github.com/go-playground/validator/v10 v10.22.0 h1:k6HsTZ0sTnROkhS//R0O+55JgM8C4Bx7ia+JlgcnOao=
+github.com/go-playground/validator/v10 v10.22.0/go.mod h1:dbuPbCMFw/DrkbEynArYaCwl3amGuJotoKCe95atGMM=
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/goccy/go-json v0.10.3 h1:KZ5WoDbxAIgm2HNbYckL0se1fHD6rz5j4ywS6ebzDqA=
+github.com/goccy/go-json v0.10.3/go.mod h1:oq7eo15ShAhp70Anwd5lgX2pLfOS3QCiwU/PULtXL6M=
github.com/golang/mock v1.6.0 h1:ErTB+efbowRARo13NNdxyJji2egdxLGQhRaY+DUumQc=
github.com/golang/mock v1.6.0/go.mod h1:p6yTPP+5HYm5mzsMV8JkE6ZKdX+/wYM6Hr+LicevLPs=
github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU=
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
+github.com/gorilla/websocket v1.5.3 h1:saDtZ6Pbx/0u+bgYQ3q96pZgCzfhKXGPqt7kZ72aNNg=
+github.com/gorilla/websocket v1.5.3/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
+github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
+github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I=
+github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
+github.com/hashicorp/go-multierror v1.1.0 h1:B9UzwGQJehnUY1yNrnwREHc3fGbC2xefo8g4TbElacI=
+github.com/hashicorp/go-multierror v1.1.0/go.mod h1:spPvp8C1qA32ftKqdAHm4hHTbPw+vmowP0z+KUhOZdA=
github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM=
github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg=
github.com/klauspost/cpuid/v2 v2.2.7 h1:ZWSB3igEs+d0qvnxR/ZBzXVmxkgt8DdzP6m9pfuVLDM=
github.com/klauspost/cpuid/v2 v2.2.7/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws=
+github.com/klauspost/cpuid/v2 v2.2.8 h1:+StwCXwm9PdpiEkPyzBXIy+M9KUb4ODm0Zarf1kS5BM=
+github.com/klauspost/cpuid/v2 v2.2.8/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws=
github.com/knz/go-libedit v1.10.1/go.mod h1:MZTVkCWyz0oBc7JOWP3wNAzd002ZbM/5hgShxwh4x8M=
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0=
github.com/leodido/go-urn v1.4.0/go.mod h1:bvxc+MVxLKB4z00jd1z+Dvzr47oO32F/QSNjSBOlFxI=
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
+github.com/mitchellh/mapstructure v1.4.1 h1:CpVNEelQCZBooIPDn+AR3NpivK/TIKU8bDxdASFVQag=
+github.com/mitchellh/mapstructure v1.4.1/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
github.com/pion/dtls/v2 v2.2.7/go.mod h1:8WiMkebSHFD0T+dIU+UeBaoV7kDhOW5oDCzZ7WZ/F9s=
github.com/pion/dtls/v2 v2.2.10 h1:u2Axk+FyIR1VFTPurktB+1zoEPGIW3bmyj3LEFrXjAA=
github.com/pion/dtls/v2 v2.2.10/go.mod h1:d9SYc9fch0CqK90mRk1dC7AkzzpwJj6u2GU3u+9pqFE=
+github.com/pion/dtls/v2 v2.2.11 h1:9U/dpCYl1ySttROPWJgqWKEylUdT0fXp/xst6JwY5Ks=
+github.com/pion/dtls/v2 v2.2.11/go.mod h1:d9SYc9fch0CqK90mRk1dC7AkzzpwJj6u2GU3u+9pqFE=
github.com/pion/ice/v3 v3.0.7 h1:dfMViRKblENqzorR2cQiiRKWqQfqKZ9+nT/sREX3ra8=
github.com/pion/ice/v3 v3.0.7/go.mod h1:pBRcCoJRC0vwvFsemfRIqRLYukV4bPboGb0B4b8AhrQ=
github.com/pion/interceptor v0.1.29 h1:39fsnlP1U8gw2JzOFWdfCU82vHvhW9o0rZnZF56wF+M=
github.com/pion/transport/v2 v2.2.1/go.mod h1:cXXWavvCnFF6McHTft3DWS9iic2Mftcz1Aq29pGcU5g=
github.com/pion/transport/v2 v2.2.4 h1:41JJK6DZQYSeVLxILA2+F4ZkKb4Xd/tFJZRFZQ9QAlo=
github.com/pion/transport/v2 v2.2.4/go.mod h1:q2U/tf9FEfnSBGSW6w5Qp5PFWRLRj3NjLhCCgpRK4p0=
+github.com/pion/transport/v2 v2.2.5 h1:iyi25i/21gQck4hfRhomF6SktmUQjRsRW4WJdhfc3Kc=
+github.com/pion/transport/v2 v2.2.5/go.mod h1:q2U/tf9FEfnSBGSW6w5Qp5PFWRLRj3NjLhCCgpRK4p0=
github.com/pion/transport/v3 v3.0.1/go.mod h1:UY7kiITrlMv7/IKgd5eTUcaahZx5oUN3l9SzK5f5xE0=
github.com/pion/transport/v3 v3.0.2 h1:r+40RJR25S9w3jbA6/5uEPTzcdn7ncyU44RWCbHkLg4=
github.com/pion/transport/v3 v3.0.2/go.mod h1:nIToODoOlb5If2jF9y2Igfx3PFYWfuXi37m0IlWa/D0=
github.com/pion/turn/v3 v3.0.3/go.mod h1:vw0Dz420q7VYAF3J4wJKzReLHIo2LGp4ev8nXQexYsc=
github.com/pion/webrtc/v4 v4.0.0-beta.19 h1:qAmESbOR4C8Odv+FjGc7qS1sqhWAZJgmSjQFu8pahI8=
github.com/pion/webrtc/v4 v4.0.0-beta.19/go.mod h1:yL80J6f59xyNERWAJXFdKZjjQXR4NchgtXr5JDA/2uQ=
+github.com/pion/webrtc/v4 v4.0.0-beta.20 h1:dt1th4CqqKV2APgPsapaskZuOKKvbYsNpgmgi8D6014=
+github.com/pion/webrtc/v4 v4.0.0-beta.20/go.mod h1:tBa/6GmW34fT7UURDdj7kwJlAW9NLEkeHKP1jAonhXY=
+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/rogpeppe/go-internal v1.12.0 h1:exVL4IDcn6na9z1rAb56Vxr+CgyK3nn3O+epU5NdKM8=
github.com/rogpeppe/go-internal v1.12.0/go.mod h1:E+RYuTGaKKdloAfM02xzb0FW3Paa99yedzYV+kq4uf4=
+github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ=
github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA=
+github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/wimspaargaren/yolov3 v0.3.1 h1:6vna2f0+E2PA8CSt26AGCWhADpul0WJVAHNVj5nSCvY=
github.com/wimspaargaren/yolov3 v0.3.1/go.mod h1:MQ+aZYPx4DF8UVCGlIVdETPxPnl0iPiZ0SIJ6ZdQnc4=
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
+github.com/yutopp/go-amf0 v0.1.0 h1:a3UeBZG7nRF0zfvmPn2iAfNo1RGzUpHz1VyJD2oGrik=
+github.com/yutopp/go-amf0 v0.1.0/go.mod h1:QzDOBr9RV6sQh6E5GFEJROZbU0iQKijORBmprkb3FIk=
+github.com/yutopp/go-flv v0.3.1 h1:4ILK6OgCJgUNm2WOjaucWM5lUHE0+sLNPdjq3L0Xtjk=
+github.com/yutopp/go-flv v0.3.1/go.mod h1:pAlHPSVRMv5aCUKmGOS/dZn/ooTgnc09qOPmiUNMubs=
+github.com/yutopp/go-rtmp v0.0.6 h1:iH52Zc1AamOe/8E3+DwMVkV+cEuYfDkV0CRBhcipxG8=
+github.com/yutopp/go-rtmp v0.0.6/go.mod h1:KSwrC9Xj5Kf18EUlk1g7CScecjXfIqc0J5q+S0u6Irc=
gocv.io/x/gocv v0.37.0 h1:sISHvnApErjoJodz1Dxb8UAkFdITOB3vXGslbVu6Knk=
gocv.io/x/gocv v0.37.0/go.mod h1:lmS802zoQmnNvXETpmGriBqWrENPei2GxYx5KUxJsMA=
golang.org/x/arch v0.0.0-20210923205945-b76863e36670/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8=
golang.org/x/crypto v0.21.0/go.mod h1:0BP7YvVV9gBbVKyeTG0Gyn+gZm94bibOW5BjDEYAOMs=
golang.org/x/crypto v0.23.0 h1:dIJU/v2J8Mdglj/8rJ6UUOM3Zc9zLZxVZwwxMooUSAI=
golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8=
+golang.org/x/crypto v0.24.0 h1:mnl8DM0o513X8fdIkmyFE/5hTYxbwYOjDS/+rK6qpRI=
+golang.org/x/crypto v0.24.0/go.mod h1:Z1PMYSOR5nyMcyAVAIQSKCDwalqy85Aqn1x3Ws4L5DM=
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.22.0/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg=
golang.org/x/net v0.25.0 h1:d/OCCoBEUq33pjydKrGQhw7IlUPI2Oylr+8qLx49kac=
golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM=
+golang.org/x/net v0.26.0 h1:soB7SVo0PWrY4vPW/+ay0jKDNScG2X9wFeYlXIvJsOQ=
+golang.org/x/net v0.26.0/go.mod h1:5YKkiSynbBIh3p6iOc/vibscux0x38BZDkn8sCUPxHE=
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=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.3.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.7.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.18.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.20.0 h1:Od9JTbYCk261bKm4M/mw7AklTlFYIa0bIp9BgSm1S8Y=
golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
+golang.org/x/sys v0.21.0 h1:rF+pYz3DAGSQAxAu1CbC7catZg4ebC4UIeIhKxBZvws=
+golang.org/x/sys v0.21.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.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
golang.org/x/text v0.15.0 h1:h1V/4gjBv8v9cjcR6+AR5+/cIYK5N/WAgiv4xlsEtAk=
golang.org/x/text v0.15.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
+golang.org/x/text v0.16.0 h1:a94ExnEXNtEwYLGJSIUxnWoxoRz/ZcCsV63ROupILh4=
+golang.org/x/text v0.16.0/go.mod h1:GhwF1Be+LQoKShO3cGOHzqOgRrGaYc9AvblQOmPVHnI=
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.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
google.golang.org/protobuf v1.34.1 h1:9ddQBjfCyZPOHPUiPxpYESBLc+T8P3E+Vo4IbKZgFWg=
google.golang.org/protobuf v1.34.1/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos=
+google.golang.org/protobuf v1.34.2 h1:6xV6lTsCfpGD21XK49h7MhtcApnLqkfYgPcdHftf6hg=
+google.golang.org/protobuf v1.34.2/go.mod h1:qYOHts0dSfpeUzUFpOMr/WGzszTmLH+DiWniOlNbLDw=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
package stream
import (
- "errors"
- "fmt"
+ "bytes"
+ "encoding/binary"
+ "encoding/json"
"io"
+ "log"
"net"
- "net/http"
+ "time"
"github.com/gin-gonic/gin"
- webrtcv4 "github.com/pion/webrtc/v4"
- pkgutils "github.com/seantywork/sorrylinus-again/pkg/utils"
+ "github.com/pion/webrtc/v4"
+ "github.com/pion/webrtc/v4/pkg/media"
+ "github.com/pkg/errors"
+ flvtag "github.com/yutopp/go-flv/tag"
+ "github.com/yutopp/go-rtmp"
+ rtmpmsg "github.com/yutopp/go-rtmp/message"
)
-var UDP_BUFFER_BYTE_SIZE int
-
-var RTP_RECEIVE_ADDR string
-
-var RTP_RECEIVE_PORT string
-
-var RECV_STARTED int = 0
-
func GetCCTVIndex(c *gin.Context) {
c.HTML(200, "cctv.html", gin.H{
"title": "CCTV",
})
-}
-
-func GetCCTVTurnServeAddr(c *gin.Context) {
-
- c.JSON(http.StatusOK, SERVER_RE{Status: "success", Reply: TURN_SERVER_ADDR})
}
-func PostCCTVOffer(c *gin.Context) {
-
- if RECV_STARTED == 1 {
-
- fmt.Println("recv already started")
-
- c.JSON(http.StatusBadRequest, SERVER_RE{Status: "error", Reply: "invalid request"})
-
- return
- }
-
- var offerjson CLIENT_REQ
-
- if err := c.BindJSON(&offerjson); err != nil {
-
- fmt.Println("failed to get request body")
-
- c.JSON(http.StatusBadRequest, SERVER_RE{Status: "error", Reply: "invalid format"})
-
- return
-
- }
-
- offer_out := make(chan string)
+func PostCCTVCreate(c *gin.Context) {
+ log.Println("Incoming HTTP Request")
- go startCCTVReceiver(offerjson.Data, offer_out)
-
- offer_out_str := <-offer_out
-
- c.JSON(http.StatusOK, SERVER_RE{Status: "success", Reply: offer_out_str})
-
-}
-func startCCTVReceiver(offer_in string, offer_out chan string) {
-
- peerConnection, err := webrtcv4.NewPeerConnection(webrtcv4.Configuration{
- ICEServers: []webrtcv4.ICEServer{
- {
- URLs: []string{TURN_SERVER_ADDR},
- },
- },
- })
+ peerConnection, err := webrtc.NewPeerConnection(webrtc.Configuration{})
if err != nil {
panic(err)
}
- var udp_port int
-
- fmt.Sscanf(RTP_RECEIVE_PORT, "%d", &udp_port)
-
- listener, err := net.ListenUDP("udp", &net.UDPAddr{IP: net.ParseIP(RTP_RECEIVE_ADDR), Port: udp_port})
+ videoTrack, err := webrtc.NewTrackLocalStaticSample(webrtc.RTPCodecCapability{MimeType: webrtc.MimeTypeH264}, "video", "pion")
if err != nil {
panic(err)
}
+ if _, err = peerConnection.AddTrack(videoTrack); err != nil {
+ panic(err)
+ }
- // Increase the UDP receive buffer size
- // Default UDP buffer sizes vary on different operating systems
- bufferSize := UDP_BUFFER_BYTE_SIZE // 300KB
- err = listener.SetReadBuffer(bufferSize)
+ audioTrack, err := webrtc.NewTrackLocalStaticSample(webrtc.RTPCodecCapability{MimeType: webrtc.MimeTypePCMA}, "audio", "pion")
if err != nil {
panic(err)
}
+ if _, err = peerConnection.AddTrack(audioTrack); err != nil {
+ panic(err)
+ }
- defer func() {
- if err = listener.Close(); err != nil {
- panic(err)
- }
- }()
+ var offer webrtc.SessionDescription
+ if err := json.NewDecoder(c.Request.Body).Decode(&offer); err != nil {
+ panic(err)
+ }
- // Create a video track
- videoTrack, err := webrtcv4.NewTrackLocalStaticRTP(webrtcv4.RTPCodecCapability{MimeType: webrtcv4.MimeTypeVP8}, "video", "pion")
- if err != nil {
+ if err := peerConnection.SetRemoteDescription(offer); err != nil {
panic(err)
}
- rtpSender, err := peerConnection.AddTrack(videoTrack)
+
+ gatherComplete := webrtc.GatheringCompletePromise(peerConnection)
+ answer, err := peerConnection.CreateAnswer(nil)
if err != nil {
panic(err)
+ } else if err = peerConnection.SetLocalDescription(answer); err != nil {
+ panic(err)
}
+ <-gatherComplete
- // Read incoming RTCP packets
- // Before these packets are returned they are processed by interceptors. For things
- // like NACK this needs to be called.
- go func() {
- rtcpBuf := make([]byte, 1500)
- for {
- if _, _, rtcpErr := rtpSender.Read(rtcpBuf); rtcpErr != nil {
- return
- }
- }
- }()
-
- // Set the handler for ICE connection state
- // This will notify you when the peer has connected/disconnected
- peerConnection.OnICEConnectionStateChange(func(connectionState webrtcv4.ICEConnectionState) {
- fmt.Printf("Connection State has changed %s \n", connectionState.String())
+ c.JSON(200, peerConnection.LocalDescription())
- if connectionState == webrtcv4.ICEConnectionStateFailed {
- if closeErr := peerConnection.Close(); closeErr != nil {
- panic(closeErr)
- }
- }
- })
+ go startRTMPServer(peerConnection, videoTrack, audioTrack)
+}
- // Wait for the offer to be pasted
- offer := webrtcv4.SessionDescription{}
- pkgutils.Decode(offer_in, &offer)
+func startRTMPServer(peerConnection *webrtc.PeerConnection, videoTrack, audioTrack *webrtc.TrackLocalStaticSample) {
+ log.Println("Starting RTMP Server")
- // Set the remote SessionDescription
- if err = peerConnection.SetRemoteDescription(offer); err != nil {
- panic(err)
+ tcpAddr, err := net.ResolveTCPAddr("tcp", ":8084")
+ if err != nil {
+ log.Panicf("Failed: %+v", err)
}
- // Create answer
- answer, err := peerConnection.CreateAnswer(nil)
+ listener, err := net.ListenTCP("tcp", tcpAddr)
if err != nil {
- panic(err)
+ log.Panicf("Failed: %+v", err)
}
- // Create channel that is blocked until ICE Gathering is complete
- gatherComplete := webrtcv4.GatheringCompletePromise(peerConnection)
-
- // Sets the LocalDescription, and starts our UDP listeners
- if err = peerConnection.SetLocalDescription(answer); err != nil {
- panic(err)
+ srv := rtmp.NewServer(&rtmp.ServerConfig{
+ OnConnect: func(conn net.Conn) (io.ReadWriteCloser, *rtmp.ConnConfig) {
+ return conn, &rtmp.ConnConfig{
+ Handler: &Handler{
+ peerConnection: peerConnection,
+ videoTrack: videoTrack,
+ audioTrack: audioTrack,
+ },
+
+ ControlState: rtmp.StreamControlStateConfig{
+ DefaultBandwidthWindowSize: 6 * 1024 * 1024 / 8,
+ },
+ }
+ },
+ })
+ if err := srv.Serve(listener); err != nil {
+ log.Panicf("Failed: %+v", err)
}
+}
- // Block until ICE Gathering is complete, disabling trickle ICE
- // we do this because we only can exchange one signaling message
- // in a production application you should exchange ICE Candidates via OnICECandidate
- <-gatherComplete
+type Handler struct {
+ rtmp.DefaultHandler
+ peerConnection *webrtc.PeerConnection
+ videoTrack, audioTrack *webrtc.TrackLocalStaticSample
+}
- // Output the answer in base64 so we can paste it in browser
+func (h *Handler) OnServe(conn *rtmp.Conn) {
+}
- localdesc := pkgutils.Encode(peerConnection.LocalDescription())
+func (h *Handler) OnConnect(timestamp uint32, cmd *rtmpmsg.NetConnectionConnect) error {
+ log.Printf("OnConnect: %#v", cmd)
+ return nil
+}
- offer_out <- localdesc
+func (h *Handler) OnCreateStream(timestamp uint32, cmd *rtmpmsg.NetConnectionCreateStream) error {
+ log.Printf("OnCreateStream: %#v", cmd)
+ return nil
+}
- // Read RTP packets forever and send them to the WebRTC Client
- inboundRTPPacket := make([]byte, 1600) // UDP MTU
+func (h *Handler) OnPublish(ctx *rtmp.StreamContext, timestamp uint32, cmd *rtmpmsg.NetStreamPublish) error {
+ log.Printf("OnPublish: %#v", cmd)
- RECV_STARTED = 1
+ if cmd.PublishingName == "" {
+ return errors.New("PublishingName is empty")
+ }
+ return nil
+}
- for {
- n, _, err := listener.ReadFrom(inboundRTPPacket)
- if err != nil {
+func (h *Handler) OnAudio(timestamp uint32, payload io.Reader) error {
+ var audio flvtag.AudioData
+ if err := flvtag.DecodeAudioData(payload, &audio); err != nil {
+ return err
+ }
- RECV_STARTED = 0
+ data := new(bytes.Buffer)
+ if _, err := io.Copy(data, audio.Data); err != nil {
+ return err
+ }
- panic(fmt.Sprintf("error during read: %s", err))
- }
+ return h.audioTrack.WriteSample(media.Sample{
+ Data: data.Bytes(),
+ Duration: 128 * time.Millisecond,
+ })
+}
- if _, err = videoTrack.Write(inboundRTPPacket[:n]); err != nil {
- if errors.Is(err, io.ErrClosedPipe) {
- // The peerConnection has been closed.
+const headerLengthField = 4
- RECV_STARTED = 0
- return
- }
+func (h *Handler) OnVideo(timestamp uint32, payload io.Reader) error {
+ var video flvtag.VideoData
+ if err := flvtag.DecodeVideoData(payload, &video); err != nil {
+ return err
+ }
- RECV_STARTED = 0
+ data := new(bytes.Buffer)
+ if _, err := io.Copy(data, video.Data); err != nil {
+ return err
+ }
- panic(err)
+ outBuf := []byte{}
+ videoBuffer := data.Bytes()
+ for offset := 0; offset < len(videoBuffer); {
+ bufferLength := int(binary.BigEndian.Uint32(videoBuffer[offset : offset+headerLengthField]))
+ if offset+bufferLength >= len(videoBuffer) {
+ break
}
+
+ offset += headerLengthField
+ outBuf = append(outBuf, []byte{0x00, 0x00, 0x00, 0x01}...)
+ outBuf = append(outBuf, videoBuffer[offset:offset+bufferLength]...)
+
+ offset += int(bufferLength)
}
+
+ return h.videoTrack.WriteSample(media.Sample{
+ Data: outBuf,
+ Duration: time.Second / 30,
+ })
+}
+
+func (h *Handler) OnClose() {
+ log.Printf("OnClose")
}
--- /dev/null
+package stream
+
+import (
+ "errors"
+ "fmt"
+ "io"
+ "net"
+ "net/http"
+
+ "github.com/gin-gonic/gin"
+ webrtcv4 "github.com/pion/webrtc/v4"
+ pkgutils "github.com/seantywork/sorrylinus-again/pkg/utils"
+)
+
+var UDP_BUFFER_BYTE_SIZE int
+
+var RTP_RECEIVE_ADDR string
+
+var RTP_RECEIVE_PORT string
+
+var RECV_STARTED int = 0
+
+func GetCCTVLocalIndex(c *gin.Context) {
+
+ c.HTML(200, "cctv_local.html", gin.H{
+ "title": "CCTV",
+ })
+}
+
+func GetCCTVLocalTurnServeAddr(c *gin.Context) {
+
+ c.JSON(http.StatusOK, SERVER_RE{Status: "success", Reply: TURN_SERVER_ADDR})
+
+}
+
+func PostCCTVLocalOffer(c *gin.Context) {
+
+ if RECV_STARTED == 1 {
+
+ fmt.Println("recv already started")
+
+ c.JSON(http.StatusBadRequest, SERVER_RE{Status: "error", Reply: "invalid request"})
+
+ return
+ }
+
+ var offerjson CLIENT_REQ
+
+ if err := c.BindJSON(&offerjson); err != nil {
+
+ fmt.Println("failed to get request body")
+
+ c.JSON(http.StatusBadRequest, SERVER_RE{Status: "error", Reply: "invalid format"})
+
+ return
+
+ }
+
+ offer_out := make(chan string)
+
+ go startCCTVReceiver(offerjson.Data, offer_out)
+
+ offer_out_str := <-offer_out
+
+ c.JSON(http.StatusOK, SERVER_RE{Status: "success", Reply: offer_out_str})
+
+}
+func startCCTVReceiver(offer_in string, offer_out chan string) {
+
+ peerConnection, err := webrtcv4.NewPeerConnection(webrtcv4.Configuration{
+ ICEServers: []webrtcv4.ICEServer{
+ {
+ URLs: []string{TURN_SERVER_ADDR},
+ },
+ },
+ })
+ if err != nil {
+ panic(err)
+ }
+
+ var udp_port int
+
+ fmt.Sscanf(RTP_RECEIVE_PORT, "%d", &udp_port)
+
+ listener, err := net.ListenTCP("tcp", &net.TCPAddr{IP: net.ParseIP(RTP_RECEIVE_ADDR), Port: udp_port})
+ if err != nil {
+ panic(err)
+ }
+
+ // Increase the UDP receive buffer size
+ // Default UDP buffer sizes vary on different operating systems
+ //bufferSize := UDP_BUFFER_BYTE_SIZE // 300KB
+ //err = listener.SetReadBuffer(bufferSize)
+ //if err != nil {
+ // panic(err)
+ //}
+
+ defer func() {
+ if err = listener.Close(); err != nil {
+ panic(err)
+ }
+ }()
+
+ // Create a video track
+ videoTrack, err := webrtcv4.NewTrackLocalStaticRTP(webrtcv4.RTPCodecCapability{MimeType: webrtcv4.MimeTypeVP8}, "video", "pion")
+ if err != nil {
+ panic(err)
+ }
+ rtpSender, err := peerConnection.AddTrack(videoTrack)
+ if err != nil {
+ panic(err)
+ }
+
+ // Read incoming RTCP packets
+ // Before these packets are returned they are processed by interceptors. For things
+ // like NACK this needs to be called.
+ go func() {
+ rtcpBuf := make([]byte, 1500)
+ for {
+ if _, _, rtcpErr := rtpSender.Read(rtcpBuf); rtcpErr != nil {
+ return
+ }
+ }
+ }()
+
+ // Set the handler for ICE connection state
+ // This will notify you when the peer has connected/disconnected
+ peerConnection.OnICEConnectionStateChange(func(connectionState webrtcv4.ICEConnectionState) {
+ fmt.Printf("Connection State has changed %s \n", connectionState.String())
+
+ if connectionState == webrtcv4.ICEConnectionStateFailed {
+ if closeErr := peerConnection.Close(); closeErr != nil {
+ panic(closeErr)
+ }
+ }
+ })
+
+ // Wait for the offer to be pasted
+ offer := webrtcv4.SessionDescription{}
+ pkgutils.Decode(offer_in, &offer)
+
+ // Set the remote SessionDescription
+ if err = peerConnection.SetRemoteDescription(offer); err != nil {
+ panic(err)
+ }
+
+ // Create answer
+ answer, err := peerConnection.CreateAnswer(nil)
+ if err != nil {
+ panic(err)
+ }
+
+ // Create channel that is blocked until ICE Gathering is complete
+ gatherComplete := webrtcv4.GatheringCompletePromise(peerConnection)
+
+ // Sets the LocalDescription, and starts our UDP listeners
+ if err = peerConnection.SetLocalDescription(answer); err != nil {
+ panic(err)
+ }
+
+ // Block until ICE Gathering is complete, disabling trickle ICE
+ // we do this because we only can exchange one signaling message
+ // in a production application you should exchange ICE Candidates via OnICECandidate
+ <-gatherComplete
+
+ // Output the answer in base64 so we can paste it in browser
+
+ localdesc := pkgutils.Encode(peerConnection.LocalDescription())
+
+ offer_out <- localdesc
+
+ // Read RTP packets forever and send them to the WebRTC Client
+ inboundRTPPacket := make([]byte, 1600) // UDP MTU
+
+ RECV_STARTED = 1
+
+ new_conn, err := listener.Accept()
+
+ if err != nil {
+
+ panic(err)
+
+ }
+
+ for {
+
+ n, err := new_conn.Read(inboundRTPPacket)
+ //n, _, err := listener.ReadFrom(inboundRTPPacket)
+ if err != nil {
+
+ RECV_STARTED = 0
+
+ panic(fmt.Sprintf("error during read: %s", err))
+ }
+
+ if _, err = videoTrack.Write(inboundRTPPacket[:n]); err != nil {
+ if errors.Is(err, io.ErrClosedPipe) {
+ // The peerConnection has been closed.
+
+ RECV_STARTED = 0
+ return
+ }
+
+ RECV_STARTED = 0
+
+ panic(err)
+ }
+ }
+}
+++ /dev/null
-textarea {
- width: 500px;
- min-height: 75px;
-}
\ No newline at end of file
--- /dev/null
+textarea {
+ width: 500px;
+ min-height: 75px;
+}
\ No newline at end of file
+++ /dev/null
-/*
-let pc = new RTCPeerConnection({
- iceServers: [
- {
- urls: 'stun:stun.l.google.com:19302'
- }
- ]
- })
-
-*/
-
-TURN_SERVER_ADDRESS = ""
-
-CLIENT_REQ = {
- "data":""
-}
-
-pc = {}
-
-log = function(msg) {
- document.getElementById('div').innerHTML += msg + '<br>'
-}
-
-
-
-
-async function startCCTVOffer(){
-
-
- let offer_val = document.getElementById('localSessionDescription').value
-
-
- let offerjson = JSON.parse(JSON.stringify(CLIENT_REQ))
-
- offerjson.data = offer_val
-
- let result = await axios.post("/cctv/offer", offerjson)
-
- if (result.data.status != "success") {
-
- alert("failed to start cctv offer")
- }
-
-
- document.getElementById('remoteSessionDescription').value = result.data.reply
-
-
-
-}
-
-
-function startSession() {
- let sd = document.getElementById('remoteSessionDescription').value
- if (sd === '') {
- return alert('Session Description must not be empty')
- }
-
- try {
- pc.setRemoteDescription(new RTCSessionDescription(JSON.parse(atob(sd))))
- } catch (e) {
- alert(e)
- }
-}
-
-
-async function getTurnServerAddressAndInit(){
-
- let result = await axios.get("/cctv/turn/address")
-
- if(result.data.status != "success"){
-
- alert("failed to get turn server address")
-
- return
- }
-
-
- TURN_SERVER_ADDRESS = result.data.reply
-
- console.log("turnServerAddr: " + TURN_SERVER_ADDRESS)
-
-
- pc = new RTCPeerConnection({
- iceServers: [
- {
- urls: TURN_SERVER_ADDRESS
- }
- ]
- })
-
-
- pc.ontrack = function (event) {
- let el = document.createElement(event.track.kind)
- el.srcObject = event.streams[0]
- el.autoplay = true
- el.controls = true
-
- document.getElementById('remoteVideos').appendChild(el)
- }
-
- pc.oniceconnectionstatechange = function(e) {log(pc.iceConnectionState)}
- pc.onicecandidate = function(event){
- if (event.candidate === null) {
- document.getElementById('localSessionDescription').value = btoa(JSON.stringify(pc.localDescription))
- }
- }
-
- // Offer to receive 1 audio, and 2 video tracks
- pc.addTransceiver('audio', {'direction': 'recvonly'})
- pc.addTransceiver('video', {'direction': 'recvonly'})
- pc.createOffer().then(function(d){ pc.setLocalDescription(d)}).catch(log)
-
-}
-
-
-getTurnServerAddressAndInit()
\ No newline at end of file
--- /dev/null
+/*
+let pc = new RTCPeerConnection({
+ iceServers: [
+ {
+ urls: 'stun:stun.l.google.com:19302'
+ }
+ ]
+ })
+
+*/
+
+TURN_SERVER_ADDRESS = ""
+
+CLIENT_REQ = {
+ "data":""
+}
+
+pc = {}
+
+log = function(msg) {
+ document.getElementById('div').innerHTML += msg + '<br>'
+}
+
+
+
+
+async function startCCTVOffer(){
+
+
+ let offer_val = document.getElementById('localSessionDescription').value
+
+
+ let offerjson = JSON.parse(JSON.stringify(CLIENT_REQ))
+
+ offerjson.data = offer_val
+
+ let result = await axios.post("/cctv/offer", offerjson)
+
+ if (result.data.status != "success") {
+
+ alert("failed to start cctv offer")
+ }
+
+
+ document.getElementById('remoteSessionDescription').value = result.data.reply
+
+
+
+}
+
+
+function startSession() {
+ let sd = document.getElementById('remoteSessionDescription').value
+ if (sd === '') {
+ return alert('Session Description must not be empty')
+ }
+
+ try {
+ pc.setRemoteDescription(new RTCSessionDescription(JSON.parse(atob(sd))))
+ } catch (e) {
+ alert(e)
+ }
+}
+
+
+async function getTurnServerAddressAndInit(){
+
+ let result = await axios.get("/cctv/turn/address")
+
+ if(result.data.status != "success"){
+
+ alert("failed to get turn server address")
+
+ return
+ }
+
+
+ TURN_SERVER_ADDRESS = result.data.reply
+
+ console.log("turnServerAddr: " + TURN_SERVER_ADDRESS)
+
+
+ pc = new RTCPeerConnection({
+ iceServers: [
+ {
+ urls: TURN_SERVER_ADDRESS
+ }
+ ]
+ })
+
+
+ pc.ontrack = function (event) {
+ let el = document.createElement(event.track.kind)
+ el.srcObject = event.streams[0]
+ el.autoplay = true
+ el.controls = true
+
+ document.getElementById('remoteVideos').appendChild(el)
+ }
+
+ pc.oniceconnectionstatechange = function(e) {log(pc.iceConnectionState)}
+ pc.onicecandidate = function(event){
+ if (event.candidate === null) {
+ document.getElementById('localSessionDescription').value = btoa(JSON.stringify(pc.localDescription))
+ }
+ }
+
+ // Offer to receive 1 audio, and 2 video tracks
+ pc.addTransceiver('audio', {'direction': 'recvonly'})
+ pc.addTransceiver('video', {'direction': 'recvonly'})
+ pc.createOffer().then(function(d){ pc.setLocalDescription(d)}).catch(log)
+
+}
+
+
+getTurnServerAddressAndInit()
\ No newline at end of file
-<!doctype html>
-<html lang="en">
-<head>
- <meta charset="utf-8">
- <title>webrtc client</title>
- <meta name="viewport" content="width=device-width, initial-scale=1">
- <link rel="icon" type="image/x-icon" href="favicon.ico">
+<html>
+ <head>
+ <title> RTMP to WebRTC </title>
+ </head>
- <link rel="stylesheet" href="/public/css/cctv.css">
- <script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script>
+ <body>
+ <h1> RTMP to WebRTC </h1>
+ <div id="rtmpFeed"></div>
+ </body>
- <script src="/public/js/cctv.js"></script>
+ <script>
+ let pc = new RTCPeerConnection()
+ pc.ontrack = function (event) {
+ var el = document.createElement(event.track.kind)
+ el.srcObject = event.streams[0]
+ el.autoplay = true
+ el.controls = true
-</head>
-<body>
- Browser base64 Session Description<br />
- <textarea id="localSessionDescription" readonly="true"></textarea> <br />
-
- <button onclick="startCCTVOffer()"> Start offer </button><br />
-
- Golang base64 Session Description<br />
- <textarea id="remoteSessionDescription"> </textarea> <br/>
- <button onclick="startSession()"> Start Session </button><br />
-
- <br />
-
- Video<br />
- <div id="remoteVideos"></div> <br />
-
- Logs<br />
- <div id="div"></div>
-
-</body>
+ document.getElementById('rtmpFeed').appendChild(el)
+ }
+ pc.addTransceiver('video')
+ pc.addTransceiver('audio')
+ pc.createOffer()
+ .then(offer => {
+ pc.setLocalDescription(offer)
+ console.log(offer)
+ return fetch(`/cctv/create`, {
+ method: 'post',
+ headers: {
+ 'Accept': 'application/json, text/plain, */*',
+ 'Content-Type': 'application/json'
+ },
+ body: JSON.stringify(offer)
+ })
+ })
+ .then(res => res.json())
+ .then(res => pc.setRemoteDescription(res))
+ .catch(alert)
+ </script>
</html>
\ No newline at end of file
--- /dev/null
+<!doctype html>
+<html lang="en">
+<head>
+ <meta charset="utf-8">
+ <title>webrtc client</title>
+ <meta name="viewport" content="width=device-width, initial-scale=1">
+ <link rel="icon" type="image/x-icon" href="favicon.ico">
+
+ <link rel="stylesheet" href="/public/css/cctv_local.css">
+ <script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script>
+
+ <script src="/public/js/cctv_local.js"></script>
+
+</head>
+<body>
+ Browser base64 Session Description<br />
+ <textarea id="localSessionDescription" readonly="true"></textarea> <br />
+
+ <button onclick="startCCTVOffer()"> Start offer </button><br />
+
+ Golang base64 Session Description<br />
+ <textarea id="remoteSessionDescription"> </textarea> <br/>
+ <button onclick="startSession()"> Start Session </button><br />
+
+ <br />
+
+ Video<br />
+ <div id="remoteVideos"></div> <br />
+
+ Logs<br />
+ <div id="div"></div>
+
+</body>
+
+</html>
\ No newline at end of file