initial commit - coding by Benyamin Azarkhazin (and not me, even though I am committing it)
commit
4318395ad0
|
@ -0,0 +1,3 @@
|
|||
.dockerignore
|
||||
.gitignore
|
||||
Dockerfile
|
|
@ -0,0 +1,2 @@
|
|||
.idea
|
||||
goldgorilla
|
|
@ -0,0 +1,19 @@
|
|||
# GoldGorilla
|
||||
|
||||
**GoldGorilla** is bespoke **Selective Forwarding Unit** (**SFU**) designed to work with **GreatApe**.
|
||||
|
||||
## Team
|
||||
|
||||
The following is a list of the people who are actively working on GoldGorilla (in alphabetical order):
|
||||
|
||||
| Name | Role | Online |
|
||||
|--------------------------|----------------------------|------------------------------------------------------------------------------------|
|
||||
| Atanaz Ostovar | qa | |
|
||||
| Benyamin Azarkhazin | engineering (**primary**) | |
|
||||
| Charles Iliya Krempeaux | product, engineering | [🐘](https://mastodon.social/@reiver) [🕸️](http://changelog.ca/) |
|
||||
| Chris Trottier | community, marketing | [🐘](https://calckey.social/@atomicpoet) [📷](https://peerverse.space/atomicpoet) |
|
||||
| Massoud Seifi | engineering | [🐘](https://mastodon.social/@accesstoken) |
|
||||
| Mehrdad Mirsamie | engineering | [🐘](https://mastodon.social/@mmcomp) |
|
||||
| Sepideh Farsi | qa | |
|
||||
|
||||
🦍
|
|
@ -0,0 +1,62 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"sourcecode.social/greatape/goldgorilla/controllers"
|
||||
"sourcecode.social/greatape/goldgorilla/models"
|
||||
"sourcecode.social/greatape/goldgorilla/repositories"
|
||||
"sourcecode.social/greatape/goldgorilla/routers"
|
||||
"io"
|
||||
"net/http"
|
||||
"time"
|
||||
)
|
||||
|
||||
type App struct {
|
||||
conf *models.ConfigModel
|
||||
router *routers.Router
|
||||
src string
|
||||
}
|
||||
|
||||
func (a *App) Init(srcListenAddr string, logjamBaseUrl string, targetRoom string) {
|
||||
a.src = srcListenAddr
|
||||
a.conf = &models.ConfigModel{
|
||||
LogjamBaseUrl: logjamBaseUrl + "/auxiliary-node",
|
||||
TargetRoom: targetRoom,
|
||||
}
|
||||
roomRepo := repositories.NewRoomRepository(a.conf)
|
||||
a.router = &routers.Router{}
|
||||
respHelper := controllers.NewResponseHelper()
|
||||
roomCtrl := controllers.NewRoomController(respHelper, roomRepo, a.conf)
|
||||
|
||||
err := a.router.RegisterRoutes(roomCtrl)
|
||||
panicIfErr(err)
|
||||
}
|
||||
|
||||
func (a *App) Run() {
|
||||
go func() {
|
||||
start:
|
||||
buffer, _ := json.Marshal(map[string]any{"roomId": a.conf.TargetRoom})
|
||||
body := bytes.NewReader(buffer)
|
||||
res, err := http.Post(a.conf.LogjamBaseUrl+"/join", "application/json", body)
|
||||
if err != nil {
|
||||
println(err.Error())
|
||||
time.Sleep(4 * time.Second)
|
||||
goto start
|
||||
}
|
||||
if res.StatusCode > 204 {
|
||||
resbody, _ := io.ReadAll(res.Body)
|
||||
println("get /join "+res.Status, string(resbody))
|
||||
time.Sleep(4 * time.Second)
|
||||
goto start
|
||||
}
|
||||
}()
|
||||
err := a.router.Serve(a.src)
|
||||
panicIfErr(err)
|
||||
}
|
||||
|
||||
func panicIfErr(err error) {
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
|
@ -0,0 +1,70 @@
|
|||
package controllers
|
||||
|
||||
import (
|
||||
"github.com/gin-gonic/gin"
|
||||
"sourcecode.social/greatape/goldgorilla/models"
|
||||
)
|
||||
|
||||
type ResponseHelper struct {
|
||||
}
|
||||
|
||||
func NewResponseHelper() *ResponseHelper {
|
||||
return &ResponseHelper{}
|
||||
}
|
||||
|
||||
func (r *ResponseHelper) Response(ctx *gin.Context, body any, code int) {
|
||||
if body == nil {
|
||||
body = struct{}{}
|
||||
}
|
||||
ctx.JSON(code, body)
|
||||
}
|
||||
|
||||
func (r *ResponseHelper) ResponseError(ctx *gin.Context, errObj any, code *int) {
|
||||
errCode := 500
|
||||
if code != nil {
|
||||
errCode = *code
|
||||
} else if bigErr, isBigErr := errObj.(models.BigError); isBigErr {
|
||||
errCode = bigErr.ErrCode()
|
||||
}
|
||||
|
||||
var errResp models.MessageResponse
|
||||
if err, isError := errObj.(error); isError {
|
||||
errResp.Message = err.Error()
|
||||
} else if err, isMessage := errObj.(models.MessageResponse); isMessage {
|
||||
errResp = err
|
||||
} else {
|
||||
errResp.Message = "unhandled error, contact support"
|
||||
}
|
||||
ctx.JSON(errCode, errResp)
|
||||
}
|
||||
|
||||
func (r *ResponseHelper) ResponseBadReq(ctx *gin.Context) {
|
||||
st := 400
|
||||
r.ResponseError(ctx, models.MessageResponse{Message: "bad request, invalid input"}, &st)
|
||||
}
|
||||
|
||||
func (r *ResponseHelper) ResponseUnprocessableEntity(ctx *gin.Context) {
|
||||
st := 422
|
||||
r.ResponseError(ctx, models.MessageResponse{Message: "unprocessable entity, invalid input"}, &st)
|
||||
}
|
||||
|
||||
func (r *ResponseHelper) HandleIfErr(ctx *gin.Context, err error, status *int) bool {
|
||||
if err == nil {
|
||||
return false
|
||||
}
|
||||
var statusCode = 500
|
||||
if bigErr, extends := err.(models.BigError); extends {
|
||||
if status != nil {
|
||||
statusCode = *status
|
||||
} else {
|
||||
statusCode = bigErr.ErrCode()
|
||||
}
|
||||
r.ResponseError(ctx, models.MessageResponse{Message: bigErr.Error()}, &statusCode)
|
||||
} else {
|
||||
if status != nil {
|
||||
statusCode = *status
|
||||
}
|
||||
r.ResponseError(ctx, models.MessageResponse{Message: err.Error()}, &statusCode)
|
||||
}
|
||||
return true
|
||||
}
|
|
@ -0,0 +1,156 @@
|
|||
package controllers
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"github.com/gin-gonic/gin"
|
||||
"sourcecode.social/greatape/goldgorilla/models"
|
||||
"sourcecode.social/greatape/goldgorilla/models/dto"
|
||||
"sourcecode.social/greatape/goldgorilla/repositories"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
type RoomController struct {
|
||||
helper *ResponseHelper
|
||||
repo *repositories.RoomRepository
|
||||
conf *models.ConfigModel
|
||||
}
|
||||
|
||||
func NewRoomController(respHelper *ResponseHelper, repo *repositories.RoomRepository, conf *models.ConfigModel) *RoomController {
|
||||
return &RoomController{
|
||||
helper: respHelper,
|
||||
repo: repo,
|
||||
conf: conf,
|
||||
}
|
||||
}
|
||||
|
||||
func (c *RoomController) CreatePeer(ctx *gin.Context) {
|
||||
var reqModel dto.CreatePeerReqModel
|
||||
badReqSt := 400
|
||||
if err := ctx.ShouldBindJSON(&reqModel); c.helper.HandleIfErr(ctx, err, &badReqSt) {
|
||||
return
|
||||
}
|
||||
if !reqModel.Validate() {
|
||||
c.helper.ResponseUnprocessableEntity(ctx)
|
||||
return
|
||||
}
|
||||
offer, err := c.repo.CreatePeer(reqModel.RoomId, reqModel.ID, reqModel.CanPublish, reqModel.IsCaller)
|
||||
if c.helper.HandleIfErr(ctx, err, nil) {
|
||||
return
|
||||
}
|
||||
c.helper.Response(ctx, struct{}{}, http.StatusNoContent)
|
||||
|
||||
if offer != nil {
|
||||
buffer, err := json.Marshal(dto.SetSDPReqModel{
|
||||
PeerDTO: dto.PeerDTO{
|
||||
RoomId: reqModel.RoomId,
|
||||
ID: reqModel.ID,
|
||||
},
|
||||
SDP: *offer,
|
||||
})
|
||||
if err != nil {
|
||||
println(err.Error())
|
||||
return
|
||||
}
|
||||
reader := bytes.NewReader(buffer)
|
||||
resp, err := http.Post(c.conf.LogjamBaseUrl+"/offer", "application/json", reader)
|
||||
if err != nil {
|
||||
println(err.Error())
|
||||
return
|
||||
}
|
||||
if resp.StatusCode > 204 {
|
||||
println(resp.Status)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (c *RoomController) AddICECandidate(ctx *gin.Context) {
|
||||
var reqModel dto.AddPeerICECandidateReqModel
|
||||
badReqSt := 400
|
||||
if err := ctx.ShouldBindJSON(&reqModel); c.helper.HandleIfErr(ctx, err, &badReqSt) {
|
||||
return
|
||||
}
|
||||
if !reqModel.Validate() {
|
||||
c.helper.ResponseUnprocessableEntity(ctx)
|
||||
return
|
||||
}
|
||||
err := c.repo.AddPeerIceCandidate(reqModel.RoomId, reqModel.ID, reqModel.ICECandidate)
|
||||
if c.helper.HandleIfErr(ctx, err, nil) {
|
||||
return
|
||||
}
|
||||
c.helper.Response(ctx, struct{}{}, http.StatusNoContent)
|
||||
}
|
||||
|
||||
func (c *RoomController) Offer(ctx *gin.Context) {
|
||||
var reqModel dto.SetSDPReqModel
|
||||
badReqSt := 400
|
||||
if err := ctx.ShouldBindJSON(&reqModel); c.helper.HandleIfErr(ctx, err, &badReqSt) {
|
||||
return
|
||||
}
|
||||
if !reqModel.Validate() {
|
||||
c.helper.ResponseUnprocessableEntity(ctx)
|
||||
return
|
||||
}
|
||||
answer, err := c.repo.SetPeerOffer(reqModel.RoomId, reqModel.ID, reqModel.SDP)
|
||||
if c.helper.HandleIfErr(ctx, err, nil) {
|
||||
println(err.Error())
|
||||
return
|
||||
}
|
||||
c.helper.Response(ctx, struct{}{}, http.StatusNoContent)
|
||||
{
|
||||
buffer, err := json.Marshal(dto.SetSDPReqModel{
|
||||
PeerDTO: dto.PeerDTO{
|
||||
RoomId: reqModel.RoomId,
|
||||
ID: reqModel.ID,
|
||||
},
|
||||
SDP: *answer,
|
||||
})
|
||||
if err != nil {
|
||||
println(err.Error())
|
||||
return
|
||||
}
|
||||
reader := bytes.NewReader(buffer)
|
||||
resp, err := http.Post(c.conf.LogjamBaseUrl+"/answer", "application/json", reader)
|
||||
if err != nil {
|
||||
println(err.Error())
|
||||
return
|
||||
}
|
||||
if resp.StatusCode > 204 {
|
||||
println(resp.Status)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (c *RoomController) Answer(ctx *gin.Context) {
|
||||
var reqModel dto.SetSDPReqModel
|
||||
badReqSt := 400
|
||||
if err := ctx.ShouldBindJSON(&reqModel); c.helper.HandleIfErr(ctx, err, &badReqSt) {
|
||||
return
|
||||
}
|
||||
if !reqModel.Validate() {
|
||||
c.helper.ResponseUnprocessableEntity(ctx)
|
||||
return
|
||||
}
|
||||
err := c.repo.SetPeerAnswer(reqModel.RoomId, reqModel.ID, reqModel.SDP)
|
||||
if c.helper.HandleIfErr(ctx, err, nil) {
|
||||
return
|
||||
}
|
||||
c.helper.Response(ctx, struct{}{}, http.StatusNoContent)
|
||||
}
|
||||
|
||||
func (c *RoomController) ClosePeer(ctx *gin.Context) {
|
||||
var reqModel dto.PeerDTO
|
||||
badReqSt := 400
|
||||
if err := ctx.ShouldBindJSON(&reqModel); c.helper.HandleIfErr(ctx, err, &badReqSt) {
|
||||
return
|
||||
}
|
||||
if !reqModel.Validate() {
|
||||
c.helper.ResponseUnprocessableEntity(ctx)
|
||||
return
|
||||
}
|
||||
err := c.repo.ClosePeer(reqModel.RoomId, reqModel.ID)
|
||||
if c.helper.HandleIfErr(ctx, err, nil) {
|
||||
return
|
||||
}
|
||||
c.helper.Response(ctx, struct{}{}, http.StatusNoContent)
|
||||
}
|
|
@ -0,0 +1,54 @@
|
|||
module sourcecode.social/greatape/goldgorilla
|
||||
|
||||
go 1.20
|
||||
|
||||
require (
|
||||
github.com/gin-gonic/gin v1.9.1
|
||||
github.com/pion/rtcp v1.2.10
|
||||
github.com/pion/webrtc/v3 v3.2.12
|
||||
)
|
||||
|
||||
require (
|
||||
github.com/bytedance/sonic v1.9.1 // indirect
|
||||
github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311 // indirect
|
||||
github.com/davecgh/go-spew v1.1.1 // indirect
|
||||
github.com/gabriel-vasile/mimetype v1.4.2 // 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.14.0 // indirect
|
||||
github.com/goccy/go-json v0.10.2 // indirect
|
||||
github.com/google/uuid v1.3.0 // indirect
|
||||
github.com/json-iterator/go v1.1.12 // indirect
|
||||
github.com/klauspost/cpuid/v2 v2.2.4 // indirect
|
||||
github.com/leodido/go-urn v1.2.4 // indirect
|
||||
github.com/mattn/go-isatty v0.0.19 // 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.0.8 // indirect
|
||||
github.com/pion/datachannel v1.5.5 // indirect
|
||||
github.com/pion/dtls/v2 v2.2.7 // indirect
|
||||
github.com/pion/ice/v2 v2.3.9 // indirect
|
||||
github.com/pion/interceptor v0.1.17 // indirect
|
||||
github.com/pion/logging v0.2.2 // indirect
|
||||
github.com/pion/mdns v0.0.7 // indirect
|
||||
github.com/pion/randutil v0.1.0 // indirect
|
||||
github.com/pion/rtp v1.7.13 // indirect
|
||||
github.com/pion/sctp v1.8.7 // indirect
|
||||
github.com/pion/sdp/v3 v3.0.6 // indirect
|
||||
github.com/pion/srtp/v2 v2.0.15 // indirect
|
||||
github.com/pion/stun v0.6.1 // indirect
|
||||
github.com/pion/transport/v2 v2.2.1 // indirect
|
||||
github.com/pion/turn/v2 v2.1.2 // indirect
|
||||
github.com/pmezard/go-difflib v1.0.0 // indirect
|
||||
github.com/stretchr/testify v1.8.4 // indirect
|
||||
github.com/twitchyliquid64/golang-asm v0.15.1 // indirect
|
||||
github.com/ugorji/go/codec v1.2.11 // indirect
|
||||
golang.org/x/arch v0.3.0 // indirect
|
||||
golang.org/x/crypto v0.10.0 // indirect
|
||||
golang.org/x/net v0.11.0 // indirect
|
||||
golang.org/x/sys v0.9.0 // indirect
|
||||
golang.org/x/text v0.10.0 // indirect
|
||||
google.golang.org/protobuf v1.30.0 // indirect
|
||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||
)
|
|
@ -0,0 +1,245 @@
|
|||
github.com/bytedance/sonic v1.5.0/go.mod h1:ED5hyg4y6t3/9Ku1R6dU/4KyJ48DZ4jPhfY1O2AihPM=
|
||||
github.com/bytedance/sonic v1.9.1 h1:6iJ6NqdoxCDr6mbY8h18oSO+cShGSMRGCEo7F2h0x8s=
|
||||
github.com/bytedance/sonic v1.9.1/go.mod h1:i736AoUSYt75HyZLoJW9ERYxcy6eaN6h4BZXU064P/U=
|
||||
github.com/chenzhuoyu/base64x v0.0.0-20211019084208-fb5309c8db06/go.mod h1:DH46F32mSOjUmXrMHnKwZdA8wcEefY7UVqBKYGjpdQY=
|
||||
github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311 h1:qSGYFH7+jGhDF8vLC+iwCD4WpbV1EBDSzWkJODFLams=
|
||||
github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311/go.mod h1:b583jCggY9gE99b6G5LEC39OIiVsWj+R97kbl5odCEk=
|
||||
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/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/gabriel-vasile/mimetype v1.4.2 h1:w5qFW6JKBz9Y393Y4q372O9A7cUSequkh1Q7OhCmWKU=
|
||||
github.com/gabriel-vasile/mimetype v1.4.2/go.mod h1:zApsH/mKG4w07erKIaJPFiX0Tsq9BFQgN3qGY5GnNgA=
|
||||
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.9.1 h1:4idEAncQnU5cB7BeOkPtxjfCSye0AAm1R0RVIqJ+Jmg=
|
||||
github.com/gin-gonic/gin v1.9.1/go.mod h1:hPrL7YrpYKXt5YId3A/Tnip5kqbEAP+KLuI3SUcPTeU=
|
||||
github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/oXslEjJA=
|
||||
github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY=
|
||||
github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY=
|
||||
github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY=
|
||||
github.com/go-playground/validator/v10 v10.14.0 h1:vgvQWe3XCz3gIeFDm/HnTIbj6UGmg/+t63MyGU2n5js=
|
||||
github.com/go-playground/validator/v10 v10.14.0/go.mod h1:9iXMNT7sEkjXb0I+enO7QXmzG6QCsPWY4zveKFVRSyU=
|
||||
github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE=
|
||||
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/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8=
|
||||
github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA=
|
||||
github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs=
|
||||
github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w=
|
||||
github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0=
|
||||
github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
|
||||
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
|
||||
github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
|
||||
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
||||
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
||||
github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
||||
github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I=
|
||||
github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
|
||||
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.4 h1:acbojRNwl3o09bUq+yDCtZFc1aiwaAAxtcn8YkZXnvk=
|
||||
github.com/klauspost/cpuid/v2 v2.2.4/go.mod h1:RVVoqg1df56z8g3pUjL/3lE5UfnlrJX8tyFgg4nqhuY=
|
||||
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
|
||||
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
||||
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
||||
github.com/leodido/go-urn v1.2.4 h1:XlAE/cm/ms7TE/VMVoduSpNBoyc2dOxHs5MZSwAN63Q=
|
||||
github.com/leodido/go-urn v1.2.4/go.mod h1:7ZrI8mTSeBSHl/UaRyKQW1qZeMgak41ANeCNaVckg+4=
|
||||
github.com/mattn/go-isatty v0.0.19 h1:JITubQf0MOLdlGRuRq+jtsDlekdYPia9ZFsB8h/APPA=
|
||||
github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
|
||||
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/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M=
|
||||
github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
|
||||
github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A=
|
||||
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.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk=
|
||||
github.com/onsi/ginkgo v1.16.4/go.mod h1:dX+/inL/fNMqNlz0e9LfyB9TswhZpCVdJM/Z6Vvnwo0=
|
||||
github.com/onsi/ginkgo v1.16.5/go.mod h1:+E8gABHa3K6zRBolWtd+ROzc/U5bkGt0FwiG042wbpU=
|
||||
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.17.0/go.mod h1:HnhC7FXeEQY45zxNK3PPoIUhzk/80Xly9PcubAlGdZY=
|
||||
github.com/pelletier/go-toml/v2 v2.0.8 h1:0ctb6s9mE31h0/lhu+J6OPmVeDxJn+kYnJc2jZR9tGQ=
|
||||
github.com/pelletier/go-toml/v2 v2.0.8/go.mod h1:vuYfssBdrU2XDZ9bYydBu6t+6a6PYNcZljzZR9VXg+4=
|
||||
github.com/pion/datachannel v1.5.5 h1:10ef4kwdjije+M9d7Xm9im2Y3O6A6ccQb0zcqZcJew8=
|
||||
github.com/pion/datachannel v1.5.5/go.mod h1:iMz+lECmfdCMqFRhXhcA/219B0SQlbpoR2V118yimL0=
|
||||
github.com/pion/dtls/v2 v2.2.7 h1:cSUBsETxepsCSFSxC3mc/aDo14qQLMSL+O6IjG28yV8=
|
||||
github.com/pion/dtls/v2 v2.2.7/go.mod h1:8WiMkebSHFD0T+dIU+UeBaoV7kDhOW5oDCzZ7WZ/F9s=
|
||||
github.com/pion/ice/v2 v2.3.9 h1:7yZpHf3PhPxJGT4JkMj1Y8Rl5cQ6fB709iz99aeMd/U=
|
||||
github.com/pion/ice/v2 v2.3.9/go.mod h1:lT3kv5uUIlHfXHU/ZRD7uKD/ufM202+eTa3C/umgGf4=
|
||||
github.com/pion/interceptor v0.1.17 h1:prJtgwFh/gB8zMqGZoOgJPHivOwVAp61i2aG61Du/1w=
|
||||
github.com/pion/interceptor v0.1.17/go.mod h1:SY8kpmfVBvrbUzvj2bsXz7OJt5JvmVNZ+4Kjq7FcwrI=
|
||||
github.com/pion/logging v0.2.2 h1:M9+AIj/+pxNsDfAT64+MAVgJO0rsyLnoJKCqf//DoeY=
|
||||
github.com/pion/logging v0.2.2/go.mod h1:k0/tDVsRCX2Mb2ZEmTqNa7CWsQPc+YYCB7Q+5pahoms=
|
||||
github.com/pion/mdns v0.0.7 h1:P0UB4Sr6xDWEox0kTVxF0LmQihtCbSAdW0H2nEgkA3U=
|
||||
github.com/pion/mdns v0.0.7/go.mod h1:4iP2UbeFhLI/vWju/bw6ZfwjJzk0z8DNValjGxR/dD8=
|
||||
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 h1:nkr3uj+8Sp97zyItdN60tE/S6vk4al5CPRR6Gejsdjc=
|
||||
github.com/pion/rtcp v1.2.10/go.mod h1:ztfEwXZNLGyF1oQDttz/ZKIBaeeg/oWbRYqzBM9TL1I=
|
||||
github.com/pion/rtp v1.7.13 h1:qcHwlmtiI50t1XivvoawdCGTP4Uiypzfrsap+bijcoA=
|
||||
github.com/pion/rtp v1.7.13/go.mod h1:bDb5n+BFZxXx0Ea7E5qe+klMuqiBrP+w8XSjiWtCUko=
|
||||
github.com/pion/sctp v1.8.5/go.mod h1:SUFFfDpViyKejTAdwD1d/HQsCu+V/40cCs2nZIvC3s0=
|
||||
github.com/pion/sctp v1.8.7 h1:JnABvFakZueGAn4KU/4PSKg+GWbF6QWbKTWZOSGJjXw=
|
||||
github.com/pion/sctp v1.8.7/go.mod h1:g1Ul+ARqZq5JEmoFy87Q/4CePtKnTJ1QCL9dBBdN6AU=
|
||||
github.com/pion/sdp/v3 v3.0.6 h1:WuDLhtuFUUVpTfus9ILC4HRyHsW6TdugjEX/QY9OiUw=
|
||||
github.com/pion/sdp/v3 v3.0.6/go.mod h1:iiFWFpQO8Fy3S5ldclBkpXqmWy02ns78NOKoLLL0YQw=
|
||||
github.com/pion/srtp/v2 v2.0.15 h1:+tqRtXGsGwHC0G0IUIAzRmdkHvriF79IHVfZGfHrQoA=
|
||||
github.com/pion/srtp/v2 v2.0.15/go.mod h1:b/pQOlDrbB0HEH5EUAQXzSYxikFbNcNuKmF8tM0hCtw=
|
||||
github.com/pion/stun v0.6.1 h1:8lp6YejULeHBF8NmV8e2787BogQhduZugh5PdhDyyN4=
|
||||
github.com/pion/stun v0.6.1/go.mod h1:/hO7APkX4hZKu/D0f2lHzNyvdkTGtIy3NDmLR7kSz/8=
|
||||
github.com/pion/transport v0.14.1 h1:XSM6olwW+o8J4SCmOBb/BpwZypkHeyM0PGFCxNQBr40=
|
||||
github.com/pion/transport v0.14.1/go.mod h1:4tGmbk00NeYA3rUa9+n+dzCCoKkcy3YlYb99Jn2fNnI=
|
||||
github.com/pion/transport/v2 v2.0.0/go.mod h1:HS2MEBJTwD+1ZI2eSXSvHJx/HnzQqRy2/LXxt6eVMHc=
|
||||
github.com/pion/transport/v2 v2.1.0/go.mod h1:AdSw4YBZVDkZm8fpoz+fclXyQwANWmZAlDuQdctTThQ=
|
||||
github.com/pion/transport/v2 v2.2.0/go.mod h1:AdSw4YBZVDkZm8fpoz+fclXyQwANWmZAlDuQdctTThQ=
|
||||
github.com/pion/transport/v2 v2.2.1 h1:7qYnCBlpgSJNYMbLCKuSY9KbQdBFoETvPNETv0y4N7c=
|
||||
github.com/pion/transport/v2 v2.2.1/go.mod h1:cXXWavvCnFF6McHTft3DWS9iic2Mftcz1Aq29pGcU5g=
|
||||
github.com/pion/turn/v2 v2.1.2 h1:wj0cAoGKltaZ790XEGW9HwoUewqjliwmhtxCuB2ApyM=
|
||||
github.com/pion/turn/v2 v2.1.2/go.mod h1:1kjnPkBcex3dhCU2Am+AAmxDcGhLX3WnMfmkNpvSTQU=
|
||||
github.com/pion/webrtc/v3 v3.2.12 h1:pVqz5NdtTqyhKIhMcXR8bPp709kCf9blyAhDjoVRLvA=
|
||||
github.com/pion/webrtc/v3 v3.2.12/go.mod h1:/Oz6K95CGWaN+3No+Z0NYvgOPOr3aY8UyTlMm/dec3A=
|
||||
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/sclevine/agouti v3.0.0+incompatible/go.mod h1:b4WX9W9L1sfQKXeJf1mUTLZKJ48R1S7H23Ji7oFO5Bw=
|
||||
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/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
|
||||
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/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
|
||||
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
|
||||
github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
|
||||
github.com/stretchr/testify v1.8.3/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
|
||||
github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
|
||||
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
|
||||
github.com/twitchyliquid64/golang-asm v0.15.1 h1:SU5vSMR7hnwNxj24w34ZyCi/FmDZTkS4MhqMhdFk5YI=
|
||||
github.com/twitchyliquid64/golang-asm v0.15.1/go.mod h1:a1lVb/DtPvCB8fslRZhAngC2+aY1QWCk3Cedj/Gdt08=
|
||||
github.com/ugorji/go/codec v1.2.11 h1:BMaWp1Bb6fHwEtbplGBGJ498wD+LKlNSl25MjdZY4dU=
|
||||
github.com/ugorji/go/codec v1.2.11/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg=
|
||||
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
|
||||
golang.org/x/arch v0.0.0-20210923205945-b76863e36670/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8=
|
||||
golang.org/x/arch v0.3.0 h1:02VY4/ZcO/gBOH6PUaoiptASxtXU10jazRCP865E97k=
|
||||
golang.org/x/arch v0.3.0/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8=
|
||||
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-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.9.0 h1:LF6fAI+IutBocDJ2OT0Q1g8plpYljMZ4+lty+dsqw3g=
|
||||
golang.org/x/crypto v0.9.0/go.mod h1:yrmDGqONDYtNj3tH8X9dzUun2m2lzPa9ngI6/RUPGR0=
|
||||
golang.org/x/crypto v0.10.0 h1:LKqV2xt9+kDzSTfOhx4FrkEBcMrAgHSYgzywV9zcGmM=
|
||||
golang.org/x/crypto v0.10.0/go.mod h1:o4eNf7Ede1fv+hwOwZsTHl9EsPFO6q6ZvYR8vYfY45I=
|
||||
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
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-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
|
||||
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
||||
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||
golang.org/x/net v0.0.0-20210428140749-89ef3d95e781/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk=
|
||||
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
|
||||
golang.org/x/net v0.1.0/go.mod h1:Cx3nUiGt4eDBEyega/BKRp+/AlGL8hYe7U9odMt2Cco=
|
||||
golang.org/x/net v0.5.0/go.mod h1:DivGGAXEgPSlEBzxGzZI+ZLohi+xUj054jfeKui00ws=
|
||||
golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
|
||||
golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc=
|
||||
golang.org/x/net v0.9.0/go.mod h1:d48xBJpPfHeWQsugry2m+kC02ZBRGRgulfHnEXEuWns=
|
||||
golang.org/x/net v0.10.0 h1:X2//UzNDwYmtCLn7To6G58Wr6f5ahEAQgKNzv9Y951M=
|
||||
golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg=
|
||||
golang.org/x/net v0.11.0 h1:Gi2tvZIJyBtO9SDr1q9h5hEQCp/4L2RQ+ar0qjx2oNU=
|
||||
golang.org/x/net v0.11.0/go.mod h1:2L/ixqYpgIVXmeoSA/4Lu7BzTG4KIyPIryS4IsOd1oQ=
|
||||
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=
|
||||
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-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/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-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/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-20220704084225-05e143d24a9e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.4.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.8.0 h1:EBmGv8NaZBZTWvrbjNoL6HVt+IVy3QDQpJs7VRIw3tU=
|
||||
golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.9.0 h1:KS/R3tvhPqvJvwcKfnBHJwwthS11LRhmM5D59eEXa0s=
|
||||
golang.org/x/sys v0.9.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
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=
|
||||
golang.org/x/term v0.4.0/go.mod h1:9P2UbLfCdcvo3p/nzKvsmas4TnlujnuoV9hGgYzW1lQ=
|
||||
golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
|
||||
golang.org/x/term v0.6.0/go.mod h1:m6U89DPEgQRMq3DNkDClhWw02AUbt2daBVO4cn4Hv9U=
|
||||
golang.org/x/term v0.7.0/go.mod h1:P32HKFT3hSsZrRxla30E9HqToFYAQPCMs/zFMBUFqPY=
|
||||
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/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
|
||||
golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
|
||||
golang.org/x/text v0.6.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
|
||||
golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
|
||||
golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
|
||||
golang.org/x/text v0.9.0 h1:2sjJmO8cDvYveuX97RDLsxlyUxLl+GHoLxBiRdHllBE=
|
||||
golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
|
||||
golang.org/x/text v0.10.0 h1:UpjohKhiEgNc0CSauXmwYftY1+LlaC75SJwh0SgCX58=
|
||||
golang.org/x/text v0.10.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
|
||||
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=
|
||||
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
|
||||
golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
|
||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
|
||||
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
|
||||
google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
|
||||
google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE=
|
||||
google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo=
|
||||
google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
|
||||
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
|
||||
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
|
||||
google.golang.org/protobuf v1.30.0 h1:kPPoIgf3TsEvrm0PFe15JQ+570QVxYzEvvHqChK+cng=
|
||||
google.golang.org/protobuf v1.30.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
|
||||
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/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
|
||||
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
|
||||
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=
|
||||
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=
|
||||
rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4=
|
|
@ -0,0 +1,21 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"flag"
|
||||
"strings"
|
||||
)
|
||||
|
||||
func main() {
|
||||
src := flag.String("src", ":8080", "listenhost:listenPort")
|
||||
logjamBaseUrl := flag.String("logjam-base-url", "https://example.com", "logjam base url(shouldn't end with /)")
|
||||
targetRoom := flag.String("targetRoom", "testyroom", "target room")
|
||||
|
||||
flag.Parse()
|
||||
|
||||
if strings.HasSuffix(*logjamBaseUrl, "/") {
|
||||
panic("logjam-base-url shouldn't end with /")
|
||||
}
|
||||
app := App{}
|
||||
app.Init(*src, *logjamBaseUrl, *targetRoom)
|
||||
app.Run()
|
||||
}
|
|
@ -0,0 +1,5 @@
|
|||
package models
|
||||
|
||||
type MessageResponse struct {
|
||||
Message string `json:"message"`
|
||||
}
|
|
@ -0,0 +1,6 @@
|
|||
package models
|
||||
|
||||
type ConfigModel struct {
|
||||
LogjamBaseUrl string `json:"logjamBaseUrl"`
|
||||
TargetRoom string `json:"targetRoom"`
|
||||
}
|
|
@ -0,0 +1,36 @@
|
|||
package dto
|
||||
|
||||
import "github.com/pion/webrtc/v3"
|
||||
|
||||
type PeerDTO struct {
|
||||
RoomId string `json:"roomId"`
|
||||
ID uint64 `json:"id"`
|
||||
}
|
||||
|
||||
func (model *PeerDTO) Validate() bool {
|
||||
return len(model.RoomId) > 0
|
||||
}
|
||||
|
||||
type CreatePeerReqModel struct {
|
||||
PeerDTO
|
||||
CanPublish bool `json:"canPublish"`
|
||||
IsCaller bool `json:"isCaller"`
|
||||
}
|
||||
|
||||
type AddPeerICECandidateReqModel struct {
|
||||
PeerDTO
|
||||
ICECandidate webrtc.ICECandidateInit `json:"iceCandidate"`
|
||||
}
|
||||
|
||||
func (model *AddPeerICECandidateReqModel) Validate() bool {
|
||||
return model.PeerDTO.Validate() // && len(model.ICECandidate.Candidate) > 0
|
||||
}
|
||||
|
||||
type SetSDPReqModel struct {
|
||||
PeerDTO
|
||||
SDP webrtc.SessionDescription `json:"sdp"`
|
||||
}
|
||||
|
||||
func (model *SetSDPReqModel) Validate() bool {
|
||||
return model.PeerDTO.Validate() && len(model.SDP.SDP) > 0
|
||||
}
|
|
@ -0,0 +1,42 @@
|
|||
package models
|
||||
|
||||
type BigError struct {
|
||||
message string `json:"message"`
|
||||
errCode int `json:"-"`
|
||||
metaData any `json:"meta"`
|
||||
}
|
||||
|
||||
func (err BigError) Error() string {
|
||||
return err.message
|
||||
}
|
||||
|
||||
func (err BigError) ErrCode() int {
|
||||
return err.errCode
|
||||
}
|
||||
|
||||
func (err BigError) Meta() any {
|
||||
return err.metaData
|
||||
}
|
||||
|
||||
func NewError(msg string, errCode int, meta any) BigError {
|
||||
if meta == nil {
|
||||
meta = struct {
|
||||
}{}
|
||||
}
|
||||
return BigError{
|
||||
message: msg,
|
||||
errCode: errCode,
|
||||
metaData: meta,
|
||||
}
|
||||
}
|
||||
|
||||
func (BigError) FromErr(err error, errCode int, meta any) BigError {
|
||||
if meta == nil {
|
||||
meta = err
|
||||
}
|
||||
return BigError{
|
||||
message: err.Error(),
|
||||
errCode: errCode,
|
||||
metaData: meta,
|
||||
}
|
||||
}
|
|
@ -0,0 +1,412 @@
|
|||
package repositories
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"github.com/pion/rtcp"
|
||||
"github.com/pion/webrtc/v3"
|
||||
"sourcecode.social/greatape/goldgorilla/models"
|
||||
"sourcecode.social/greatape/goldgorilla/models/dto"
|
||||
"log"
|
||||
"net/http"
|
||||
"sync"
|
||||
"time"
|
||||
)
|
||||
|
||||
type Track struct {
|
||||
OwnerId uint64
|
||||
TrackLocal *webrtc.TrackLocalStaticRTP
|
||||
}
|
||||
|
||||
type Peer struct {
|
||||
ID uint64
|
||||
Conn *webrtc.PeerConnection
|
||||
CanPublish bool
|
||||
}
|
||||
|
||||
type Room struct {
|
||||
*sync.Mutex
|
||||
Peers map[uint64]*Peer
|
||||
trackLock *sync.Mutex
|
||||
Tracks map[string]*Track
|
||||
}
|
||||
|
||||
type RoomRepository struct {
|
||||
Rooms map[string]*Room
|
||||
conf *models.ConfigModel
|
||||
*sync.Mutex
|
||||
}
|
||||
|
||||
func NewRoomRepository(conf *models.ConfigModel) *RoomRepository {
|
||||
return &RoomRepository{
|
||||
Mutex: &sync.Mutex{},
|
||||
Rooms: make(map[string]*Room),
|
||||
conf: conf,
|
||||
}
|
||||
}
|
||||
|
||||
func (r *RoomRepository) doesRoomExists(id string) bool {
|
||||
if _, exists := r.Rooms[id]; exists {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (r *RoomRepository) doesPeerExists(roomId string, id uint64) bool {
|
||||
if !r.doesRoomExists(roomId) {
|
||||
return false
|
||||
}
|
||||
if _, exists := r.Rooms[roomId].Peers[id]; exists {
|
||||
return true
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
func (r *RoomRepository) CreatePeer(roomId string, id uint64, canPublish, isCaller bool) (*webrtc.SessionDescription, error) {
|
||||
r.Lock()
|
||||
|
||||
if !r.doesRoomExists(roomId) {
|
||||
room := &Room{
|
||||
Mutex: &sync.Mutex{},
|
||||
Peers: make(map[uint64]*Peer),
|
||||
trackLock: &sync.Mutex{},
|
||||
Tracks: make(map[string]*Track),
|
||||
}
|
||||
r.Rooms[roomId] = room
|
||||
go func() {
|
||||
for range time.NewTicker(3 * time.Second).C {
|
||||
room.Lock()
|
||||
for _, peer := range room.Peers {
|
||||
for _, receiver := range peer.Conn.GetReceivers() {
|
||||
if receiver.Track() == nil {
|
||||
continue
|
||||
}
|
||||
|
||||
go peer.Conn.WriteRTCP([]rtcp.Packet{
|
||||
&rtcp.PictureLossIndication{
|
||||
MediaSSRC: uint32(receiver.Track().SSRC()),
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
}
|
||||
room.Unlock()
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
||||
r.Unlock()
|
||||
room := r.Rooms[roomId]
|
||||
room.Lock()
|
||||
defer room.Unlock()
|
||||
|
||||
peerConn, err := webrtc.NewPeerConnection(webrtc.Configuration{})
|
||||
if err != nil {
|
||||
return nil, models.NewError("can't create peer connection", 500, models.MessageResponse{Message: err.Error()})
|
||||
}
|
||||
for _, typ := range []webrtc.RTPCodecType{webrtc.RTPCodecTypeVideo, webrtc.RTPCodecTypeAudio} {
|
||||
if _, err := peerConn.AddTransceiverFromKind(typ, webrtc.RTPTransceiverInit{
|
||||
Direction: webrtc.RTPTransceiverDirectionSendrecv,
|
||||
}); err != nil {
|
||||
return nil, models.NewError("unhandled error, contact support #1313", 500, err)
|
||||
}
|
||||
}
|
||||
|
||||
peerConn.OnICECandidate(func(ic *webrtc.ICECandidate) {
|
||||
r.onPeerICECandidate(roomId, id, ic)
|
||||
})
|
||||
peerConn.OnConnectionStateChange(func(state webrtc.PeerConnectionState) {
|
||||
r.onPeerConnectionStateChange(roomId, id, state)
|
||||
})
|
||||
peerConn.OnTrack(func(remote *webrtc.TrackRemote, receiver *webrtc.RTPReceiver) {
|
||||
r.onPeerTrack(roomId, id, remote, receiver)
|
||||
})
|
||||
|
||||
var sdp *webrtc.SessionDescription
|
||||
if !isCaller {
|
||||
offer, err := peerConn.CreateOffer(nil)
|
||||
if err != nil {
|
||||
println(err.Error())
|
||||
peerConn.Close()
|
||||
return nil, models.NewError("unhandled error, contact support #1314", 500, err)
|
||||
}
|
||||
err = peerConn.SetLocalDescription(offer)
|
||||
if err != nil {
|
||||
println(err.Error())
|
||||
peerConn.Close()
|
||||
return nil, models.NewError("unhandled error, contact support #1315", 500, err)
|
||||
}
|
||||
sdp = &offer
|
||||
}
|
||||
|
||||
room.Peers[id] = &Peer{
|
||||
ID: id,
|
||||
Conn: peerConn,
|
||||
}
|
||||
|
||||
return sdp, nil
|
||||
}
|
||||
|
||||
func (r *RoomRepository) onPeerICECandidate(roomId string, id uint64, ic *webrtc.ICECandidate) {
|
||||
if ic == nil {
|
||||
return
|
||||
}
|
||||
reqModel := dto.AddPeerICECandidateReqModel{
|
||||
PeerDTO: dto.PeerDTO{
|
||||
RoomId: roomId,
|
||||
ID: id,
|
||||
},
|
||||
ICECandidate: ic.ToJSON(),
|
||||
}
|
||||
serializedReqBody, err := json.Marshal(reqModel)
|
||||
if err != nil {
|
||||
println(err.Error())
|
||||
return
|
||||
}
|
||||
resp, err := http.Post(r.conf.LogjamBaseUrl+"/ice", "application/json", bytes.NewReader(serializedReqBody))
|
||||
if err != nil {
|
||||
println(err.Error())
|
||||
return
|
||||
}
|
||||
if resp.StatusCode > 204 {
|
||||
println("POST /ice", resp.StatusCode)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
func (r *RoomRepository) onPeerConnectionStateChange(roomId string, id uint64, newState webrtc.PeerConnectionState) {
|
||||
r.Lock()
|
||||
|
||||
if !r.doesRoomExists(roomId) {
|
||||
r.Unlock()
|
||||
return
|
||||
}
|
||||
r.Unlock()
|
||||
room := r.Rooms[roomId]
|
||||
room.Lock()
|
||||
defer room.Unlock()
|
||||
|
||||
switch newState {
|
||||
case webrtc.PeerConnectionStateFailed:
|
||||
if err := room.Peers[id].Conn.Close(); err != nil {
|
||||
log.Print(err)
|
||||
}
|
||||
case webrtc.PeerConnectionStateClosed:
|
||||
delete(room.Peers, id)
|
||||
}
|
||||
}
|
||||
|
||||
func (r *RoomRepository) onPeerTrack(roomId string, id uint64, remote *webrtc.TrackRemote, receiver *webrtc.RTPReceiver) {
|
||||
fmt.Println("got a track!", remote.ID(), remote.StreamID(), remote.Kind().String())
|
||||
r.Lock()
|
||||
if !r.doesRoomExists(roomId) {
|
||||
r.Unlock()
|
||||
return
|
||||
}
|
||||
room := r.Rooms[roomId]
|
||||
r.Unlock()
|
||||
|
||||
trackLocal, err := webrtc.NewTrackLocalStaticRTP(remote.Codec().RTPCodecCapability, remote.ID(), remote.StreamID())
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
room.trackLock.Lock()
|
||||
room.Tracks[remote.ID()] = &Track{
|
||||
OwnerId: id,
|
||||
TrackLocal: trackLocal,
|
||||
}
|
||||
room.trackLock.Unlock()
|
||||
|
||||
defer func() {
|
||||
room.trackLock.Lock()
|
||||
delete(room.Tracks, remote.ID())
|
||||
room.trackLock.Unlock()
|
||||
r.updatePCTracks(roomId)
|
||||
}()
|
||||
go r.updatePCTracks(roomId)
|
||||
buffer := make([]byte, 1500)
|
||||
for {
|
||||
n, _, err := remote.Read(buffer)
|
||||
if err != nil {
|
||||
println(err.Error())
|
||||
return
|
||||
}
|
||||
if _, err = trackLocal.Write(buffer[:n]); err != nil {
|
||||
println(err.Error())
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (r *RoomRepository) updatePCTracks(roomId string) {
|
||||
r.Lock()
|
||||
if !r.doesRoomExists(roomId) {
|
||||
r.Unlock()
|
||||
return
|
||||
}
|
||||
room := r.Rooms[roomId]
|
||||
defer r.Unlock()
|
||||
room.Lock()
|
||||
defer room.Unlock()
|
||||
for _, peer := range room.Peers {
|
||||
if peer.Conn == nil {
|
||||
continue
|
||||
}
|
||||
alreadySentTracks := map[string]*webrtc.RTPSender{}
|
||||
receivingPeerTracks := map[string]*webrtc.RTPReceiver{}
|
||||
for _, rtpSender := range peer.Conn.GetSenders() {
|
||||
if rtpSender.Track() == nil {
|
||||
continue
|
||||
}
|
||||
track := rtpSender.Track()
|
||||
alreadySentTracks[track.ID()] = rtpSender
|
||||
}
|
||||
for _, rtpReceiver := range peer.Conn.GetReceivers() {
|
||||
if rtpReceiver.Track() == nil {
|
||||
continue
|
||||
}
|
||||
track := rtpReceiver.Track()
|
||||
receivingPeerTracks[track.ID()] = rtpReceiver
|
||||
}
|
||||
room.trackLock.Lock()
|
||||
for id, track := range room.Tracks {
|
||||
_, alreadySend := alreadySentTracks[id]
|
||||
_, alreadyReceiver := receivingPeerTracks[id]
|
||||
if track.OwnerId != peer.ID && (!alreadySend && !alreadyReceiver) {
|
||||
go func(peer *Peer, track *Track) {
|
||||
println("add track")
|
||||
_, err := peer.Conn.AddTrack(track.TrackLocal)
|
||||
if err != nil {
|
||||
println(err.Error())
|
||||
}
|
||||
}(peer, track)
|
||||
}
|
||||
}
|
||||
room.trackLock.Unlock()
|
||||
|
||||
/*room.trackLock.Lock()
|
||||
for trackId, _ := range alreadySentTracks {
|
||||
if _, exists := room.Tracks[trackId]; !exists {
|
||||
go func(peer *Peer, rtpSender *webrtc.RTPSender) {
|
||||
err := peer.Conn.RemoveTrack(rtpSender)
|
||||
if err != nil {
|
||||
println(err.Error())
|
||||
}
|
||||
}(peer, alreadySentTracks[trackId])
|
||||
}
|
||||
}
|
||||
room.trackLock.Unlock()*/
|
||||
}
|
||||
}
|
||||
|
||||
func (r *RoomRepository) AddPeerIceCandidate(roomId string, id uint64, ic webrtc.ICECandidateInit) error {
|
||||
r.Lock()
|
||||
if !r.doesRoomExists(roomId) {
|
||||
r.Unlock()
|
||||
return models.NewError("room doesn't exists", 403, map[string]any{"roomId": roomId})
|
||||
}
|
||||
r.Unlock()
|
||||
room := r.Rooms[roomId]
|
||||
room.Lock()
|
||||
defer room.Unlock()
|
||||
|
||||
if !r.doesPeerExists(roomId, id) {
|
||||
return models.NewError("no such a peer with this id in this room", 403, map[string]any{"roomId": roomId, "peerId": id})
|
||||
}
|
||||
|
||||
err := room.Peers[id].Conn.AddICECandidate(ic)
|
||||
if err != nil {
|
||||
return models.NewError(err.Error(), 500, models.MessageResponse{Message: err.Error()})
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r *RoomRepository) SetPeerAnswer(roomId string, id uint64, answer webrtc.SessionDescription) error {
|
||||
r.Lock()
|
||||
if !r.doesRoomExists(roomId) {
|
||||
r.Unlock()
|
||||
return models.NewError("room doesn't exists", 403, map[string]any{"roomId": roomId})
|
||||
}
|
||||
r.Unlock()
|
||||
room := r.Rooms[roomId]
|
||||
room.Lock()
|
||||
defer room.Unlock()
|
||||
|
||||
if !r.doesPeerExists(roomId, id) {
|
||||
return models.NewError("no such a peer with this id in this room", 403, map[string]any{"roomId": roomId, "peerId": id})
|
||||
}
|
||||
|
||||
err := room.Peers[id].Conn.SetRemoteDescription(answer)
|
||||
if err != nil {
|
||||
return models.NewError(err.Error(), 500, models.MessageResponse{Message: err.Error()})
|
||||
}
|
||||
return nil
|
||||
}
|
||||
func (r *RoomRepository) SetPeerOffer(roomId string, id uint64, offer webrtc.SessionDescription) (sdpAnswer *webrtc.SessionDescription, err error) {
|
||||
r.Lock()
|
||||
if !r.doesRoomExists(roomId) {
|
||||
r.Unlock()
|
||||
return nil, models.NewError("room doesn't exists", 403, map[string]any{"roomId": roomId})
|
||||
}
|
||||
r.Unlock()
|
||||
room := r.Rooms[roomId]
|
||||
room.Lock()
|
||||
defer room.Unlock()
|
||||
|
||||
if !r.doesPeerExists(roomId, id) {
|
||||
return nil, models.NewError("no such a peer with this id in this room", 403, map[string]any{"roomId": roomId, "peerId": id})
|
||||
}
|
||||
|
||||
err = room.Peers[id].Conn.SetRemoteDescription(offer)
|
||||
if err != nil {
|
||||
return nil, models.NewError(err.Error(), 500, models.MessageResponse{Message: err.Error()})
|
||||
}
|
||||
answer, err := room.Peers[id].Conn.CreateAnswer(nil)
|
||||
if err != nil {
|
||||
return nil, models.NewError(err.Error(), 500, models.MessageResponse{Message: err.Error()})
|
||||
}
|
||||
err = room.Peers[id].Conn.SetLocalDescription(answer)
|
||||
if err != nil {
|
||||
return nil, models.NewError(err.Error(), 500, models.MessageResponse{Message: err.Error()})
|
||||
}
|
||||
|
||||
return &answer, nil
|
||||
}
|
||||
|
||||
func (r *RoomRepository) AllowPublish(roomId string, id uint64) error {
|
||||
r.Lock()
|
||||
if !r.doesRoomExists(roomId) {
|
||||
r.Unlock()
|
||||
return models.NewError("room doesn't exists", 403, map[string]any{"roomId": roomId})
|
||||
}
|
||||
r.Unlock()
|
||||
room := r.Rooms[roomId]
|
||||
room.Lock()
|
||||
defer room.Unlock()
|
||||
|
||||
if !r.doesPeerExists(roomId, id) {
|
||||
return models.NewError("no such a peer with this id in this room", 403, map[string]any{"roomId": roomId, "peerId": id})
|
||||
}
|
||||
|
||||
room.Peers[id].CanPublish = true
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r *RoomRepository) ClosePeer(roomId string, id uint64) error {
|
||||
r.Lock()
|
||||
if !r.doesRoomExists(roomId) {
|
||||
r.Unlock()
|
||||
return models.NewError("room doesn't exists", 403, map[string]any{"roomId": roomId})
|
||||
}
|
||||
r.Unlock()
|
||||
room := r.Rooms[roomId]
|
||||
room.Lock()
|
||||
defer room.Unlock()
|
||||
|
||||
if !r.doesPeerExists(roomId, id) {
|
||||
return models.NewError("no such a peer with this id in this room", 403, map[string]any{"roomId": roomId, "peerId": id})
|
||||
}
|
||||
return room.Peers[id].Conn.Close()
|
||||
}
|
|
@ -0,0 +1,16 @@
|
|||
package routers
|
||||
|
||||
import (
|
||||
"github.com/gin-gonic/gin"
|
||||
"sourcecode.social/greatape/goldgorilla/controllers"
|
||||
)
|
||||
|
||||
func registerRoomRoutes(rg *gin.RouterGroup, ctrl *controllers.RoomController) {
|
||||
|
||||
rg.POST("/peer", ctrl.CreatePeer)
|
||||
rg.DELETE("/peer", ctrl.ClosePeer)
|
||||
rg.POST("/ice", ctrl.AddICECandidate)
|
||||
rg.POST("/answer", ctrl.Answer)
|
||||
rg.POST("/offer", ctrl.Offer)
|
||||
|
||||
}
|
|
@ -0,0 +1,23 @@
|
|||
package routers
|
||||
|
||||
import (
|
||||
"github.com/gin-gonic/gin"
|
||||
"sourcecode.social/greatape/goldgorilla/controllers"
|
||||
)
|
||||
|
||||
type Router struct {
|
||||
router *gin.Engine
|
||||
}
|
||||
|
||||
func (r *Router) RegisterRoutes(rCtrl *controllers.RoomController) error {
|
||||
gin.SetMode(gin.ReleaseMode)
|
||||
r.router = gin.Default()
|
||||
registerRoomRoutes(r.router.Group("/room"), rCtrl)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r *Router) Serve(addr string) error {
|
||||
println("serving on ", addr)
|
||||
return r.router.Run(addr)
|
||||
}
|
Loading…
Reference in New Issue