├── README.md ├── webcodecs-quic ├── README.md ├── go.mod ├── index.html ├── server.csr ├── server.crt ├── server.key ├── script.js ├── main.go ├── quic_transport_server.py ├── cbor.js └── go.sum ├── webcodecs-websocket ├── go.mod ├── main.go ├── index.html ├── player.js ├── go.sum ├── pusher.js └── cbor.js ├── webcodecs-datachannel ├── go.mod ├── index.html ├── main.go ├── player.js ├── pusher.js ├── cbor.js └── go.sum └── .gitignore /README.md: -------------------------------------------------------------------------------- 1 | # webcodecs-play 2 | 3 | play WebCodecs with WebTransport/WebSocket/Datachannel 4 | -------------------------------------------------------------------------------- /webcodecs-quic/README.md: -------------------------------------------------------------------------------- 1 | # webcodecs-play 2 | 3 | 4 | play WebCodecs + WebTransport 5 | 6 | 7 | -------------------------------------------------------------------------------- /webcodecs-websocket/go.mod: -------------------------------------------------------------------------------- 1 | module github.com/notedit/webcodecs-play 2 | 3 | go 1.15 4 | 5 | require ( 6 | github.com/gin-gonic/gin v1.7.1 7 | github.com/gorilla/websocket v1.4.2 8 | ) 9 | -------------------------------------------------------------------------------- /webcodecs-datachannel/go.mod: -------------------------------------------------------------------------------- 1 | module github.com/notedit/webcodecs-play 2 | 3 | go 1.15 4 | 5 | require ( 6 | github.com/gin-contrib/cors v1.3.1 7 | github.com/gin-gonic/gin v1.7.1 8 | github.com/gorilla/websocket v1.4.2 9 | github.com/pion/webrtc/v3 v3.1.11 10 | ) 11 | -------------------------------------------------------------------------------- /webcodecs-quic/go.mod: -------------------------------------------------------------------------------- 1 | module github.com/notedit/webcodecs-play 2 | 3 | go 1.15 4 | 5 | require ( 6 | github.com/gin-contrib/static v0.0.0-20200916080430-d45d9a37d28e // indirect 7 | github.com/gin-gonic/gin v1.6.3 8 | github.com/gorilla/websocket v1.4.2 9 | github.com/lucas-clemente/quic-go v0.19.3 // indirect 10 | ) 11 | -------------------------------------------------------------------------------- /webcodecs-quic/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | WebCodecs + WebTransport Play 7 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 37 | 38 | 39 | 40 | -------------------------------------------------------------------------------- /webcodecs-quic/server.csr: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE REQUEST----- 2 | MIICWTCCAUECAQAwFDESMBAGA1UEAwwJbG9jYWxob3N0MIIBIjANBgkqhkiG9w0B 3 | AQEFAAOCAQ8AMIIBCgKCAQEA1ZUi7mzvRJbFXNKJgHyhLY/5qCrwq2WFM428V7Yd 4 | EyuGs49I/ptVeHGgDYd5g7yRtP/Jp8LBX/MMilcCoT3lb795FHBHGQT3ahv1kcmu 5 | AYYelWrVlHrs//FY9sq9O5ptDEcQgtLMpPp1/Wk2g4GrtGqovOCIiQNzD9fgh13k 6 | aGWa9lSiO2Vm1OxotupocAMoJUKSOzi+JWM0P4QtdATFC1PIpBuEL48r/aoTG5iD 7 | V/tXrAGHX1Cry9wd5ZIoftTYY3vibpKrYMHhea5//SDOerTzWEP/DAq6YXMxNtL1 8 | 8thyqhCC1bJ4TFsRW29gEu8g0QIdhfs8pFR2wnut5uW9/wIDAQABoAAwDQYJKoZI 9 | hvcNAQELBQADggEBAMGo554PNpL2j+4NahoXZStzkJP+zkjtQ0b4p9PmMpPETRwb 10 | pEi6Cllp6G9WkrpxLZE6+wTEtmUSmYAQXPS8cKR4cm0Cl2aMrp1HfI+0kqyo5pVl 11 | LpU28HDO+hRVE1t0g1WZoFNpIDsP43iSxTLAQhzmRYWUSLPvRRsUZ4tnAz8hu85x 12 | 3oKz9EduE2YsvH+9DBC5RiwWeL2TA5EEpx93HAX9fv4zePzg4y0TZ82Bzun15VG0 13 | yDL8zcXNJUhWb9W7o3PR0jWLr9ysHilUjv1UtlLDBsDK7kH54pY8m41EDUgHkf2C 14 | HEM9aiRr38DmcwToiqBNlZukPY74upNUwkv8V/A= 15 | -----END CERTIFICATE REQUEST----- 16 | -------------------------------------------------------------------------------- /webcodecs-quic/server.crt: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIICpDCCAYwCCQD7XERHpe0TRDANBgkqhkiG9w0BAQsFADAUMRIwEAYDVQQDDAls 3 | b2NhbGhvc3QwHhcNMjEwMTMxMTEwNzU5WhcNMjIwMTMxMTEwNzU5WjAUMRIwEAYD 4 | VQQDDAlsb2NhbGhvc3QwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDV 5 | lSLubO9ElsVc0omAfKEtj/moKvCrZYUzjbxXth0TK4azj0j+m1V4caANh3mDvJG0 6 | /8mnwsFf8wyKVwKhPeVvv3kUcEcZBPdqG/WRya4Bhh6VatWUeuz/8Vj2yr07mm0M 7 | RxCC0syk+nX9aTaDgau0aqi84IiJA3MP1+CHXeRoZZr2VKI7ZWbU7Gi26mhwAygl 8 | QpI7OL4lYzQ/hC10BMULU8ikG4Qvjyv9qhMbmINX+1esAYdfUKvL3B3lkih+1Nhj 9 | e+JukqtgweF5rn/9IM56tPNYQ/8MCrphczE20vXy2HKqEILVsnhMWxFbb2AS7yDR 10 | Ah2F+zykVHbCe63m5b3/AgMBAAEwDQYJKoZIhvcNAQELBQADggEBALmNQ33leX67 11 | YrzaeEPUu5TM7TGjKxM0SafWVdvw1E3r945AtA8CjMmvWindv3yXwhblIJdyywJj 12 | wjAYjDnCOkw6MlQrL8s+6bBfW0ZYPbK3eV8RjtnzOFa5gAo0wdcDjo5D/dayKwGL 13 | bWz4b6zLdpnIuLNJN/jBMOwyZvXz5i/8PfnOPlc32HaHTpvpwng0RBKJEQdxa1Ue 14 | gbprWiuiUQCwBmNTuJHZR89Fa3JEv2grpXc7GYBbuzcgetnCn9K7WfBXwA6iY9H2 15 | NAgdJAHN3N63VtXS/4zQzFYTayf044ZhHUgKq/gn+K7tLUcZEIALCqsdR2gwBGA4 16 | Xe9Zj2kgWCw= 17 | -----END CERTIFICATE----- 18 | -------------------------------------------------------------------------------- /webcodecs-websocket/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "net/http" 6 | "sync" 7 | 8 | "github.com/gin-gonic/gin" 9 | "github.com/gorilla/websocket" 10 | ) 11 | 12 | var upGrader = websocket.Upgrader{ 13 | CheckOrigin: func(r *http.Request) bool { 14 | return true 15 | }, 16 | } 17 | 18 | var pubws *websocket.Conn 19 | var subwss sync.Map 20 | 21 | func pubChannel(c *gin.Context) { 22 | var err error 23 | pubws, err = upGrader.Upgrade(c.Writer, c.Request, nil) 24 | if err != nil { 25 | return 26 | } 27 | defer pubws.Close() 28 | 29 | for { 30 | messageType, p, err := pubws.ReadMessage() 31 | if err != nil { 32 | fmt.Println("error ", err) 33 | return 34 | } 35 | 36 | subwss.Range(func(k, _ interface{}) bool { 37 | s := k.(*websocket.Conn) 38 | s.WriteMessage(messageType, p) 39 | return true 40 | }) 41 | } 42 | } 43 | 44 | func subChannel(c *gin.Context) { 45 | subws, err := upGrader.Upgrade(c.Writer, c.Request, nil) 46 | if err != nil { 47 | return 48 | } 49 | defer subws.Close() 50 | 51 | subwss.Store(subws, "") 52 | 53 | for { 54 | _, _, err = subws.ReadMessage() 55 | 56 | if err != nil { 57 | fmt.Println("error ", err) 58 | break 59 | } 60 | } 61 | 62 | subwss.Delete(subws) 63 | } 64 | 65 | func index(c *gin.Context) { 66 | c.HTML(http.StatusOK, "index.html", gin.H{}) 67 | } 68 | 69 | func main() { 70 | 71 | address := ":8000" 72 | r := gin.Default() 73 | r.LoadHTMLFiles("./index.html") 74 | r.StaticFile("/pusher.js", "./pusher.js") 75 | r.StaticFile("/player.js", "./player.js") 76 | r.StaticFile("/cbor.js", "./cbor.js") 77 | r.GET("/", index) 78 | 79 | r.GET("/pub", pubChannel) 80 | r.GET("/sub", subChannel) 81 | 82 | r.Run(address) 83 | } 84 | -------------------------------------------------------------------------------- /webcodecs-quic/server.key: -------------------------------------------------------------------------------- 1 | -----BEGIN RSA PRIVATE KEY----- 2 | MIIEpQIBAAKCAQEA1ZUi7mzvRJbFXNKJgHyhLY/5qCrwq2WFM428V7YdEyuGs49I 3 | /ptVeHGgDYd5g7yRtP/Jp8LBX/MMilcCoT3lb795FHBHGQT3ahv1kcmuAYYelWrV 4 | lHrs//FY9sq9O5ptDEcQgtLMpPp1/Wk2g4GrtGqovOCIiQNzD9fgh13kaGWa9lSi 5 | O2Vm1OxotupocAMoJUKSOzi+JWM0P4QtdATFC1PIpBuEL48r/aoTG5iDV/tXrAGH 6 | X1Cry9wd5ZIoftTYY3vibpKrYMHhea5//SDOerTzWEP/DAq6YXMxNtL18thyqhCC 7 | 1bJ4TFsRW29gEu8g0QIdhfs8pFR2wnut5uW9/wIDAQABAoIBAQDFYQagGpHf7AnG 8 | Z1blI8f8CELrE4vIiZBYfVKiKE2kSqQ4SmFl0f1hynfkKN+2S8zH3V7pp0T3u/BJ 9 | 5HEsu7vN0sA9kClUSM+xAtelfCFPjTe0U7+/cP6W5N6Xa/MHIwZFw2LR06eFi2UA 10 | 5HuZentIxwzbSBFFtade69y2nKGZiyJ+Fx0iWOGIv3PnLeoU72Ft3nZOSgi8Aola 11 | s1Q6JY4LLHcu+kP2UVMvVzJIbZYi40u/riEEUQ6Fq45JsLndKC8GlsDylWYtvlSB 12 | LVGTRRl61E0hjkl0qDSuhvD47hi4hzAQVQJthndIgnQhtTdL+bbQY69i4hFaeeNH 13 | oXRwuR8RAoGBAP/0m2CohYroSP4HNCPqJpmwOJdDlXYOSeILIaN723pl8hmxAD/r 14 | agQ/e8pbZuOCpYkgZBqnuyn2GiWPJTuc3kvcSJNcdnx6n2GQC1kaA+nRM4cvokFh 15 | yuQB0MMSltXIlYEFm1d2EKjjmFZz1zoegMOS4FO2kUV4k8QUYunYI4N3AoGBANWe 16 | pLZvpLrgR2/78+PXrL2bVsxykPZXrhWDqlHhkL5G+gW0QnVZrPICGK++fbBIRBkJ 17 | Fe8QMheOTnRMPAW7nvnbXvLvtd1Qz2lBJ7/p/t3bcDx53+SDrkAGcNjWKhY83lim 18 | HUOs/y6zIilZAyWmUHxEd0glAHQbMwXiOTpVP2u5AoGAVTvfghCcZ+VyaSV893jB 19 | 4ewM7FJVMzsO33dVfFuCev/33xZSPvbmFwQM9RX67UhUV5WxwC6a5R5PFrLUc0WJ 20 | wTlZ8biYvFsZOCP/o2xGYVaJEjuKjLtEFSmFm3BVSlvBbXWwhS+L3LHtyNxKj9AY 21 | kQgYK8hgGAJPMryXM8gGC4ECgYEAzkx+L32ULbFI7Dn7KA9yUE5DPgBqRK0afsZ/ 22 | 5sGa4ldzP6z8/Y2T+sfRhW/GvEaeFTt0BkKyzZLt61xwHu05s3yKrryW+tv+4lw9 23 | Ahb9vs4cDxt4AJy23DgcJRx22rD/3cbWvjPE4Rm4JQxEgMikM85/D5pEXNyjosv9 24 | jnsjW2kCgYEAqPfBJQQJPImVKEoEbs8E0hpDAAExFQVlSAtaHO6sTM0QekD8K7So 25 | g80ybjTTGS4BTlm1tYbPZGWqmK7vXq+uetFBWe3XUFRD/989kYnR0vg9t7cYamz4 26 | 9blY/0kIg2lhBRiXCxOpFmTlfuzNTp6m8JFI3K35D0gkuGNZhKD3wrU= 27 | -----END RSA PRIVATE KEY----- 28 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | lerna-debug.log* 8 | 9 | # Diagnostic reports (https://nodejs.org/api/report.html) 10 | report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json 11 | 12 | # Runtime data 13 | pids 14 | *.pid 15 | *.seed 16 | *.pid.lock 17 | 18 | # Directory for instrumented libs generated by jscoverage/JSCover 19 | lib-cov 20 | 21 | # Coverage directory used by tools like istanbul 22 | coverage 23 | *.lcov 24 | 25 | # nyc test coverage 26 | .nyc_output 27 | 28 | # Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) 29 | .grunt 30 | 31 | # Bower dependency directory (https://bower.io/) 32 | bower_components 33 | 34 | # node-waf configuration 35 | .lock-wscript 36 | 37 | # Compiled binary addons (https://nodejs.org/api/addons.html) 38 | build/Release 39 | 40 | # Dependency directories 41 | node_modules/ 42 | jspm_packages/ 43 | 44 | # TypeScript v1 declaration files 45 | typings/ 46 | 47 | # TypeScript cache 48 | *.tsbuildinfo 49 | 50 | # Optional npm cache directory 51 | .npm 52 | 53 | # Optional eslint cache 54 | .eslintcache 55 | 56 | # Microbundle cache 57 | .rpt2_cache/ 58 | .rts2_cache_cjs/ 59 | .rts2_cache_es/ 60 | .rts2_cache_umd/ 61 | 62 | # Optional REPL history 63 | .node_repl_history 64 | 65 | # Output of 'npm pack' 66 | *.tgz 67 | 68 | # Yarn Integrity file 69 | .yarn-integrity 70 | 71 | # dotenv environment variables file 72 | .env 73 | .env.test 74 | 75 | # parcel-bundler cache (https://parceljs.org/) 76 | .cache 77 | 78 | # Next.js build output 79 | .next 80 | 81 | # Nuxt.js build / generate output 82 | .nuxt 83 | dist 84 | 85 | # Gatsby files 86 | .cache/ 87 | # Comment in the public line in if your project uses Gatsby and *not* Next.js 88 | # https://nextjs.org/blog/next-9-1#public-directory-support 89 | # public 90 | 91 | # vuepress build output 92 | .vuepress/dist 93 | 94 | # Serverless directories 95 | .serverless/ 96 | 97 | # FuseBox cache 98 | .fusebox/ 99 | 100 | # DynamoDB Local files 101 | .dynamodb/ 102 | 103 | # TernJS port file 104 | .tern-port 105 | -------------------------------------------------------------------------------- /webcodecs-datachannel/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | webcodecs test 7 | 17 | 18 | 19 | 20 | 21 | 22 | 53 | 54 | 55 | 56 | 57 |

WebCodecs Demo

58 |
59 | 60 | 61 |
62 | 63 |

64 | 65 |
66 | 67 | 68 | 69 |
70 | publish: 71 |
72 |
73 | 74 |
75 |
76 | 77 |
78 | 79 | 80 |
81 | play: 82 |
83 |
84 | 85 |
86 |
87 | 88 |
89 | 90 | 91 | 92 | 93 | -------------------------------------------------------------------------------- /webcodecs-websocket/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | webcodecs test 7 | 17 | 18 | 19 | 20 | 21 | 22 | 53 | 54 | 55 | 56 | 57 |

WebCodecs Demo

58 |
59 | 60 | 61 |
62 | 63 |

64 | 65 |
66 | 67 | 68 | 69 |
70 | publish: 71 |
72 |
73 | 74 |
75 |
76 | 77 |
78 | 79 | 80 |
81 | play: 82 |
83 |
84 | 85 |
86 |
87 | 88 |
89 | 90 | 91 | 92 | 93 | -------------------------------------------------------------------------------- /webcodecs-websocket/player.js: -------------------------------------------------------------------------------- 1 | 2 | 3 | class Player { 4 | constructor() { 5 | this.adecoder_ = null; 6 | this.vdecoder_ = null; 7 | this.socket_ = null; 8 | 9 | this.vwriter_ = null; 10 | this.awriter_ = null; 11 | 12 | this.waitKeyframe_ = true; 13 | } 14 | async init(videoElement) { 15 | 16 | // VideoDecoder config 17 | this.vdecoder_ = new VideoDecoder({ 18 | output: this.handleVideoDecoded.bind(this), 19 | error: (error) => { 20 | console.error("video decoder " + error); 21 | } 22 | }); 23 | this.vdecoder_.configure({ codec: 'vp8', width: 1280, height: 720 }); 24 | 25 | 26 | // AudioDecoder config 27 | this.adecoder_ = new AudioDecoder({ 28 | output: this.handleAudioDecoded.bind(this), 29 | error: (error) => { 30 | console.error("audio decoder " + error); 31 | } 32 | }); 33 | this.adecoder_.configure({ codec: 'opus', numberOfChannels: 2, sampleRate: 48000 }); 34 | 35 | 36 | let vgenerator = new MediaStreamTrackGenerator('video'); 37 | this.vwriter_ = vgenerator.writable.getWriter(); 38 | 39 | 40 | let agenerator = new MediaStreamTrackGenerator('audio'); 41 | this.awriter_ = agenerator.writable.getWriter(); 42 | 43 | 44 | let processedStream = new MediaStream(); 45 | processedStream.addTrack(vgenerator); 46 | processedStream.addTrack(agenerator); 47 | videoElement.srcObject = processedStream; 48 | 49 | this.socket_ = new WebSocket("ws://localhost:8000/sub"); 50 | this.socket_.binaryType = 'arraybuffer'; 51 | 52 | this.socket_.onopen = async () => { 53 | console.log('socket open'); 54 | } 55 | 56 | this.socket_.onmessage = async (event) => { 57 | 58 | const chunk = CBOR.decode(event.data); 59 | if (chunk.kind === 'video') { 60 | if (this.waitKeyframe_ ){ 61 | if(chunk.type === 'delta'){ 62 | return; 63 | } 64 | this.waitKeyframe_ = false; 65 | console.log('got first keyframe' + Date.now()); 66 | } 67 | const encoded = new EncodedVideoChunk(chunk); 68 | this.vdecoder_.decode(encoded); 69 | } else { 70 | const encoded = new EncodedAudioChunk(chunk); 71 | this.adecoder_.decode(encoded); 72 | } 73 | 74 | } 75 | 76 | } 77 | async handleVideoDecoded(frame) { 78 | this.vwriter_.write(frame); 79 | console.log('video decoded ' + Date.now()); 80 | } 81 | 82 | async handleAudioDecoded(frame) { 83 | this.awriter_.write(frame); 84 | } 85 | 86 | destroy() { 87 | if (this.socket_) { 88 | this.socket_.close(); 89 | this.socket_ = null; 90 | } 91 | } 92 | } 93 | 94 | 95 | 96 | class WebAudioPlayer { 97 | constructor(options) { 98 | this.context = new AudioContext(); 99 | this.gain = this.context.createGain(); 100 | this.gain.connect(this.context.destination); 101 | this.context._connections = (this.context._connections || 0) + 1; 102 | 103 | this.startTime = 0; 104 | this.buffer = null; 105 | this.wallclockStartTime = 0; 106 | this.volume = 1; 107 | this.enabled = true; 108 | 109 | this.sampleRate = options.sampleRate || 48000; 110 | this.numberOfChannels = options.numberOfChannels || 2; 111 | } 112 | 113 | play(data) { 114 | 115 | if (!this.enabled) { 116 | return; 117 | } 118 | 119 | this.gain.gain.value = this.volume; 120 | 121 | var buffer = this.context.createBuffer(2, data.length/2, this.sampleRate); 122 | } 123 | } -------------------------------------------------------------------------------- /webcodecs-datachannel/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "log" 6 | "net/http" 7 | "sync" 8 | 9 | "github.com/gin-contrib/cors" 10 | "github.com/gin-gonic/gin" 11 | "github.com/pion/webrtc/v3" 12 | ) 13 | 14 | var pubChan *webrtc.DataChannel 15 | var subChans sync.Map 16 | 17 | func pubChannel(c *gin.Context) { 18 | 19 | var data struct { 20 | Sdp string `json:"sdp"` 21 | } 22 | 23 | if err := c.ShouldBind(&data); err != nil { 24 | c.JSON(200, gin.H{"s": 10001, "e": err}) 25 | return 26 | } 27 | 28 | var config = webrtc.Configuration{ 29 | ICEServers: []webrtc.ICEServer{}, 30 | BundlePolicy: webrtc.BundlePolicyMaxBundle, 31 | SDPSemantics: webrtc.SDPSemanticsUnifiedPlan, 32 | } 33 | 34 | peerConnection, err := webrtc.NewPeerConnection(config) 35 | 36 | if err != nil { 37 | panic(err) 38 | } 39 | 40 | peerConnection.OnDataChannel(func(dc *webrtc.DataChannel) { 41 | 42 | pubChan = dc 43 | 44 | dc.OnOpen(func() { 45 | log.Printf("OnOpen: %s-%d. Pub Datachannel ", dc.Label(), dc.ID()) 46 | }) 47 | 48 | // Register the OnMessage to handle incoming messages 49 | dc.OnMessage(func(dcMsg webrtc.DataChannelMessage) { 50 | 51 | subChans.Range(func(key, _ interface{}) bool { 52 | 53 | datachan := key.(*webrtc.DataChannel) 54 | datachan.Send(dcMsg.Data) 55 | return true 56 | }) 57 | }) 58 | }) 59 | 60 | offer := webrtc.SessionDescription{ 61 | Type: webrtc.SDPTypeOffer, 62 | SDP: data.Sdp, 63 | } 64 | 65 | err = peerConnection.SetRemoteDescription(offer) 66 | if err != nil { 67 | panic(err) 68 | } 69 | answer, err := peerConnection.CreateAnswer(nil) 70 | if err != nil { 71 | fmt.Println(err) 72 | panic(err) 73 | } 74 | peerConnection.SetLocalDescription(answer) 75 | 76 | gatherComplete := webrtc.GatheringCompletePromise(peerConnection) 77 | 78 | <-gatherComplete 79 | 80 | c.JSON(200, gin.H{ 81 | "sdp": peerConnection.LocalDescription().SDP, 82 | }) 83 | 84 | } 85 | 86 | func subChannel(c *gin.Context) { 87 | 88 | var data struct { 89 | Sdp string `json:"sdp"` 90 | } 91 | 92 | if err := c.ShouldBind(&data); err != nil { 93 | c.JSON(200, gin.H{"s": 10001, "e": err}) 94 | return 95 | } 96 | 97 | var config = webrtc.Configuration{ 98 | ICEServers: []webrtc.ICEServer{}, 99 | BundlePolicy: webrtc.BundlePolicyMaxBundle, 100 | SDPSemantics: webrtc.SDPSemanticsUnifiedPlan, 101 | } 102 | 103 | peerConnection, err := webrtc.NewPeerConnection(config) 104 | 105 | if err != nil { 106 | panic(err) 107 | } 108 | 109 | peerConnection.OnDataChannel(func(dc *webrtc.DataChannel) { 110 | 111 | subChan := dc 112 | 113 | subChans.Store(subChan, "") 114 | 115 | dc.OnOpen(func() { 116 | log.Printf("OnOpen: %s-%d. Sub Datachannel", dc.Label(), dc.ID()) 117 | }) 118 | 119 | // Register the OnMessage to handle incoming messages 120 | dc.OnMessage(func(dcMsg webrtc.DataChannelMessage) { 121 | }) 122 | 123 | dc.OnClose(func() { 124 | subChans.Delete(subChan) 125 | }) 126 | }) 127 | 128 | offer := webrtc.SessionDescription{ 129 | Type: webrtc.SDPTypeOffer, 130 | SDP: data.Sdp, 131 | } 132 | 133 | err = peerConnection.SetRemoteDescription(offer) 134 | if err != nil { 135 | panic(err) 136 | } 137 | answer, err := peerConnection.CreateAnswer(nil) 138 | if err != nil { 139 | fmt.Println(err) 140 | panic(err) 141 | } 142 | peerConnection.SetLocalDescription(answer) 143 | 144 | gatherComplete := webrtc.GatheringCompletePromise(peerConnection) 145 | 146 | <-gatherComplete 147 | 148 | c.JSON(200, gin.H{ 149 | "sdp": peerConnection.LocalDescription().SDP, 150 | }) 151 | 152 | // subws, err := upGrader.Upgrade(c.Writer, c.Request, nil) 153 | // if err != nil { 154 | // return 155 | // } 156 | // defer subws.Close() 157 | 158 | // subwss.Store(subws, "") 159 | 160 | // for { 161 | // _, _, err = subws.ReadMessage() 162 | 163 | // if err != nil { 164 | // fmt.Println("error ", err) 165 | // break 166 | // } 167 | // } 168 | 169 | // subwss.Delete(subws) 170 | } 171 | 172 | func index(c *gin.Context) { 173 | c.HTML(http.StatusOK, "index.html", gin.H{}) 174 | } 175 | 176 | func main() { 177 | 178 | address := ":8000" 179 | r := gin.Default() 180 | 181 | corsc := cors.DefaultConfig() 182 | corsc.AllowAllOrigins = true 183 | corsc.AllowCredentials = true 184 | r.Use(cors.New(corsc)) 185 | 186 | r.LoadHTMLFiles("./index.html") 187 | r.StaticFile("/pusher.js", "./pusher.js") 188 | r.StaticFile("/player.js", "./player.js") 189 | r.StaticFile("/cbor.js", "./cbor.js") 190 | r.GET("/", index) 191 | 192 | r.POST("/pub", pubChannel) 193 | r.POST("/sub", subChannel) 194 | 195 | r.Run(address) 196 | } 197 | -------------------------------------------------------------------------------- /webcodecs-websocket/go.sum: -------------------------------------------------------------------------------- 1 | github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 2 | github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 3 | github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE= 4 | github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI= 5 | github.com/gin-gonic/gin v1.7.1 h1:qC89GU3p8TvKWMAVhEpmpB2CIb1hnqt2UdKZaP93mS8= 6 | github.com/gin-gonic/gin v1.7.1/go.mod h1:jD2toBW3GZUr5UMcdrwQA10I7RuaFOl/SGeDjXkfUtY= 7 | github.com/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4= 8 | github.com/go-playground/locales v0.13.0 h1:HyWk6mgj5qFqCT5fjGBuRArbVDfE4hi8+e8ceBS/t7Q= 9 | github.com/go-playground/locales v0.13.0/go.mod h1:taPMhCMXrRLJO55olJkUXHZBHCxTMfnGwq/HNwmWNS8= 10 | github.com/go-playground/universal-translator v0.17.0 h1:icxd5fm+REJzpZx7ZfpaD876Lmtgy7VtROAbHHXk8no= 11 | github.com/go-playground/universal-translator v0.17.0/go.mod h1:UkSxE5sNxxRwHyU+Scu5vgOQjsIJAF8j9muTVoKLVtA= 12 | github.com/go-playground/validator/v10 v10.4.1 h1:pH2c5ADXtd66mxoE0Zm9SUhxE20r7aM3F26W0hOn+GE= 13 | github.com/go-playground/validator/v10 v10.4.1/go.mod h1:nlOn6nFhuKACm19sB/8EGNn9GlaMV7XkbRSipzJ0Ii4= 14 | github.com/golang/protobuf v1.3.3 h1:gyjaxf+svBWX08ZjK86iN9geUJF0H6gp2IRKX6Nf6/I= 15 | github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= 16 | github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= 17 | github.com/gorilla/websocket v1.4.2 h1:+/TMaTYc4QFitKJxsQ7Yye35DkWvkdLcvGKqM+x0Ufc= 18 | github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= 19 | github.com/json-iterator/go v1.1.9 h1:9yzud/Ht36ygwatGx56VwCZtlI/2AD15T1X2sjSuGns= 20 | github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= 21 | github.com/leodido/go-urn v1.2.0 h1:hpXL4XnriNwQ/ABnpepYM/1vCLWNDfUNts8dX3xTG6Y= 22 | github.com/leodido/go-urn v1.2.0/go.mod h1:+8+nEpDfqqsY+g338gtMEUOtuK+4dEMhiQEgxpxOKII= 23 | github.com/mattn/go-isatty v0.0.12 h1:wuysRhFDzyxgEmMf5xjvJ2M9dZoWAXNNr5LSBS7uHXY= 24 | github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= 25 | github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421 h1:ZqeYNhU3OHLH3mGKHDcjJRFFRrJa6eAM5H+CtDdOsPc= 26 | github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= 27 | github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742 h1:Esafd1046DLDQ0W1YjYsBW+p8U2u7vzgW2SQVmlNazg= 28 | github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= 29 | github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= 30 | github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= 31 | github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= 32 | github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= 33 | github.com/ugorji/go v1.1.7 h1:/68gy2h+1mWMrwZFeD1kQialdSzAb432dtpeJ42ovdo= 34 | github.com/ugorji/go v1.1.7/go.mod h1:kZn38zHttfInRq0xu/PH0az30d+z6vm202qpg1oXVMw= 35 | github.com/ugorji/go/codec v1.1.7 h1:2SvQaVZ1ouYrrKKwoSk2pzd4A9evlKJb9oTL+OaLUSs= 36 | github.com/ugorji/go/codec v1.1.7/go.mod h1:Ax+UKWsSmolVDwsd+7N3ZtXu+yMGCf907BLYF3GoBXY= 37 | golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= 38 | golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9 h1:psW17arqaxU48Z5kZ0CQnkZWQJsqcURM6tKiBApRjXI= 39 | golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= 40 | golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= 41 | golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 42 | golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 43 | golang.org/x/sys v0.0.0-20200116001909-b77594299b42 h1:vEOn+mP2zCOVzKckCZy6YsCtDblrpj/w7B9nxGNELpg= 44 | golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 45 | golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= 46 | golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= 47 | golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= 48 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 49 | gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= 50 | gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10= 51 | gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= 52 | -------------------------------------------------------------------------------- /webcodecs-websocket/pusher.js: -------------------------------------------------------------------------------- 1 | 2 | 3 | class Pusher { 4 | constructor() { 5 | this.aencoder_ = null; 6 | this.vencoder_ = null; 7 | this.videoElement_ = null; 8 | this.socket_ = null; 9 | this.sendFrames_ = 0; 10 | this.videoGop_ = 30; 11 | } 12 | async init(videoElement) { 13 | 14 | 15 | this.socket_ = new WebSocket("ws://localhost:8000/pub"); 16 | 17 | this.socket_.binaryType = 'arraybuffer'; 18 | 19 | this.socket_.onopen = async () => { 20 | console.log('socket open'); 21 | this.sendFrames_ = 0; 22 | } 23 | 24 | this.socket_.onmessage = async (event) => { 25 | } 26 | 27 | this.socket_.onclose = async (event) => { 28 | console.log("socket close"); 29 | } 30 | 31 | const constraints = { 32 | video: { width: { exact: 1280 }, height: { exact: 720 } }, 33 | audio: { 34 | channelCount:2, 35 | sampleRate:48000, 36 | } 37 | } 38 | 39 | // VideoEncoder config 40 | this.vencoder_ = new VideoEncoder({ 41 | output: this.handleVideoEncoded.bind(this), 42 | error: (error) => { 43 | console.error("video encoder " + error); 44 | } 45 | }); 46 | this.vencoder_.configure({ codec: 'vp8', width: 1289, height: 720 }); 47 | 48 | 49 | 50 | // AudioEncoder config 51 | this.aencoder_ = new AudioEncoder({ 52 | output: this.handleAudioEncoded.bind(this), 53 | error: (error) => { 54 | console.error("audio encoder " + error); 55 | } 56 | }); 57 | this.aencoder_.configure({ codec: 'opus', numberOfChannels: 2, sampleRate: 48000 }); 58 | 59 | const stream = await navigator.mediaDevices.getUserMedia(constraints); 60 | 61 | let vprocessor = new MediaStreamTrackProcessor(stream.getVideoTracks()[0]); 62 | let vgenerator = new MediaStreamTrackGenerator('video'); 63 | const vsource = vprocessor.readable; 64 | const vsink = vgenerator.writable; 65 | let vtransformer = new TransformStream({ transform: this.videoTransform() }); 66 | vsource.pipeThrough(vtransformer).pipeTo(vsink); 67 | 68 | 69 | let aprocessor = new MediaStreamTrackProcessor(stream.getAudioTracks()[0]); 70 | let agenerator = new MediaStreamTrackGenerator('audio'); 71 | const asource = aprocessor.readable; 72 | const asink = agenerator.writable; 73 | let atransformer = new TransformStream({ transform: this.audioTransform() }); 74 | asource.pipeThrough(atransformer).pipeTo(asink); 75 | 76 | 77 | let processedStream = new MediaStream(); 78 | processedStream.addTrack(vgenerator); 79 | processedStream.addTrack(agenerator); 80 | videoElement.srcObject = processedStream; 81 | await videoElement.play(); 82 | 83 | 84 | 85 | } 86 | 87 | videoTransform(frame, controller) { 88 | 89 | return (frame, controller) => { 90 | 91 | const insert_keyframe = (this.sendFrames_ % 30) == 0; 92 | this.sendFrames_++; 93 | if (insert_keyframe) { 94 | console.log('keyframe == '); 95 | } 96 | this.vencoder_.encode(frame, { keyFrame: insert_keyframe }); 97 | controller.enqueue(frame); 98 | } 99 | 100 | } 101 | 102 | audioTransform() { 103 | return (frame, controller) => { 104 | this.aencoder_.encode(frame); 105 | controller.enqueue(frame); 106 | } 107 | 108 | } 109 | 110 | async handleVideoEncoded(chunk) { 111 | 112 | 113 | let data = new Uint8Array(chunk.byteLength); 114 | chunk.copyTo(data.buffer); 115 | const { type, timestamp, duration } = chunk; 116 | let kind = 'video'; 117 | let data_ = CBOR.encode({ 118 | kind, 119 | type, 120 | timestamp, 121 | duration, 122 | data: data, 123 | }); 124 | if (this.socket_) { 125 | this.socket_.send(data_); 126 | } 127 | 128 | } 129 | 130 | async handleAudioEncoded(chunk) { 131 | 132 | 133 | let data = new Uint8Array(chunk.byteLength); 134 | chunk.copyTo(data.buffer); 135 | let kind = 'audio'; 136 | const {type,timestamp} = chunk; 137 | let data_ = CBOR.encode({ 138 | kind, 139 | type, 140 | timestamp, 141 | data: data, 142 | }); 143 | if (this.socket_) { 144 | this.socket_.send(data_); 145 | } 146 | 147 | } 148 | 149 | destroy() { 150 | if (this.socket_) { 151 | this.socket_.close(); 152 | this.socket_ = null; 153 | } 154 | } 155 | } -------------------------------------------------------------------------------- /webcodecs-datachannel/player.js: -------------------------------------------------------------------------------- 1 | 2 | 3 | class Player { 4 | constructor() { 5 | this.adecoder_ = null; 6 | this.vdecoder_ = null; 7 | 8 | 9 | this.pc_ = null; 10 | this.datachannel_ = null; 11 | this.channelOpen_ = false; 12 | 13 | this.vwriter_ = null; 14 | this.awriter_ = null; 15 | 16 | this.waitKeyframe_ = true; 17 | } 18 | async init(videoElement) { 19 | 20 | // VideoDecoder config 21 | this.vdecoder_ = new VideoDecoder({ 22 | output: this.handleVideoDecoded.bind(this), 23 | error: (error) => { 24 | console.error("video decoder " + error); 25 | } 26 | }); 27 | this.vdecoder_.configure({ codec: 'vp8', width: 1280, height: 720 }); 28 | 29 | 30 | // AudioDecoder config 31 | this.adecoder_ = new AudioDecoder({ 32 | output: this.handleAudioDecoded.bind(this), 33 | error: (error) => { 34 | console.error("audio decoder " + error); 35 | } 36 | }); 37 | this.adecoder_.configure({ codec: 'opus', numberOfChannels: 2, sampleRate: 48000 }); 38 | 39 | 40 | let vgenerator = new MediaStreamTrackGenerator('video'); 41 | this.vwriter_ = vgenerator.writable.getWriter(); 42 | 43 | 44 | let agenerator = new MediaStreamTrackGenerator('audio'); 45 | this.awriter_ = agenerator.writable.getWriter(); 46 | 47 | 48 | let processedStream = new MediaStream(); 49 | processedStream.addTrack(vgenerator); 50 | processedStream.addTrack(agenerator); 51 | videoElement.srcObject = processedStream; 52 | 53 | this.pc_ = new RTCPeerConnection(); 54 | this.datachannel_ = this.pc_.createDataChannel('message',{ordered:true}); 55 | this.datachannel_.binaryType = 'arraybuffer'; 56 | this.datachannel_.onopen = () => { 57 | console.log('datachannel open'); 58 | this.channelOpen_ = true; 59 | }; 60 | this.datachannel_.onmessage = async (event) => { 61 | console.log('datachannel message'); 62 | console.log(event.data); 63 | 64 | const chunk = CBOR.decode(event.data); 65 | if (chunk.kind === 'video') { 66 | if (this.waitKeyframe_ ){ 67 | if(chunk.type === 'delta'){ 68 | return; 69 | } 70 | this.waitKeyframe_ = false; 71 | console.log('got first keyframe' + Date.now()); 72 | } 73 | const encoded = new EncodedVideoChunk(chunk); 74 | this.vdecoder_.decode(encoded); 75 | } else { 76 | const encoded = new EncodedAudioChunk(chunk); 77 | this.adecoder_.decode(encoded); 78 | } 79 | }; 80 | 81 | const offer = await this.pc_.createOffer(); 82 | await this.pc_.setLocalDescription(offer); 83 | 84 | console.log(offer.sdp); 85 | 86 | let res = await fetch("http://localhost:8000/sub", { 87 | method: 'post', 88 | headers: { 89 | 'Content-Type': 'application/json' 90 | }, 91 | body: JSON.stringify({ 92 | sdp: offer.sdp 93 | }) 94 | }) 95 | 96 | console.dir(res) 97 | 98 | 99 | let ret = await res.json() 100 | 101 | let answer = new RTCSessionDescription({ 102 | type: 'answer', 103 | sdp: ret.sdp 104 | }) 105 | 106 | await this.pc_.setRemoteDescription(answer); 107 | 108 | 109 | 110 | } 111 | async handleVideoDecoded(frame) { 112 | this.vwriter_.write(frame); 113 | console.log('video decoded ' + Date.now()); 114 | } 115 | 116 | async handleAudioDecoded(frame) { 117 | this.awriter_.write(frame); 118 | } 119 | 120 | destroy() { 121 | if (this.socket_) { 122 | this.socket_.close(); 123 | this.socket_ = null; 124 | } 125 | } 126 | } 127 | 128 | 129 | 130 | class WebAudioPlayer { 131 | constructor(options) { 132 | this.context = new AudioContext(); 133 | this.gain = this.context.createGain(); 134 | this.gain.connect(this.context.destination); 135 | this.context._connections = (this.context._connections || 0) + 1; 136 | 137 | this.startTime = 0; 138 | this.buffer = null; 139 | this.wallclockStartTime = 0; 140 | this.volume = 1; 141 | this.enabled = true; 142 | 143 | this.sampleRate = options.sampleRate || 48000; 144 | this.numberOfChannels = options.numberOfChannels || 2; 145 | } 146 | 147 | play(data) { 148 | 149 | if (!this.enabled) { 150 | return; 151 | } 152 | 153 | this.gain.gain.value = this.volume; 154 | 155 | var buffer = this.context.createBuffer(2, data.length/2, this.sampleRate); 156 | } 157 | } -------------------------------------------------------------------------------- /webcodecs-quic/script.js: -------------------------------------------------------------------------------- 1 | 2 | let codec_string = "vp8"; 3 | let decoder; 4 | let transport; 5 | let bidirectionalStream; 6 | 7 | async function captureAndEncode() { 8 | 9 | let fps = 30; 10 | let pending_outputs = 0; 11 | let frame_counter = 0; 12 | 13 | const constraints = { 14 | video: { width: 640, height: 480 }, 15 | audio: true 16 | } 17 | 18 | const stream = await navigator.mediaDevices.getUserMedia(constraints); 19 | 20 | let camera = document.getElementById("camera"); 21 | camera.srcObject = stream; 22 | camera.controls = true; 23 | camera.muted = true; 24 | 25 | 26 | let vtr = new VideoTrackReader(stream.getVideoTracks()[0]); 27 | 28 | const writer = bidirectionalStream.writable.getWriter(); 29 | 30 | const init = { 31 | output: (chunk) => { 32 | pending_outputs--; 33 | const { type, timestamp, duration, data } = chunk; 34 | const encoded = new Uint8Array( 35 | CBOR.encode({ 36 | type, 37 | timestamp, 38 | duration, 39 | data: new Uint8Array(data), 40 | })); 41 | 42 | const size = new Uint8Array(4); 43 | const view = new DataView(size.buffer); 44 | view.setUint32(0, encoded.length); 45 | writer.write(new Uint8Array([...size, ...encoded])); 46 | 47 | }, 48 | error: (e) => { 49 | console.log(e.message); 50 | vtr.stop(); 51 | } 52 | }; 53 | 54 | const config = { 55 | codec: codec_string, 56 | width: 640, 57 | height: 480, 58 | bitrate: 1e6, 59 | framerate: fps, 60 | }; 61 | 62 | let encoder = new VideoEncoder(init); 63 | encoder.configure(config); 64 | 65 | vtr.start((frame) => { 66 | if (pending_outputs > 30) { 67 | // Too many frames in flight, encoder is overwhelmed 68 | // let's drop this frame. 69 | return; 70 | } 71 | frame_counter++; 72 | pending_outputs++; 73 | const insert_keyframe = (frame_counter % 60) == 0; 74 | encoder.encode(frame, { keyFrame: insert_keyframe }); 75 | }); 76 | } 77 | 78 | 79 | function startDecodingAndRendering() { 80 | let cnv = document.getElementById("dst"); 81 | let ctx = cnv.getContext("2d", { alpha: false }); 82 | let ready_frames = []; 83 | 84 | async function renderFrame() { 85 | 86 | if (ready_frames.length == 0) { 87 | return; 88 | } 89 | 90 | let frame = ready_frames.shift(); 91 | 92 | let bitmap = await frame.createImageBitmap(); 93 | ctx.drawImage(bitmap, 0, 0); 94 | 95 | // Immediately schedule rendering of the next frame 96 | setTimeout(renderFrame, 0); 97 | frame.close(); 98 | } 99 | 100 | function handleFrame(frame) { 101 | ready_frames.push(frame); 102 | setTimeout(renderFrame, 0); 103 | } 104 | 105 | const init = { 106 | output: handleFrame, 107 | error: (e) => { 108 | console.log(e.message); 109 | } 110 | }; 111 | 112 | const config = { 113 | codec: codec_string, 114 | codedWidth: cnv.width, 115 | codedHeight: cnv.height 116 | }; 117 | 118 | let decoder = new VideoDecoder(init); 119 | decoder.configure(config); 120 | return decoder; 121 | } 122 | 123 | async function main() { 124 | if (!("VideoEncoder" in window)) { 125 | document.body.innerHTML = "

WebCodecs API is not supported.

"; 126 | return; 127 | } 128 | 129 | const url = 'https://localhost:4433/webcodecs'; 130 | transport = new WebTransport(url); 131 | 132 | transport.closed.then(() => { 133 | console.log('quictransport closed') 134 | }).catch((error) => { 135 | console.error('quictransport error ', error) 136 | }) 137 | 138 | decoder = startDecodingAndRendering(); 139 | 140 | await transport.ready; 141 | bidirectionalStream = await transport.createBidirectionalStream(); 142 | 143 | captureAndEncode(); 144 | 145 | const reader = bidirectionalStream.readable.getReader(); 146 | 147 | while (true) { 148 | 149 | let { done, value } = await reader.read(); 150 | if (done) { 151 | console.log('Done accepting unidirectional streams!'); 152 | return; 153 | } 154 | 155 | const view = new DataView(value.buffer); 156 | let size = null; 157 | try { 158 | size = view.getUint32(0); 159 | } catch { 160 | console.log('error size'); 161 | continue; 162 | } 163 | 164 | let buffer = value.slice(4); 165 | 166 | while (buffer.length < size) { 167 | let { done, value } = await reader.read(); 168 | buffer = new Uint8Array([...buffer, ...value]); 169 | } 170 | 171 | 172 | // todo, handle the remain buffer 173 | if (buffer.length != size) { 174 | console.log("buffer length ", buffer.length, " should be ", size); 175 | } 176 | 177 | const chunk = CBOR.decode(buffer.buffer); 178 | const encoded = new EncodedVideoChunk(chunk); 179 | decoder.decode(encoded); 180 | } 181 | 182 | } 183 | -------------------------------------------------------------------------------- /webcodecs-datachannel/pusher.js: -------------------------------------------------------------------------------- 1 | 2 | 3 | class Pusher { 4 | constructor() { 5 | this.aencoder_ = null; 6 | this.vencoder_ = null; 7 | this.videoElement_ = null; 8 | 9 | 10 | this.pc_ = null; 11 | this.datachannel_ = null; 12 | this.channelOpen_ = false; 13 | 14 | this.sendFrames_ = 0; 15 | this.videoGop_ = 30; 16 | } 17 | async init(videoElement) { 18 | 19 | this.pc_ = new RTCPeerConnection(); 20 | this.datachannel_ = this.pc_.createDataChannel('message',{ordered:true}); 21 | this.datachannel_.binaryType = 'arraybuffer'; 22 | this.datachannel_.onopen = () => { 23 | console.log('datachannel open'); 24 | this.channelOpen_ = true; 25 | }; 26 | this.datachannel_.onmessage = (event) => { 27 | console.log('datachannel message'); 28 | console.log(event.data); 29 | }; 30 | 31 | const offer = await this.pc_.createOffer(); 32 | await this.pc_.setLocalDescription(offer); 33 | 34 | 35 | console.log(offer.sdp); 36 | 37 | let res = await fetch("http://localhost:8000/pub", { 38 | method: 'post', 39 | headers: { 40 | 'Content-Type': 'application/json' 41 | }, 42 | body: JSON.stringify({ 43 | sdp: offer.sdp 44 | }) 45 | }) 46 | 47 | console.dir(res) 48 | 49 | 50 | let ret = await res.json() 51 | 52 | let answer = new RTCSessionDescription({ 53 | type: 'answer', 54 | sdp: ret.sdp 55 | }) 56 | 57 | await this.pc_.setRemoteDescription(answer); 58 | 59 | const constraints = { 60 | video: { width: { exact: 1280 }, height: { exact: 720 } }, 61 | audio: { 62 | channelCount:2, 63 | sampleRate:48000, 64 | } 65 | } 66 | 67 | // VideoEncoder config 68 | this.vencoder_ = new VideoEncoder({ 69 | output: this.handleVideoEncoded.bind(this), 70 | error: (error) => { 71 | console.error("video encoder " + error); 72 | } 73 | }); 74 | this.vencoder_.configure({ codec: 'vp8', width: 1289, height: 720 }); 75 | 76 | 77 | 78 | // AudioEncoder config 79 | this.aencoder_ = new AudioEncoder({ 80 | output: this.handleAudioEncoded.bind(this), 81 | error: (error) => { 82 | console.error("audio encoder " + error); 83 | } 84 | }); 85 | this.aencoder_.configure({ codec: 'opus', numberOfChannels: 2, sampleRate: 48000 }); 86 | 87 | const stream = await navigator.mediaDevices.getUserMedia(constraints); 88 | 89 | let vprocessor = new MediaStreamTrackProcessor(stream.getVideoTracks()[0]); 90 | let vgenerator = new MediaStreamTrackGenerator('video'); 91 | const vsource = vprocessor.readable; 92 | const vsink = vgenerator.writable; 93 | let vtransformer = new TransformStream({ transform: this.videoTransform() }); 94 | vsource.pipeThrough(vtransformer).pipeTo(vsink); 95 | 96 | 97 | let aprocessor = new MediaStreamTrackProcessor(stream.getAudioTracks()[0]); 98 | let agenerator = new MediaStreamTrackGenerator('audio'); 99 | const asource = aprocessor.readable; 100 | const asink = agenerator.writable; 101 | let atransformer = new TransformStream({ transform: this.audioTransform() }); 102 | asource.pipeThrough(atransformer).pipeTo(asink); 103 | 104 | 105 | let processedStream = new MediaStream(); 106 | processedStream.addTrack(vgenerator); 107 | processedStream.addTrack(agenerator); 108 | videoElement.srcObject = processedStream; 109 | await videoElement.play(); 110 | } 111 | 112 | videoTransform(frame, controller) { 113 | 114 | return (frame, controller) => { 115 | 116 | const insert_keyframe = (this.sendFrames_ % 30) == 0; 117 | this.sendFrames_++; 118 | if (insert_keyframe) { 119 | console.log('keyframe == '); 120 | } 121 | this.vencoder_.encode(frame, { keyFrame: insert_keyframe }); 122 | controller.enqueue(frame); 123 | } 124 | 125 | } 126 | 127 | audioTransform() { 128 | return (frame, controller) => { 129 | this.aencoder_.encode(frame); 130 | controller.enqueue(frame); 131 | } 132 | 133 | } 134 | 135 | async handleVideoEncoded(chunk) { 136 | 137 | 138 | let data = new Uint8Array(chunk.byteLength); 139 | chunk.copyTo(data.buffer); 140 | const { type, timestamp, duration } = chunk; 141 | let kind = 'video'; 142 | let data_ = CBOR.encode({ 143 | kind, 144 | type, 145 | timestamp, 146 | duration, 147 | data: data, 148 | }); 149 | if (this.channelOpen_) { 150 | this.datachannel_.send(data_); 151 | } 152 | 153 | } 154 | 155 | async handleAudioEncoded(chunk) { 156 | 157 | 158 | let data = new Uint8Array(chunk.byteLength); 159 | chunk.copyTo(data.buffer); 160 | let kind = 'audio'; 161 | const {type,timestamp} = chunk; 162 | let data_ = CBOR.encode({ 163 | kind, 164 | type, 165 | timestamp, 166 | data: data, 167 | }); 168 | if (this.channelOpen_) { 169 | this.datachannel_.send(data_); 170 | } 171 | 172 | } 173 | 174 | destroy() { 175 | if (this.datachannel_) { 176 | this.datachannel_.close(); 177 | this.datachannel_ = null; 178 | this.channelOpen_ = false; 179 | } 180 | } 181 | } -------------------------------------------------------------------------------- /webcodecs-quic/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "context" 5 | "crypto/tls" 6 | "encoding/binary" 7 | "errors" 8 | "io" 9 | "log" 10 | "net/http" 11 | 12 | "github.com/gin-contrib/static" 13 | "github.com/gin-gonic/gin" 14 | "github.com/lucas-clemente/quic-go" 15 | ) 16 | 17 | const ( 18 | // https://tools.ietf.org/html/draft-vvv-webtransport-quic-02#section-3.1 19 | alpnQuicTransport = "wq-vvv-01" 20 | // https://tools.ietf.org/html/draft-vvv-webtransport-quic-02#section-3.2 21 | maxClientIndicationLength = 65535 22 | ) 23 | 24 | type clientIndicationKey int16 25 | 26 | const ( 27 | clientIndicationKeyOrigin clientIndicationKey = 0 28 | clientIndicationKeyPath = 1 29 | ) 30 | 31 | type ClientIndication struct { 32 | // Origin indication value. 33 | Origin string 34 | // Path indication value. 35 | Path string 36 | } 37 | 38 | // Config for WebTransportServerQuic. 39 | type Config struct { 40 | // ListenAddr sets an address to bind server to. 41 | ListenAddr string 42 | // TLSCertPath defines a path to .crt cert file. 43 | TLSCertPath string 44 | // TLSKeyPath defines a path to .key cert file 45 | TLSKeyPath string 46 | // AllowedOrigins represents list of allowed origins to connect from. 47 | AllowedOrigins []string 48 | } 49 | 50 | type WebTransportServerQuic struct { 51 | config Config 52 | } 53 | 54 | func NewWebTransportServerQuic(config Config) *WebTransportServerQuic { 55 | return &WebTransportServerQuic{ 56 | config: config, 57 | } 58 | } 59 | 60 | // Run server. 61 | func (s *WebTransportServerQuic) Run() error { 62 | listener, err := quic.ListenAddr(s.config.ListenAddr, s.generateTLSConfig(), nil) 63 | if err != nil { 64 | return err 65 | } 66 | for { 67 | sess, err := listener.Accept(context.Background()) 68 | if err != nil { 69 | return err 70 | } 71 | log.Printf("session accepted: %s", sess.RemoteAddr().String()) 72 | 73 | go func() { 74 | defer func() { 75 | _ = sess.CloseWithError(0, "bye") 76 | log.Printf("close session: %s", sess.RemoteAddr().String()) 77 | }() 78 | s.handleSession(sess) 79 | }() 80 | } 81 | } 82 | 83 | func (s *WebTransportServerQuic) handleSession(sess quic.Session) { 84 | stream, err := sess.AcceptUniStream(context.Background()) 85 | if err != nil { 86 | log.Println(err) 87 | return 88 | } 89 | log.Printf("unidirectional stream accepted, id: %d", stream.StreamID()) 90 | indication, err := receiveClientIndication(stream) 91 | if err != nil { 92 | log.Println(err) 93 | return 94 | } 95 | log.Printf("client indication: %+v", indication) 96 | if err := s.validateClientIndication(indication); err != nil { 97 | log.Println(err) 98 | return 99 | } 100 | err = s.communicate(sess) 101 | if err != nil { 102 | log.Println(err) 103 | return 104 | } 105 | } 106 | 107 | func (s *WebTransportServerQuic) communicate(sess quic.Session) error { 108 | for { 109 | stream, err := sess.AcceptStream(context.Background()) 110 | if err != nil { 111 | return err 112 | } 113 | log.Printf("bidirectional stream accepted: %d", stream.StreamID()) 114 | if _, err := io.Copy(loggingWriter{stream}, loggingReader{stream}); err != nil { 115 | return err 116 | } 117 | log.Printf("bidirectional stream closed: %d", stream.StreamID()) 118 | } 119 | } 120 | 121 | // The client indication is a sequence of key-value pairs that are 122 | // formatted in the following way: 123 | // 124 | // 0 1 2 3 125 | // 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 126 | // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 127 | // | Key (16) | Length (16) | 128 | // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 129 | // | Value (*) ... 130 | // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 131 | func receiveClientIndication(stream quic.ReceiveStream) (ClientIndication, error) { 132 | var clientIndication ClientIndication 133 | reader := io.LimitReader(stream, maxClientIndicationLength) 134 | 135 | done := false 136 | 137 | for { 138 | if done { 139 | break 140 | } 141 | 142 | var key int16 143 | err := binary.Read(reader, binary.BigEndian, &key) 144 | if err != nil { 145 | if err == io.EOF { 146 | done = true 147 | } else { 148 | return clientIndication, err 149 | } 150 | } 151 | 152 | var valueLength int16 153 | err = binary.Read(reader, binary.BigEndian, &valueLength) 154 | if err != nil { 155 | return clientIndication, err 156 | } 157 | 158 | buf := make([]byte, valueLength) 159 | n, err := reader.Read(buf) 160 | if err != nil { 161 | if err == io.EOF { 162 | done = true 163 | } else { 164 | return clientIndication, err 165 | } 166 | } 167 | if int16(n) != valueLength { 168 | return clientIndication, errors.New("read less than expected") 169 | } 170 | value := string(buf) 171 | 172 | switch clientIndicationKey(key) { 173 | case clientIndicationKeyOrigin: 174 | clientIndication.Origin = value 175 | case clientIndicationKeyPath: 176 | clientIndication.Path = value 177 | default: 178 | log.Printf("skip unknown client indication key: %d: %s", key, value) 179 | } 180 | } 181 | return clientIndication, nil 182 | } 183 | 184 | func (s *WebTransportServerQuic) generateTLSConfig() *tls.Config { 185 | cert, err := tls.LoadX509KeyPair(s.config.TLSCertPath, s.config.TLSKeyPath) 186 | if err != nil { 187 | log.Fatal(err) 188 | } 189 | return &tls.Config{ 190 | Certificates: []tls.Certificate{cert}, 191 | NextProtos: []string{alpnQuicTransport}, 192 | } 193 | } 194 | 195 | func (s *WebTransportServerQuic) validateClientIndication(indication ClientIndication) error { 196 | return nil 197 | } 198 | 199 | // A wrapper for io.Writer that also logs the message. 200 | type loggingWriter struct{ io.Writer } 201 | 202 | func (w loggingWriter) Write(b []byte) (int, error) { 203 | log.Printf("---> %d", len(b)) 204 | return w.Writer.Write(b) 205 | } 206 | 207 | // A wrapper for io.Reader that also logs the message. 208 | type loggingReader struct{ io.Reader } 209 | 210 | func (r loggingReader) Read(buf []byte) (n int, err error) { 211 | n, err = r.Reader.Read(buf) 212 | if n > 0 { 213 | log.Printf("<--- %d", n) 214 | } 215 | return 216 | } 217 | 218 | func index(c *gin.Context) { 219 | c.HTML(http.StatusOK, "index.html", gin.H{}) 220 | } 221 | 222 | func main() { 223 | 224 | address := ":8000" 225 | r := gin.Default() 226 | r.LoadHTMLFiles("./index.html", "./cbor.js", "./script.js") 227 | r.Use(static.Serve("/", static.LocalFile("./", false))) 228 | r.GET("/", index) 229 | 230 | go func() { 231 | r.Run(address) 232 | }() 233 | 234 | server := NewWebTransportServerQuic(Config{ 235 | ListenAddr: "0.0.0.0:4434", 236 | TLSCertPath: "server.crt", 237 | TLSKeyPath: "server.key", 238 | AllowedOrigins: []string{"localhost"}, 239 | }) 240 | if err := server.Run(); err != nil { 241 | log.Fatal(err) 242 | } 243 | } 244 | -------------------------------------------------------------------------------- /webcodecs-quic/quic_transport_server.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | # Copyright 2020 Google LLC 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License"); 6 | # you may not use this file except in compliance with the License. 7 | # You may obtain a copy of the License at 8 | # 9 | # https://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | """ 17 | An example QuicTransport server based on the aioquic library. 18 | Processes incoming streams and datagrams, and 19 | replies with the ASCII-encoded length of the data sent in bytes. 20 | Example use: 21 | python3 quic_transport_server.py certificate.pem certificate.key 22 | Example use from JavaScript: 23 | let transport = new QuicTransport("quic-transport://localhost:4433/counter"); 24 | await transport.ready; 25 | let stream = await transport.createBidirectionalStream(); 26 | let encoder = new TextEncoder(); 27 | let writer = stream.writable.getWriter(); 28 | await writer.write(encoder.encode("Hello, world!")) 29 | writer.close(); 30 | console.log(await new Response(stream.readable).text()); 31 | This will output "13" (the length of "Hello, world!") into the console. 32 | """ 33 | 34 | # ---- Dependencies ---- 35 | # 36 | # This server only depends on Python standard library and aioquic. See 37 | # https://github.com/aiortc/aioquic for instructions on how to install 38 | # aioquic. 39 | # 40 | # ---- Certificates ---- 41 | # 42 | # QUIC always operates using TLS, meaning that running a QuicTransport server 43 | # requires a valid TLS certificate. The easiest way to do this is to get a 44 | # certificate from a real publicly trusted CA like . 45 | # https://developers.google.com/web/fundamentals/security/encrypt-in-transit/enable-https 46 | # contains a detailed explanation of how to achieve that. 47 | # 48 | # As an alternative, Chromium can be instructed to trust a self-signed 49 | # certificate using command-line flags. Here are step-by-step instructions on 50 | # how to do that: 51 | # 52 | # 1. Generate a certificate and a private key: 53 | # openssl req -newkey rsa:2048 -nodes -keyout certificate.key \ 54 | # -x509 -out certificate.pem -subj '/CN=Test Certificate' \ 55 | # -addext "subjectAltName = DNS:localhost" 56 | # 57 | # 2. Compute the fingerprint of the certificate: 58 | # openssl x509 -pubkey -noout -in certificate.pem | 59 | # openssl rsa -pubin -outform der | 60 | # openssl dgst -sha256 -binary | base64 61 | # The result should be a base64-encoded blob that looks like this: 62 | # "Gi/HIwdiMcPZo2KBjnstF5kQdLI5bPrYJ8i3Vi6Ybck=" 63 | # 64 | # 3. Pass a flag to Chromium indicating what host and port should be allowed 65 | # to use the self-signed certificate. For instance, if the host is 66 | # localhost, and the port is 4433, the flag would be: 67 | # --origin-to-force-quic-on=localhost:4433 68 | # 69 | # 4. Pass a flag to Chromium indicating which certificate needs to be trusted. 70 | # For the example above, that flag would be: 71 | # --ignore-certificate-errors-spki-list=Gi/HIwdiMcPZo2KBjnstF5kQdLI5bPrYJ8i3Vi6Ybck= 72 | # 73 | # See https://www.chromium.org/developers/how-tos/run-chromium-with-flags for 74 | # details on how to run Chromium with flags. 75 | 76 | import argparse 77 | import asyncio 78 | import io 79 | import os 80 | import struct 81 | import urllib.parse 82 | from collections import defaultdict 83 | from typing import Dict, Optional 84 | 85 | from aioquic.asyncio import QuicConnectionProtocol, serve 86 | from aioquic.quic.configuration import QuicConfiguration 87 | from aioquic.quic.connection import QuicConnection, END_STATES 88 | from aioquic.quic.events import StreamDataReceived, StreamReset, DatagramFrameReceived, QuicEvent 89 | from aioquic.tls import SessionTicket 90 | 91 | BIND_ADDRESS = '::1' 92 | BIND_PORT = 4433 93 | ALLOWED_ORIGINS = {'localhost', 'googlechrome.github.io'} 94 | 95 | 96 | # QUIC uses two lowest bits of the stream ID to indicate whether the stream is: 97 | # (a) unidirectional or bidirectional, 98 | # (b) initiated by the client or by the server. 99 | # See https://tools.ietf.org/html/draft-ietf-quic-transport-27#section-2.1 for 100 | # more details. 101 | def is_client_bidi_stream(stream_id): 102 | return stream_id % 4 == 0 103 | 104 | 105 | # CounterHandler implements a really simple protocol: 106 | # - For every incoming bidirectional stream, it counts bytes it receives on 107 | # that stream until the stream is closed, and then replies with that byte 108 | # count on the same stream. 109 | # - For every incoming unidirectional stream, it counts bytes it receives on 110 | # that stream until the stream is closed, and then replies with that byte 111 | # count on a new unidirectional stream. 112 | # - For every incoming datagram, it sends a datagram with the length of 113 | # datagram that was just received. 114 | class CounterHandler: 115 | 116 | def __init__(self, connection) -> None: 117 | self.connection = connection 118 | self.counters = defaultdict(int) 119 | 120 | def quic_event_received(self, event: QuicEvent) -> None: 121 | if isinstance(event, DatagramFrameReceived): 122 | payload = str(len(event.data)).encode('ascii') 123 | self.connection.send_datagram_frame(payload) 124 | 125 | if isinstance(event, StreamDataReceived): 126 | self.counters[event.stream_id] += len(event.data) 127 | if event.end_stream: 128 | if is_client_bidi_stream(event.stream_id): 129 | response_id = event.stream_id 130 | else: 131 | response_id = self.connection.get_next_available_stream_id( 132 | is_unidirectional=True) 133 | payload = str(self.counters[event.stream_id]).encode('ascii') 134 | self.connection.send_stream_data(response_id, payload, True) 135 | del self.counters[event.stream_id] 136 | 137 | # Streams in QUIC can be closed in two ways: normal (FIN) and abnormal 138 | # (resets). FIN is handled by event.end_stream logic above; the code 139 | # below handles the resets. 140 | if isinstance(event, StreamReset): 141 | try: 142 | del self.counters[event.stream_id] 143 | except KeyError: 144 | pass 145 | 146 | 147 | # QuicTransportProtocol handles the beginning of a QuicTransport connection: it 148 | # parses the incoming URL, and routes the transport events to a relevant 149 | # handler (in this example, CounterHandler). It does that by waiting for a 150 | # client indication (a special stream with protocol headers), and buffering all 151 | # unrelated events until the client indication can be fully processed. 152 | class QuicTransportProtocol(QuicConnectionProtocol): 153 | 154 | def __init__(self, *args, **kwargs) -> None: 155 | super().__init__(*args, **kwargs) 156 | self.pending_events = [] 157 | self.handler = None 158 | self.client_indication_data = b'' 159 | 160 | def quic_event_received(self, event: QuicEvent) -> None: 161 | try: 162 | if self.is_closing_or_closed(): 163 | return 164 | 165 | # If the handler is available, that means the connection has been 166 | # established and the client indication has been processed. 167 | if self.handler is not None: 168 | self.handler.quic_event_received(event) 169 | return 170 | 171 | if isinstance(event, StreamDataReceived) and event.stream_id == 2: 172 | self.client_indication_data += event.data 173 | if event.end_stream: 174 | self.process_client_indication() 175 | if self.is_closing_or_closed(): 176 | return 177 | # Pass all buffered events into the handler now that it's 178 | # available. 179 | for e in self.pending_events: 180 | self.handler.quic_event_received(e) 181 | self.pending_events.clear() 182 | else: 183 | # We have received some application data before we have the 184 | # request URL available, which is possible since there is no 185 | # ordering guarantee on data between different QUIC streams. 186 | # Buffer the data for now. 187 | self.pending_events.append(event) 188 | 189 | except Exception as e: 190 | self.handler = None 191 | self.close() 192 | 193 | # Client indication follows a "key-length-value" format, where key and 194 | # length are 16-bit integers. See 195 | # https://tools.ietf.org/html/draft-vvv-webtransport-quic-01#section-3.2 196 | def parse_client_indication(self, bs): 197 | while True: 198 | prefix = bs.read(4) 199 | if len(prefix) == 0: 200 | return # End-of-stream reached. 201 | if len(prefix) != 4: 202 | raise Exception('Truncated key-length tag') 203 | key, length = struct.unpack('!HH', prefix) 204 | value = bs.read(length) 205 | if len(value) != length: 206 | raise Exception('Truncated value') 207 | yield (key, value) 208 | 209 | def process_client_indication(self) -> None: 210 | KEY_ORIGIN = 0 211 | KEY_PATH = 1 212 | indication = dict( 213 | self.parse_client_indication(io.BytesIO( 214 | self.client_indication_data))) 215 | 216 | origin = urllib.parse.urlparse(indication[KEY_ORIGIN].decode()) 217 | path = urllib.parse.urlparse(indication[KEY_PATH]).decode() 218 | 219 | # Verify that the origin host is allowed to talk to this server. This 220 | # is similar to the CORS (Cross-Origin Resource Sharing) mechanism in 221 | # HTTP. See . 222 | if origin.hostname not in ALLOWED_ORIGINS: 223 | raise Exception('Wrong origin specified') 224 | 225 | # Dispatch the incoming connection based on the path specified in the 226 | # URL. 227 | self.handler = CounterHandler(self._quic) 228 | 229 | 230 | def is_closing_or_closed(self) -> bool: 231 | return self._quic._close_pending or self._quic._state in END_STATES 232 | 233 | 234 | if __name__ == '__main__': 235 | parser = argparse.ArgumentParser() 236 | parser.add_argument('certificate') 237 | parser.add_argument('key') 238 | args = parser.parse_args() 239 | 240 | configuration = QuicConfiguration( 241 | # Identifies the protocol used. The origin trial uses the protocol 242 | # described in draft-vvv-webtransport-quic-01, hence the ALPN value. 243 | # See https://tools.ietf.org/html/draft-vvv-webtransport-quic-01#section-3.1 244 | alpn_protocols=['wq-vvv-01'], 245 | is_client=False, 246 | 247 | # Note that this is just an upper limit; the real maximum datagram size 248 | # available depends on the MTU of the path. See 249 | # . 250 | max_datagram_frame_size=1500, 251 | ) 252 | configuration.load_cert_chain(args.certificate, args.key) 253 | 254 | loop = asyncio.get_event_loop() 255 | loop.run_until_complete( 256 | serve( 257 | BIND_ADDRESS, 258 | BIND_PORT, 259 | configuration=configuration, 260 | create_protocol=QuicTransportProtocol, 261 | )) 262 | loop.run_forever() 263 | -------------------------------------------------------------------------------- /webcodecs-quic/cbor.js: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License (MIT) 3 | * 4 | * Copyright (c) 2014-2016 Patrick Gansterer 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all 14 | * copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | * SOFTWARE. 23 | */ 24 | 25 | (function(global, undefined) { "use strict"; 26 | var POW_2_24 = 5.960464477539063e-8, 27 | POW_2_32 = 4294967296, 28 | POW_2_53 = 9007199254740992; 29 | 30 | function encode(value) { 31 | var data = new ArrayBuffer(256); 32 | var dataView = new DataView(data); 33 | var lastLength; 34 | var offset = 0; 35 | 36 | function prepareWrite(length) { 37 | var newByteLength = data.byteLength; 38 | var requiredLength = offset + length; 39 | while (newByteLength < requiredLength) 40 | newByteLength <<= 1; 41 | if (newByteLength !== data.byteLength) { 42 | var oldDataView = dataView; 43 | data = new ArrayBuffer(newByteLength); 44 | dataView = new DataView(data); 45 | var uint32count = (offset + 3) >> 2; 46 | for (var i = 0; i < uint32count; ++i) 47 | dataView.setUint32(i << 2, oldDataView.getUint32(i << 2)); 48 | } 49 | 50 | lastLength = length; 51 | return dataView; 52 | } 53 | function commitWrite() { 54 | offset += lastLength; 55 | } 56 | function writeFloat64(value) { 57 | commitWrite(prepareWrite(8).setFloat64(offset, value)); 58 | } 59 | function writeUint8(value) { 60 | commitWrite(prepareWrite(1).setUint8(offset, value)); 61 | } 62 | function writeUint8Array(value) { 63 | var dataView = prepareWrite(value.length); 64 | for (var i = 0; i < value.length; ++i) 65 | dataView.setUint8(offset + i, value[i]); 66 | commitWrite(); 67 | } 68 | function writeUint16(value) { 69 | commitWrite(prepareWrite(2).setUint16(offset, value)); 70 | } 71 | function writeUint32(value) { 72 | commitWrite(prepareWrite(4).setUint32(offset, value)); 73 | } 74 | function writeUint64(value) { 75 | var low = value % POW_2_32; 76 | var high = (value - low) / POW_2_32; 77 | var dataView = prepareWrite(8); 78 | dataView.setUint32(offset, high); 79 | dataView.setUint32(offset + 4, low); 80 | commitWrite(); 81 | } 82 | function writeTypeAndLength(type, length) { 83 | if (length < 24) { 84 | writeUint8(type << 5 | length); 85 | } else if (length < 0x100) { 86 | writeUint8(type << 5 | 24); 87 | writeUint8(length); 88 | } else if (length < 0x10000) { 89 | writeUint8(type << 5 | 25); 90 | writeUint16(length); 91 | } else if (length < 0x100000000) { 92 | writeUint8(type << 5 | 26); 93 | writeUint32(length); 94 | } else { 95 | writeUint8(type << 5 | 27); 96 | writeUint64(length); 97 | } 98 | } 99 | 100 | function encodeItem(value) { 101 | var i; 102 | 103 | if (value === false) 104 | return writeUint8(0xf4); 105 | if (value === true) 106 | return writeUint8(0xf5); 107 | if (value === null) 108 | return writeUint8(0xf6); 109 | if (value === undefined) 110 | return writeUint8(0xf7); 111 | 112 | switch (typeof value) { 113 | case "number": 114 | if (Math.floor(value) === value) { 115 | if (0 <= value && value <= POW_2_53) 116 | return writeTypeAndLength(0, value); 117 | if (-POW_2_53 <= value && value < 0) 118 | return writeTypeAndLength(1, -(value + 1)); 119 | } 120 | writeUint8(0xfb); 121 | return writeFloat64(value); 122 | 123 | case "string": 124 | var utf8data = []; 125 | for (i = 0; i < value.length; ++i) { 126 | var charCode = value.charCodeAt(i); 127 | if (charCode < 0x80) { 128 | utf8data.push(charCode); 129 | } else if (charCode < 0x800) { 130 | utf8data.push(0xc0 | charCode >> 6); 131 | utf8data.push(0x80 | charCode & 0x3f); 132 | } else if (charCode < 0xd800) { 133 | utf8data.push(0xe0 | charCode >> 12); 134 | utf8data.push(0x80 | (charCode >> 6) & 0x3f); 135 | utf8data.push(0x80 | charCode & 0x3f); 136 | } else { 137 | charCode = (charCode & 0x3ff) << 10; 138 | charCode |= value.charCodeAt(++i) & 0x3ff; 139 | charCode += 0x10000; 140 | 141 | utf8data.push(0xf0 | charCode >> 18); 142 | utf8data.push(0x80 | (charCode >> 12) & 0x3f); 143 | utf8data.push(0x80 | (charCode >> 6) & 0x3f); 144 | utf8data.push(0x80 | charCode & 0x3f); 145 | } 146 | } 147 | 148 | writeTypeAndLength(3, utf8data.length); 149 | return writeUint8Array(utf8data); 150 | 151 | default: 152 | var length; 153 | if (Array.isArray(value)) { 154 | length = value.length; 155 | writeTypeAndLength(4, length); 156 | for (i = 0; i < length; ++i) 157 | encodeItem(value[i]); 158 | } else if (value instanceof Uint8Array) { 159 | writeTypeAndLength(2, value.length); 160 | writeUint8Array(value); 161 | } else { 162 | var keys = Object.keys(value); 163 | length = keys.length; 164 | writeTypeAndLength(5, length); 165 | for (i = 0; i < length; ++i) { 166 | var key = keys[i]; 167 | encodeItem(key); 168 | encodeItem(value[key]); 169 | } 170 | } 171 | } 172 | } 173 | 174 | encodeItem(value); 175 | 176 | if ("slice" in data) 177 | return data.slice(0, offset); 178 | 179 | var ret = new ArrayBuffer(offset); 180 | var retView = new DataView(ret); 181 | for (var i = 0; i < offset; ++i) 182 | retView.setUint8(i, dataView.getUint8(i)); 183 | return ret; 184 | } 185 | 186 | function decode(data, tagger, simpleValue) { 187 | var dataView = new DataView(data); 188 | var offset = 0; 189 | 190 | if (typeof tagger !== "function") 191 | tagger = function(value) { return value; }; 192 | if (typeof simpleValue !== "function") 193 | simpleValue = function() { return undefined; }; 194 | 195 | function commitRead(length, value) { 196 | offset += length; 197 | return value; 198 | } 199 | function readArrayBuffer(length) { 200 | return commitRead(length, new Uint8Array(data, offset, length)); 201 | } 202 | function readFloat16() { 203 | var tempArrayBuffer = new ArrayBuffer(4); 204 | var tempDataView = new DataView(tempArrayBuffer); 205 | var value = readUint16(); 206 | 207 | var sign = value & 0x8000; 208 | var exponent = value & 0x7c00; 209 | var fraction = value & 0x03ff; 210 | 211 | if (exponent === 0x7c00) 212 | exponent = 0xff << 10; 213 | else if (exponent !== 0) 214 | exponent += (127 - 15) << 10; 215 | else if (fraction !== 0) 216 | return (sign ? -1 : 1) * fraction * POW_2_24; 217 | 218 | tempDataView.setUint32(0, sign << 16 | exponent << 13 | fraction << 13); 219 | return tempDataView.getFloat32(0); 220 | } 221 | function readFloat32() { 222 | return commitRead(4, dataView.getFloat32(offset)); 223 | } 224 | function readFloat64() { 225 | return commitRead(8, dataView.getFloat64(offset)); 226 | } 227 | function readUint8() { 228 | return commitRead(1, dataView.getUint8(offset)); 229 | } 230 | function readUint16() { 231 | return commitRead(2, dataView.getUint16(offset)); 232 | } 233 | function readUint32() { 234 | return commitRead(4, dataView.getUint32(offset)); 235 | } 236 | function readUint64() { 237 | return readUint32() * POW_2_32 + readUint32(); 238 | } 239 | function readBreak() { 240 | if (dataView.getUint8(offset) !== 0xff) 241 | return false; 242 | offset += 1; 243 | return true; 244 | } 245 | function readLength(additionalInformation) { 246 | if (additionalInformation < 24) 247 | return additionalInformation; 248 | if (additionalInformation === 24) 249 | return readUint8(); 250 | if (additionalInformation === 25) 251 | return readUint16(); 252 | if (additionalInformation === 26) 253 | return readUint32(); 254 | if (additionalInformation === 27) 255 | return readUint64(); 256 | if (additionalInformation === 31) 257 | return -1; 258 | throw "Invalid length encoding"; 259 | } 260 | function readIndefiniteStringLength(majorType) { 261 | var initialByte = readUint8(); 262 | if (initialByte === 0xff) 263 | return -1; 264 | var length = readLength(initialByte & 0x1f); 265 | if (length < 0 || (initialByte >> 5) !== majorType) 266 | throw "Invalid indefinite length element"; 267 | return length; 268 | } 269 | 270 | function appendUtf16Data(utf16data, length) { 271 | for (var i = 0; i < length; ++i) { 272 | var value = readUint8(); 273 | if (value & 0x80) { 274 | if (value < 0xe0) { 275 | value = (value & 0x1f) << 6 276 | | (readUint8() & 0x3f); 277 | length -= 1; 278 | } else if (value < 0xf0) { 279 | value = (value & 0x0f) << 12 280 | | (readUint8() & 0x3f) << 6 281 | | (readUint8() & 0x3f); 282 | length -= 2; 283 | } else { 284 | value = (value & 0x0f) << 18 285 | | (readUint8() & 0x3f) << 12 286 | | (readUint8() & 0x3f) << 6 287 | | (readUint8() & 0x3f); 288 | length -= 3; 289 | } 290 | } 291 | 292 | if (value < 0x10000) { 293 | utf16data.push(value); 294 | } else { 295 | value -= 0x10000; 296 | utf16data.push(0xd800 | (value >> 10)); 297 | utf16data.push(0xdc00 | (value & 0x3ff)); 298 | } 299 | } 300 | } 301 | 302 | function decodeItem() { 303 | var initialByte = readUint8(); 304 | var majorType = initialByte >> 5; 305 | var additionalInformation = initialByte & 0x1f; 306 | var i; 307 | var length; 308 | 309 | if (majorType === 7) { 310 | switch (additionalInformation) { 311 | case 25: 312 | return readFloat16(); 313 | case 26: 314 | return readFloat32(); 315 | case 27: 316 | return readFloat64(); 317 | } 318 | } 319 | 320 | length = readLength(additionalInformation); 321 | if (length < 0 && (majorType < 2 || 6 < majorType)) 322 | throw "Invalid length"; 323 | 324 | switch (majorType) { 325 | case 0: 326 | return length; 327 | case 1: 328 | return -1 - length; 329 | case 2: 330 | if (length < 0) { 331 | var elements = []; 332 | var fullArrayLength = 0; 333 | while ((length = readIndefiniteStringLength(majorType)) >= 0) { 334 | fullArrayLength += length; 335 | elements.push(readArrayBuffer(length)); 336 | } 337 | var fullArray = new Uint8Array(fullArrayLength); 338 | var fullArrayOffset = 0; 339 | for (i = 0; i < elements.length; ++i) { 340 | fullArray.set(elements[i], fullArrayOffset); 341 | fullArrayOffset += elements[i].length; 342 | } 343 | return fullArray; 344 | } 345 | return readArrayBuffer(length); 346 | case 3: 347 | var utf16data = []; 348 | if (length < 0) { 349 | while ((length = readIndefiniteStringLength(majorType)) >= 0) 350 | appendUtf16Data(utf16data, length); 351 | } else 352 | appendUtf16Data(utf16data, length); 353 | return String.fromCharCode.apply(null, utf16data); 354 | case 4: 355 | var retArray; 356 | if (length < 0) { 357 | retArray = []; 358 | while (!readBreak()) 359 | retArray.push(decodeItem()); 360 | } else { 361 | retArray = new Array(length); 362 | for (i = 0; i < length; ++i) 363 | retArray[i] = decodeItem(); 364 | } 365 | return retArray; 366 | case 5: 367 | var retObject = {}; 368 | for (i = 0; i < length || length < 0 && !readBreak(); ++i) { 369 | var key = decodeItem(); 370 | retObject[key] = decodeItem(); 371 | } 372 | return retObject; 373 | case 6: 374 | return tagger(decodeItem(), length); 375 | case 7: 376 | switch (length) { 377 | case 20: 378 | return false; 379 | case 21: 380 | return true; 381 | case 22: 382 | return null; 383 | case 23: 384 | return undefined; 385 | default: 386 | return simpleValue(length); 387 | } 388 | } 389 | } 390 | 391 | var ret = decodeItem(); 392 | if (offset !== data.byteLength) 393 | throw "Remaining bytes"; 394 | return ret; 395 | } 396 | 397 | var obj = { encode: encode, decode: decode }; 398 | 399 | if (typeof define === "function" && define.amd) 400 | define("cbor/cbor", obj); 401 | else if (typeof module !== "undefined" && module.exports) 402 | module.exports = obj; 403 | else if (!global.CBOR) 404 | global.CBOR = obj; 405 | 406 | })(this); 407 | -------------------------------------------------------------------------------- /webcodecs-datachannel/cbor.js: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License (MIT) 3 | * 4 | * Copyright (c) 2014-2016 Patrick Gansterer 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all 14 | * copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | * SOFTWARE. 23 | */ 24 | 25 | (function(global, undefined) { "use strict"; 26 | var POW_2_24 = 5.960464477539063e-8, 27 | POW_2_32 = 4294967296, 28 | POW_2_53 = 9007199254740992; 29 | 30 | function encode(value) { 31 | var data = new ArrayBuffer(256); 32 | var dataView = new DataView(data); 33 | var lastLength; 34 | var offset = 0; 35 | 36 | function prepareWrite(length) { 37 | var newByteLength = data.byteLength; 38 | var requiredLength = offset + length; 39 | while (newByteLength < requiredLength) 40 | newByteLength <<= 1; 41 | if (newByteLength !== data.byteLength) { 42 | var oldDataView = dataView; 43 | data = new ArrayBuffer(newByteLength); 44 | dataView = new DataView(data); 45 | var uint32count = (offset + 3) >> 2; 46 | for (var i = 0; i < uint32count; ++i) 47 | dataView.setUint32(i << 2, oldDataView.getUint32(i << 2)); 48 | } 49 | 50 | lastLength = length; 51 | return dataView; 52 | } 53 | function commitWrite() { 54 | offset += lastLength; 55 | } 56 | function writeFloat64(value) { 57 | commitWrite(prepareWrite(8).setFloat64(offset, value)); 58 | } 59 | function writeUint8(value) { 60 | commitWrite(prepareWrite(1).setUint8(offset, value)); 61 | } 62 | function writeUint8Array(value) { 63 | var dataView = prepareWrite(value.length); 64 | for (var i = 0; i < value.length; ++i) 65 | dataView.setUint8(offset + i, value[i]); 66 | commitWrite(); 67 | } 68 | function writeUint16(value) { 69 | commitWrite(prepareWrite(2).setUint16(offset, value)); 70 | } 71 | function writeUint32(value) { 72 | commitWrite(prepareWrite(4).setUint32(offset, value)); 73 | } 74 | function writeUint64(value) { 75 | var low = value % POW_2_32; 76 | var high = (value - low) / POW_2_32; 77 | var dataView = prepareWrite(8); 78 | dataView.setUint32(offset, high); 79 | dataView.setUint32(offset + 4, low); 80 | commitWrite(); 81 | } 82 | function writeTypeAndLength(type, length) { 83 | if (length < 24) { 84 | writeUint8(type << 5 | length); 85 | } else if (length < 0x100) { 86 | writeUint8(type << 5 | 24); 87 | writeUint8(length); 88 | } else if (length < 0x10000) { 89 | writeUint8(type << 5 | 25); 90 | writeUint16(length); 91 | } else if (length < 0x100000000) { 92 | writeUint8(type << 5 | 26); 93 | writeUint32(length); 94 | } else { 95 | writeUint8(type << 5 | 27); 96 | writeUint64(length); 97 | } 98 | } 99 | 100 | function encodeItem(value) { 101 | var i; 102 | 103 | if (value === false) 104 | return writeUint8(0xf4); 105 | if (value === true) 106 | return writeUint8(0xf5); 107 | if (value === null) 108 | return writeUint8(0xf6); 109 | if (value === undefined) 110 | return writeUint8(0xf7); 111 | 112 | switch (typeof value) { 113 | case "number": 114 | if (Math.floor(value) === value) { 115 | if (0 <= value && value <= POW_2_53) 116 | return writeTypeAndLength(0, value); 117 | if (-POW_2_53 <= value && value < 0) 118 | return writeTypeAndLength(1, -(value + 1)); 119 | } 120 | writeUint8(0xfb); 121 | return writeFloat64(value); 122 | 123 | case "string": 124 | var utf8data = []; 125 | for (i = 0; i < value.length; ++i) { 126 | var charCode = value.charCodeAt(i); 127 | if (charCode < 0x80) { 128 | utf8data.push(charCode); 129 | } else if (charCode < 0x800) { 130 | utf8data.push(0xc0 | charCode >> 6); 131 | utf8data.push(0x80 | charCode & 0x3f); 132 | } else if (charCode < 0xd800) { 133 | utf8data.push(0xe0 | charCode >> 12); 134 | utf8data.push(0x80 | (charCode >> 6) & 0x3f); 135 | utf8data.push(0x80 | charCode & 0x3f); 136 | } else { 137 | charCode = (charCode & 0x3ff) << 10; 138 | charCode |= value.charCodeAt(++i) & 0x3ff; 139 | charCode += 0x10000; 140 | 141 | utf8data.push(0xf0 | charCode >> 18); 142 | utf8data.push(0x80 | (charCode >> 12) & 0x3f); 143 | utf8data.push(0x80 | (charCode >> 6) & 0x3f); 144 | utf8data.push(0x80 | charCode & 0x3f); 145 | } 146 | } 147 | 148 | writeTypeAndLength(3, utf8data.length); 149 | return writeUint8Array(utf8data); 150 | 151 | default: 152 | var length; 153 | if (Array.isArray(value)) { 154 | length = value.length; 155 | writeTypeAndLength(4, length); 156 | for (i = 0; i < length; ++i) 157 | encodeItem(value[i]); 158 | } else if (value instanceof Uint8Array) { 159 | writeTypeAndLength(2, value.length); 160 | writeUint8Array(value); 161 | } else { 162 | var keys = Object.keys(value); 163 | length = keys.length; 164 | writeTypeAndLength(5, length); 165 | for (i = 0; i < length; ++i) { 166 | var key = keys[i]; 167 | encodeItem(key); 168 | encodeItem(value[key]); 169 | } 170 | } 171 | } 172 | } 173 | 174 | encodeItem(value); 175 | 176 | if ("slice" in data) 177 | return data.slice(0, offset); 178 | 179 | var ret = new ArrayBuffer(offset); 180 | var retView = new DataView(ret); 181 | for (var i = 0; i < offset; ++i) 182 | retView.setUint8(i, dataView.getUint8(i)); 183 | return ret; 184 | } 185 | 186 | function decode(data, tagger, simpleValue) { 187 | var dataView = new DataView(data); 188 | var offset = 0; 189 | 190 | if (typeof tagger !== "function") 191 | tagger = function(value) { return value; }; 192 | if (typeof simpleValue !== "function") 193 | simpleValue = function() { return undefined; }; 194 | 195 | function commitRead(length, value) { 196 | offset += length; 197 | return value; 198 | } 199 | function readArrayBuffer(length) { 200 | return commitRead(length, new Uint8Array(data, offset, length)); 201 | } 202 | function readFloat16() { 203 | var tempArrayBuffer = new ArrayBuffer(4); 204 | var tempDataView = new DataView(tempArrayBuffer); 205 | var value = readUint16(); 206 | 207 | var sign = value & 0x8000; 208 | var exponent = value & 0x7c00; 209 | var fraction = value & 0x03ff; 210 | 211 | if (exponent === 0x7c00) 212 | exponent = 0xff << 10; 213 | else if (exponent !== 0) 214 | exponent += (127 - 15) << 10; 215 | else if (fraction !== 0) 216 | return (sign ? -1 : 1) * fraction * POW_2_24; 217 | 218 | tempDataView.setUint32(0, sign << 16 | exponent << 13 | fraction << 13); 219 | return tempDataView.getFloat32(0); 220 | } 221 | function readFloat32() { 222 | return commitRead(4, dataView.getFloat32(offset)); 223 | } 224 | function readFloat64() { 225 | return commitRead(8, dataView.getFloat64(offset)); 226 | } 227 | function readUint8() { 228 | return commitRead(1, dataView.getUint8(offset)); 229 | } 230 | function readUint16() { 231 | return commitRead(2, dataView.getUint16(offset)); 232 | } 233 | function readUint32() { 234 | return commitRead(4, dataView.getUint32(offset)); 235 | } 236 | function readUint64() { 237 | return readUint32() * POW_2_32 + readUint32(); 238 | } 239 | function readBreak() { 240 | if (dataView.getUint8(offset) !== 0xff) 241 | return false; 242 | offset += 1; 243 | return true; 244 | } 245 | function readLength(additionalInformation) { 246 | if (additionalInformation < 24) 247 | return additionalInformation; 248 | if (additionalInformation === 24) 249 | return readUint8(); 250 | if (additionalInformation === 25) 251 | return readUint16(); 252 | if (additionalInformation === 26) 253 | return readUint32(); 254 | if (additionalInformation === 27) 255 | return readUint64(); 256 | if (additionalInformation === 31) 257 | return -1; 258 | throw "Invalid length encoding"; 259 | } 260 | function readIndefiniteStringLength(majorType) { 261 | var initialByte = readUint8(); 262 | if (initialByte === 0xff) 263 | return -1; 264 | var length = readLength(initialByte & 0x1f); 265 | if (length < 0 || (initialByte >> 5) !== majorType) 266 | throw "Invalid indefinite length element"; 267 | return length; 268 | } 269 | 270 | function appendUtf16Data(utf16data, length) { 271 | for (var i = 0; i < length; ++i) { 272 | var value = readUint8(); 273 | if (value & 0x80) { 274 | if (value < 0xe0) { 275 | value = (value & 0x1f) << 6 276 | | (readUint8() & 0x3f); 277 | length -= 1; 278 | } else if (value < 0xf0) { 279 | value = (value & 0x0f) << 12 280 | | (readUint8() & 0x3f) << 6 281 | | (readUint8() & 0x3f); 282 | length -= 2; 283 | } else { 284 | value = (value & 0x0f) << 18 285 | | (readUint8() & 0x3f) << 12 286 | | (readUint8() & 0x3f) << 6 287 | | (readUint8() & 0x3f); 288 | length -= 3; 289 | } 290 | } 291 | 292 | if (value < 0x10000) { 293 | utf16data.push(value); 294 | } else { 295 | value -= 0x10000; 296 | utf16data.push(0xd800 | (value >> 10)); 297 | utf16data.push(0xdc00 | (value & 0x3ff)); 298 | } 299 | } 300 | } 301 | 302 | function decodeItem() { 303 | var initialByte = readUint8(); 304 | var majorType = initialByte >> 5; 305 | var additionalInformation = initialByte & 0x1f; 306 | var i; 307 | var length; 308 | 309 | if (majorType === 7) { 310 | switch (additionalInformation) { 311 | case 25: 312 | return readFloat16(); 313 | case 26: 314 | return readFloat32(); 315 | case 27: 316 | return readFloat64(); 317 | } 318 | } 319 | 320 | length = readLength(additionalInformation); 321 | if (length < 0 && (majorType < 2 || 6 < majorType)) 322 | throw "Invalid length"; 323 | 324 | switch (majorType) { 325 | case 0: 326 | return length; 327 | case 1: 328 | return -1 - length; 329 | case 2: 330 | if (length < 0) { 331 | var elements = []; 332 | var fullArrayLength = 0; 333 | while ((length = readIndefiniteStringLength(majorType)) >= 0) { 334 | fullArrayLength += length; 335 | elements.push(readArrayBuffer(length)); 336 | } 337 | var fullArray = new Uint8Array(fullArrayLength); 338 | var fullArrayOffset = 0; 339 | for (i = 0; i < elements.length; ++i) { 340 | fullArray.set(elements[i], fullArrayOffset); 341 | fullArrayOffset += elements[i].length; 342 | } 343 | return fullArray; 344 | } 345 | return readArrayBuffer(length); 346 | case 3: 347 | var utf16data = []; 348 | if (length < 0) { 349 | while ((length = readIndefiniteStringLength(majorType)) >= 0) 350 | appendUtf16Data(utf16data, length); 351 | } else 352 | appendUtf16Data(utf16data, length); 353 | return String.fromCharCode.apply(null, utf16data); 354 | case 4: 355 | var retArray; 356 | if (length < 0) { 357 | retArray = []; 358 | while (!readBreak()) 359 | retArray.push(decodeItem()); 360 | } else { 361 | retArray = new Array(length); 362 | for (i = 0; i < length; ++i) 363 | retArray[i] = decodeItem(); 364 | } 365 | return retArray; 366 | case 5: 367 | var retObject = {}; 368 | for (i = 0; i < length || length < 0 && !readBreak(); ++i) { 369 | var key = decodeItem(); 370 | retObject[key] = decodeItem(); 371 | } 372 | return retObject; 373 | case 6: 374 | return tagger(decodeItem(), length); 375 | case 7: 376 | switch (length) { 377 | case 20: 378 | return false; 379 | case 21: 380 | return true; 381 | case 22: 382 | return null; 383 | case 23: 384 | return undefined; 385 | default: 386 | return simpleValue(length); 387 | } 388 | } 389 | } 390 | 391 | var ret = decodeItem(); 392 | if (offset !== data.byteLength) 393 | throw "Remaining bytes"; 394 | return ret; 395 | } 396 | 397 | var obj = { encode: encode, decode: decode }; 398 | 399 | if (typeof define === "function" && define.amd) 400 | define("cbor/cbor", obj); 401 | else if (typeof module !== "undefined" && module.exports) 402 | module.exports = obj; 403 | else if (!global.CBOR) 404 | global.CBOR = obj; 405 | 406 | })(this); 407 | -------------------------------------------------------------------------------- /webcodecs-websocket/cbor.js: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License (MIT) 3 | * 4 | * Copyright (c) 2014-2016 Patrick Gansterer 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all 14 | * copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | * SOFTWARE. 23 | */ 24 | 25 | (function(global, undefined) { "use strict"; 26 | var POW_2_24 = 5.960464477539063e-8, 27 | POW_2_32 = 4294967296, 28 | POW_2_53 = 9007199254740992; 29 | 30 | function encode(value) { 31 | var data = new ArrayBuffer(256); 32 | var dataView = new DataView(data); 33 | var lastLength; 34 | var offset = 0; 35 | 36 | function prepareWrite(length) { 37 | var newByteLength = data.byteLength; 38 | var requiredLength = offset + length; 39 | while (newByteLength < requiredLength) 40 | newByteLength <<= 1; 41 | if (newByteLength !== data.byteLength) { 42 | var oldDataView = dataView; 43 | data = new ArrayBuffer(newByteLength); 44 | dataView = new DataView(data); 45 | var uint32count = (offset + 3) >> 2; 46 | for (var i = 0; i < uint32count; ++i) 47 | dataView.setUint32(i << 2, oldDataView.getUint32(i << 2)); 48 | } 49 | 50 | lastLength = length; 51 | return dataView; 52 | } 53 | function commitWrite() { 54 | offset += lastLength; 55 | } 56 | function writeFloat64(value) { 57 | commitWrite(prepareWrite(8).setFloat64(offset, value)); 58 | } 59 | function writeUint8(value) { 60 | commitWrite(prepareWrite(1).setUint8(offset, value)); 61 | } 62 | function writeUint8Array(value) { 63 | var dataView = prepareWrite(value.length); 64 | for (var i = 0; i < value.length; ++i) 65 | dataView.setUint8(offset + i, value[i]); 66 | commitWrite(); 67 | } 68 | function writeUint16(value) { 69 | commitWrite(prepareWrite(2).setUint16(offset, value)); 70 | } 71 | function writeUint32(value) { 72 | commitWrite(prepareWrite(4).setUint32(offset, value)); 73 | } 74 | function writeUint64(value) { 75 | var low = value % POW_2_32; 76 | var high = (value - low) / POW_2_32; 77 | var dataView = prepareWrite(8); 78 | dataView.setUint32(offset, high); 79 | dataView.setUint32(offset + 4, low); 80 | commitWrite(); 81 | } 82 | function writeTypeAndLength(type, length) { 83 | if (length < 24) { 84 | writeUint8(type << 5 | length); 85 | } else if (length < 0x100) { 86 | writeUint8(type << 5 | 24); 87 | writeUint8(length); 88 | } else if (length < 0x10000) { 89 | writeUint8(type << 5 | 25); 90 | writeUint16(length); 91 | } else if (length < 0x100000000) { 92 | writeUint8(type << 5 | 26); 93 | writeUint32(length); 94 | } else { 95 | writeUint8(type << 5 | 27); 96 | writeUint64(length); 97 | } 98 | } 99 | 100 | function encodeItem(value) { 101 | var i; 102 | 103 | if (value === false) 104 | return writeUint8(0xf4); 105 | if (value === true) 106 | return writeUint8(0xf5); 107 | if (value === null) 108 | return writeUint8(0xf6); 109 | if (value === undefined) 110 | return writeUint8(0xf7); 111 | 112 | switch (typeof value) { 113 | case "number": 114 | if (Math.floor(value) === value) { 115 | if (0 <= value && value <= POW_2_53) 116 | return writeTypeAndLength(0, value); 117 | if (-POW_2_53 <= value && value < 0) 118 | return writeTypeAndLength(1, -(value + 1)); 119 | } 120 | writeUint8(0xfb); 121 | return writeFloat64(value); 122 | 123 | case "string": 124 | var utf8data = []; 125 | for (i = 0; i < value.length; ++i) { 126 | var charCode = value.charCodeAt(i); 127 | if (charCode < 0x80) { 128 | utf8data.push(charCode); 129 | } else if (charCode < 0x800) { 130 | utf8data.push(0xc0 | charCode >> 6); 131 | utf8data.push(0x80 | charCode & 0x3f); 132 | } else if (charCode < 0xd800) { 133 | utf8data.push(0xe0 | charCode >> 12); 134 | utf8data.push(0x80 | (charCode >> 6) & 0x3f); 135 | utf8data.push(0x80 | charCode & 0x3f); 136 | } else { 137 | charCode = (charCode & 0x3ff) << 10; 138 | charCode |= value.charCodeAt(++i) & 0x3ff; 139 | charCode += 0x10000; 140 | 141 | utf8data.push(0xf0 | charCode >> 18); 142 | utf8data.push(0x80 | (charCode >> 12) & 0x3f); 143 | utf8data.push(0x80 | (charCode >> 6) & 0x3f); 144 | utf8data.push(0x80 | charCode & 0x3f); 145 | } 146 | } 147 | 148 | writeTypeAndLength(3, utf8data.length); 149 | return writeUint8Array(utf8data); 150 | 151 | default: 152 | var length; 153 | if (Array.isArray(value)) { 154 | length = value.length; 155 | writeTypeAndLength(4, length); 156 | for (i = 0; i < length; ++i) 157 | encodeItem(value[i]); 158 | } else if (value instanceof Uint8Array) { 159 | writeTypeAndLength(2, value.length); 160 | writeUint8Array(value); 161 | } else { 162 | var keys = Object.keys(value); 163 | length = keys.length; 164 | writeTypeAndLength(5, length); 165 | for (i = 0; i < length; ++i) { 166 | var key = keys[i]; 167 | encodeItem(key); 168 | encodeItem(value[key]); 169 | } 170 | } 171 | } 172 | } 173 | 174 | encodeItem(value); 175 | 176 | if ("slice" in data) 177 | return data.slice(0, offset); 178 | 179 | var ret = new ArrayBuffer(offset); 180 | var retView = new DataView(ret); 181 | for (var i = 0; i < offset; ++i) 182 | retView.setUint8(i, dataView.getUint8(i)); 183 | return ret; 184 | } 185 | 186 | function decode(data, tagger, simpleValue) { 187 | var dataView = new DataView(data); 188 | var offset = 0; 189 | 190 | if (typeof tagger !== "function") 191 | tagger = function(value) { return value; }; 192 | if (typeof simpleValue !== "function") 193 | simpleValue = function() { return undefined; }; 194 | 195 | function commitRead(length, value) { 196 | offset += length; 197 | return value; 198 | } 199 | function readArrayBuffer(length) { 200 | return commitRead(length, new Uint8Array(data, offset, length)); 201 | } 202 | function readFloat16() { 203 | var tempArrayBuffer = new ArrayBuffer(4); 204 | var tempDataView = new DataView(tempArrayBuffer); 205 | var value = readUint16(); 206 | 207 | var sign = value & 0x8000; 208 | var exponent = value & 0x7c00; 209 | var fraction = value & 0x03ff; 210 | 211 | if (exponent === 0x7c00) 212 | exponent = 0xff << 10; 213 | else if (exponent !== 0) 214 | exponent += (127 - 15) << 10; 215 | else if (fraction !== 0) 216 | return (sign ? -1 : 1) * fraction * POW_2_24; 217 | 218 | tempDataView.setUint32(0, sign << 16 | exponent << 13 | fraction << 13); 219 | return tempDataView.getFloat32(0); 220 | } 221 | function readFloat32() { 222 | return commitRead(4, dataView.getFloat32(offset)); 223 | } 224 | function readFloat64() { 225 | return commitRead(8, dataView.getFloat64(offset)); 226 | } 227 | function readUint8() { 228 | return commitRead(1, dataView.getUint8(offset)); 229 | } 230 | function readUint16() { 231 | return commitRead(2, dataView.getUint16(offset)); 232 | } 233 | function readUint32() { 234 | return commitRead(4, dataView.getUint32(offset)); 235 | } 236 | function readUint64() { 237 | return readUint32() * POW_2_32 + readUint32(); 238 | } 239 | function readBreak() { 240 | if (dataView.getUint8(offset) !== 0xff) 241 | return false; 242 | offset += 1; 243 | return true; 244 | } 245 | function readLength(additionalInformation) { 246 | if (additionalInformation < 24) 247 | return additionalInformation; 248 | if (additionalInformation === 24) 249 | return readUint8(); 250 | if (additionalInformation === 25) 251 | return readUint16(); 252 | if (additionalInformation === 26) 253 | return readUint32(); 254 | if (additionalInformation === 27) 255 | return readUint64(); 256 | if (additionalInformation === 31) 257 | return -1; 258 | throw "Invalid length encoding"; 259 | } 260 | function readIndefiniteStringLength(majorType) { 261 | var initialByte = readUint8(); 262 | if (initialByte === 0xff) 263 | return -1; 264 | var length = readLength(initialByte & 0x1f); 265 | if (length < 0 || (initialByte >> 5) !== majorType) 266 | throw "Invalid indefinite length element"; 267 | return length; 268 | } 269 | 270 | function appendUtf16Data(utf16data, length) { 271 | for (var i = 0; i < length; ++i) { 272 | var value = readUint8(); 273 | if (value & 0x80) { 274 | if (value < 0xe0) { 275 | value = (value & 0x1f) << 6 276 | | (readUint8() & 0x3f); 277 | length -= 1; 278 | } else if (value < 0xf0) { 279 | value = (value & 0x0f) << 12 280 | | (readUint8() & 0x3f) << 6 281 | | (readUint8() & 0x3f); 282 | length -= 2; 283 | } else { 284 | value = (value & 0x0f) << 18 285 | | (readUint8() & 0x3f) << 12 286 | | (readUint8() & 0x3f) << 6 287 | | (readUint8() & 0x3f); 288 | length -= 3; 289 | } 290 | } 291 | 292 | if (value < 0x10000) { 293 | utf16data.push(value); 294 | } else { 295 | value -= 0x10000; 296 | utf16data.push(0xd800 | (value >> 10)); 297 | utf16data.push(0xdc00 | (value & 0x3ff)); 298 | } 299 | } 300 | } 301 | 302 | function decodeItem() { 303 | var initialByte = readUint8(); 304 | var majorType = initialByte >> 5; 305 | var additionalInformation = initialByte & 0x1f; 306 | var i; 307 | var length; 308 | 309 | if (majorType === 7) { 310 | switch (additionalInformation) { 311 | case 25: 312 | return readFloat16(); 313 | case 26: 314 | return readFloat32(); 315 | case 27: 316 | return readFloat64(); 317 | } 318 | } 319 | 320 | length = readLength(additionalInformation); 321 | if (length < 0 && (majorType < 2 || 6 < majorType)) 322 | throw "Invalid length"; 323 | 324 | switch (majorType) { 325 | case 0: 326 | return length; 327 | case 1: 328 | return -1 - length; 329 | case 2: 330 | if (length < 0) { 331 | var elements = []; 332 | var fullArrayLength = 0; 333 | while ((length = readIndefiniteStringLength(majorType)) >= 0) { 334 | fullArrayLength += length; 335 | elements.push(readArrayBuffer(length)); 336 | } 337 | var fullArray = new Uint8Array(fullArrayLength); 338 | var fullArrayOffset = 0; 339 | for (i = 0; i < elements.length; ++i) { 340 | fullArray.set(elements[i], fullArrayOffset); 341 | fullArrayOffset += elements[i].length; 342 | } 343 | return fullArray; 344 | } 345 | return readArrayBuffer(length); 346 | case 3: 347 | var utf16data = []; 348 | if (length < 0) { 349 | while ((length = readIndefiniteStringLength(majorType)) >= 0) 350 | appendUtf16Data(utf16data, length); 351 | } else 352 | appendUtf16Data(utf16data, length); 353 | return String.fromCharCode.apply(null, utf16data); 354 | case 4: 355 | var retArray; 356 | if (length < 0) { 357 | retArray = []; 358 | while (!readBreak()) 359 | retArray.push(decodeItem()); 360 | } else { 361 | retArray = new Array(length); 362 | for (i = 0; i < length; ++i) 363 | retArray[i] = decodeItem(); 364 | } 365 | return retArray; 366 | case 5: 367 | var retObject = {}; 368 | for (i = 0; i < length || length < 0 && !readBreak(); ++i) { 369 | var key = decodeItem(); 370 | retObject[key] = decodeItem(); 371 | } 372 | return retObject; 373 | case 6: 374 | return tagger(decodeItem(), length); 375 | case 7: 376 | switch (length) { 377 | case 20: 378 | return false; 379 | case 21: 380 | return true; 381 | case 22: 382 | return null; 383 | case 23: 384 | return undefined; 385 | default: 386 | return simpleValue(length); 387 | } 388 | } 389 | } 390 | 391 | var ret = decodeItem(); 392 | if (offset !== data.byteLength) 393 | throw "Remaining bytes"; 394 | return ret; 395 | } 396 | 397 | var obj = { encode: encode, decode: decode }; 398 | 399 | if (typeof define === "function" && define.amd) 400 | define("cbor/cbor", obj); 401 | else if (typeof module !== "undefined" && module.exports) 402 | module.exports = obj; 403 | else if (!global.CBOR) 404 | global.CBOR = obj; 405 | 406 | })(this); 407 | -------------------------------------------------------------------------------- /webcodecs-datachannel/go.sum: -------------------------------------------------------------------------------- 1 | github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 2 | github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 3 | github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= 4 | github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= 5 | github.com/gin-contrib/cors v1.3.1 h1:doAsuITavI4IOcd0Y19U4B+O0dNWihRyX//nn4sEmgA= 6 | github.com/gin-contrib/cors v1.3.1/go.mod h1:jjEJ4268OPZUcU7k9Pm653S7lXUGcqMADzFA61xsmDk= 7 | github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE= 8 | github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI= 9 | github.com/gin-gonic/gin v1.5.0/go.mod h1:Nd6IXA8m5kNZdNEHMBd93KT+mdY3+bewLgRvmCsR2Do= 10 | github.com/gin-gonic/gin v1.7.1 h1:qC89GU3p8TvKWMAVhEpmpB2CIb1hnqt2UdKZaP93mS8= 11 | github.com/gin-gonic/gin v1.7.1/go.mod h1:jD2toBW3GZUr5UMcdrwQA10I7RuaFOl/SGeDjXkfUtY= 12 | github.com/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4= 13 | github.com/go-playground/locales v0.12.1/go.mod h1:IUMDtCfWo/w/mtMfIE/IG2K+Ey3ygWanZIBtBW0W2TM= 14 | github.com/go-playground/locales v0.13.0 h1:HyWk6mgj5qFqCT5fjGBuRArbVDfE4hi8+e8ceBS/t7Q= 15 | github.com/go-playground/locales v0.13.0/go.mod h1:taPMhCMXrRLJO55olJkUXHZBHCxTMfnGwq/HNwmWNS8= 16 | github.com/go-playground/universal-translator v0.16.0/go.mod h1:1AnU7NaIRDWWzGEKwgtJRd2xk99HeFyHw3yid4rvQIY= 17 | github.com/go-playground/universal-translator v0.17.0 h1:icxd5fm+REJzpZx7ZfpaD876Lmtgy7VtROAbHHXk8no= 18 | github.com/go-playground/universal-translator v0.17.0/go.mod h1:UkSxE5sNxxRwHyU+Scu5vgOQjsIJAF8j9muTVoKLVtA= 19 | github.com/go-playground/validator/v10 v10.4.1 h1:pH2c5ADXtd66mxoE0Zm9SUhxE20r7aM3F26W0hOn+GE= 20 | github.com/go-playground/validator/v10 v10.4.1/go.mod h1:nlOn6nFhuKACm19sB/8EGNn9GlaMV7XkbRSipzJ0Ii4= 21 | github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE= 22 | github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= 23 | github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= 24 | github.com/golang/protobuf v1.3.3 h1:gyjaxf+svBWX08ZjK86iN9geUJF0H6gp2IRKX6Nf6/I= 25 | github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= 26 | github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= 27 | github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= 28 | github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= 29 | github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= 30 | github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= 31 | github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= 32 | github.com/golang/protobuf v1.4.3 h1:JjCZWpVbqXDqFVmTfYWEVTMIYrL/NPdPSCHPJ0T/raM= 33 | github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= 34 | github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= 35 | github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= 36 | github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= 37 | github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= 38 | github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I= 39 | github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= 40 | github.com/gorilla/websocket v1.4.2 h1:+/TMaTYc4QFitKJxsQ7Yye35DkWvkdLcvGKqM+x0Ufc= 41 | github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= 42 | github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= 43 | github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= 44 | github.com/json-iterator/go v1.1.9 h1:9yzud/Ht36ygwatGx56VwCZtlI/2AD15T1X2sjSuGns= 45 | github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= 46 | github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= 47 | github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= 48 | github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= 49 | github.com/leodido/go-urn v1.1.0/go.mod h1:+cyI34gQWZcE1eQU7NVgKkkzdXDQHr1dBMtdAPozLkw= 50 | github.com/leodido/go-urn v1.2.0 h1:hpXL4XnriNwQ/ABnpepYM/1vCLWNDfUNts8dX3xTG6Y= 51 | github.com/leodido/go-urn v1.2.0/go.mod h1:+8+nEpDfqqsY+g338gtMEUOtuK+4dEMhiQEgxpxOKII= 52 | github.com/mattn/go-isatty v0.0.9/go.mod h1:YNRxwqDuOph6SZLI9vUUz6OYw3QyUt7WiY2yME+cCiQ= 53 | github.com/mattn/go-isatty v0.0.12 h1:wuysRhFDzyxgEmMf5xjvJ2M9dZoWAXNNr5LSBS7uHXY= 54 | github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= 55 | github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421 h1:ZqeYNhU3OHLH3mGKHDcjJRFFRrJa6eAM5H+CtDdOsPc= 56 | github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= 57 | github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742 h1:Esafd1046DLDQ0W1YjYsBW+p8U2u7vzgW2SQVmlNazg= 58 | github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= 59 | github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A= 60 | github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU= 61 | github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= 62 | github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk= 63 | github.com/onsi/ginkgo v1.16.1/go.mod h1:CObGmKUOKaSC0RjmoAK7tKyn4Azo5P2IWuoMnvwxz1E= 64 | github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= 65 | github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= 66 | github.com/onsi/gomega v1.11.0/go.mod h1:azGKhqFUon9Vuj0YmTfLSmx0FUwqXYSTl5re8lQLTUg= 67 | github.com/pion/datachannel v1.5.2 h1:piB93s8LGmbECrpO84DnkIVWasRMk3IimbcXkTQLE6E= 68 | github.com/pion/datachannel v1.5.2/go.mod h1:FTGQWaHrdCwIJ1rw6xBIfZVkslikjShim5yr05XFuCQ= 69 | github.com/pion/dtls/v2 v2.0.9/go.mod h1:O0Wr7si/Zj5/EBFlDzDd6UtVxx25CE1r7XM7BQKYQho= 70 | github.com/pion/dtls/v2 v2.0.10 h1:wgys7gPR1NMbWjmjJ3CW7lkUGaun8djgH8nahpNLnxI= 71 | github.com/pion/dtls/v2 v2.0.10/go.mod h1:00OxfeCRWHShcqT9jx8pKKmBWuTt0NCZoVPCaC4VKvU= 72 | github.com/pion/ice/v2 v2.1.14 h1:nD9GZs3MiR1/dPa5EiMRMe8hLBG3/qqCdx/hTS2g8VE= 73 | github.com/pion/ice/v2 v2.1.14/go.mod h1:ovgYHUmwYLlRvcCLI67PnQ5YGe+upXZbGgllBDG/ktU= 74 | github.com/pion/interceptor v0.1.2 h1:1IfrJ+AQ0HhwxNl4hqh9hMvl1hBKiNhAAr7DrUHsC6s= 75 | github.com/pion/interceptor v0.1.2/go.mod h1:Lh3JSl/cbJ2wP8I3ccrjh1K/deRGRn3UlSPuOTiHb6U= 76 | github.com/pion/logging v0.2.2 h1:M9+AIj/+pxNsDfAT64+MAVgJO0rsyLnoJKCqf//DoeY= 77 | github.com/pion/logging v0.2.2/go.mod h1:k0/tDVsRCX2Mb2ZEmTqNa7CWsQPc+YYCB7Q+5pahoms= 78 | github.com/pion/mdns v0.0.5 h1:Q2oj/JB3NqfzY9xGZ1fPzZzK7sDSD8rZPOvcIQ10BCw= 79 | github.com/pion/mdns v0.0.5/go.mod h1:UgssrvdD3mxpi8tMxAXbsppL3vJ4Jipw1mTCW+al01g= 80 | github.com/pion/randutil v0.1.0 h1:CFG1UdESneORglEsnimhUjf33Rwjubwj6xfiOXBa3mA= 81 | github.com/pion/randutil v0.1.0/go.mod h1:XcJrSMMbbMRhASFVOlj/5hQial/Y8oH/HVo7TBZq+j8= 82 | github.com/pion/rtcp v1.2.6/go.mod h1:52rMNPWFsjr39z9B9MhnkqhPLoeHTv1aN63o/42bWE0= 83 | github.com/pion/rtcp v1.2.9 h1:1ujStwg++IOLIEoOiIQ2s+qBuJ1VN81KW+9pMPsif+U= 84 | github.com/pion/rtcp v1.2.9/go.mod h1:qVPhiCzAm4D/rxb6XzKeyZiQK69yJpbUDJSF7TgrqNo= 85 | github.com/pion/rtp v1.7.0/go.mod h1:bDb5n+BFZxXx0Ea7E5qe+klMuqiBrP+w8XSjiWtCUko= 86 | github.com/pion/rtp v1.7.4 h1:4dMbjb1SuynU5OpA3kz1zHK+u+eOCQjW3MAeVHf1ODA= 87 | github.com/pion/rtp v1.7.4/go.mod h1:bDb5n+BFZxXx0Ea7E5qe+klMuqiBrP+w8XSjiWtCUko= 88 | github.com/pion/sctp v1.8.0 h1:6erMF2qmQwXr+0iB1lm0AUSmDr9LdmpaBzgSVAEgehw= 89 | github.com/pion/sctp v1.8.0/go.mod h1:xFe9cLMZ5Vj6eOzpyiKjT9SwGM4KpK/8Jbw5//jc+0s= 90 | github.com/pion/sdp/v3 v3.0.4 h1:2Kf+dgrzJflNCSw3TV5v2VLeI0s/qkzy2r5jlR0wzf8= 91 | github.com/pion/sdp/v3 v3.0.4/go.mod h1:bNiSknmJE0HYBprTHXKPQ3+JjacTv5uap92ueJZKsRk= 92 | github.com/pion/srtp/v2 v2.0.5 h1:ks3wcTvIUE/GHndO3FAvROQ9opy0uLELpwHJaQ1yqhQ= 93 | github.com/pion/srtp/v2 v2.0.5/go.mod h1:8k6AJlal740mrZ6WYxc4Dg6qDqqhxoRG2GSjlUhDF0A= 94 | github.com/pion/stun v0.3.5 h1:uLUCBCkQby4S1cf6CGuR9QrVOKcvUwFeemaC865QHDg= 95 | github.com/pion/stun v0.3.5/go.mod h1:gDMim+47EeEtfWogA37n6qXZS88L5V6LqFcf+DZA2UA= 96 | github.com/pion/transport v0.10.1/go.mod h1:PBis1stIILMiis0PewDw91WJeLJkyIMcEk+DwKOzf4A= 97 | github.com/pion/transport v0.12.2/go.mod h1:N3+vZQD9HlDP5GWkZ85LohxNsDcNgofQmyL6ojX5d8Q= 98 | github.com/pion/transport v0.12.3 h1:vdBfvfU/0Wq8kd2yhUMSDB/x+O4Z9MYVl2fJ5BT4JZw= 99 | github.com/pion/transport v0.12.3/go.mod h1:OViWW9SP2peE/HbwBvARicmAVnesphkNkCVZIWJ6q9A= 100 | github.com/pion/turn/v2 v2.0.5 h1:iwMHqDfPEDEOFzwWKT56eFmh6DYC6o/+xnLAEzgISbA= 101 | github.com/pion/turn/v2 v2.0.5/go.mod h1:APg43CFyt/14Uy7heYUOGWdkem/Wu4PhCO/bjyrTqMw= 102 | github.com/pion/udp v0.1.1 h1:8UAPvyqmsxK8oOjloDk4wUt63TzFe9WEJkg5lChlj7o= 103 | github.com/pion/udp v0.1.1/go.mod h1:6AFo+CMdKQm7UiA0eUPA8/eVCTx8jBIITLZHc9DWX5M= 104 | github.com/pion/webrtc v1.2.0 h1:3LGGPQEMacwG2hcDfhdvwQPz315gvjZXOfY4vaF4+I4= 105 | github.com/pion/webrtc/v3 v3.1.11 h1:8Q5BEsxvlDn3botM8U8n/Haln745FBa5TWgm8v2c2FA= 106 | github.com/pion/webrtc/v3 v3.1.11/go.mod h1:h9pbP+CADYb/99s5rfjflEcBLgdVKm55Rm7heQ/gIvY= 107 | github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= 108 | github.com/sclevine/agouti v3.0.0+incompatible/go.mod h1:b4WX9W9L1sfQKXeJf1mUTLZKJ48R1S7H23Ji7oFO5Bw= 109 | github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= 110 | github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= 111 | github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= 112 | github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= 113 | github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= 114 | github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= 115 | github.com/ugorji/go v1.1.7 h1:/68gy2h+1mWMrwZFeD1kQialdSzAb432dtpeJ42ovdo= 116 | github.com/ugorji/go v1.1.7/go.mod h1:kZn38zHttfInRq0xu/PH0az30d+z6vm202qpg1oXVMw= 117 | github.com/ugorji/go/codec v1.1.7 h1:2SvQaVZ1ouYrrKKwoSk2pzd4A9evlKJb9oTL+OaLUSs= 118 | github.com/ugorji/go/codec v1.1.7/go.mod h1:Ax+UKWsSmolVDwsd+7N3ZtXu+yMGCf907BLYF3GoBXY= 119 | github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= 120 | golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= 121 | golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= 122 | golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9 h1:psW17arqaxU48Z5kZ0CQnkZWQJsqcURM6tKiBApRjXI= 123 | golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= 124 | golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= 125 | golang.org/x/crypto v0.0.0-20210921155107-089bfa567519 h1:7I4JAnoQBe7ZtJcBaYHi5UtiO8tQHbUSXxL+pnGRANg= 126 | golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= 127 | golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= 128 | golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= 129 | golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= 130 | golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 131 | golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= 132 | golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= 133 | golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= 134 | golang.org/x/net v0.0.0-20201201195509-5d6afe98e0b7/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= 135 | golang.org/x/net v0.0.0-20201202161906-c7110b5ffcbb/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= 136 | golang.org/x/net v0.0.0-20210119194325-5f4716e94777/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= 137 | golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= 138 | golang.org/x/net v0.0.0-20210331212208-0fccb6fa2b5c/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= 139 | golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= 140 | golang.org/x/net v0.0.0-20211005001312-d4b1ae081e3b/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= 141 | golang.org/x/net v0.0.0-20211020060615-d418f374d309 h1:A0lJIi+hcTR6aajJH4YqKWwohY4aW9RO7oRMcdv+HKI= 142 | golang.org/x/net v0.0.0-20211020060615-d418f374d309/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= 143 | golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 144 | golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 145 | golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 146 | golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 147 | golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 148 | golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 149 | golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 150 | golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 151 | golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 152 | golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 153 | golang.org/x/sys v0.0.0-20200116001909-b77594299b42 h1:vEOn+mP2zCOVzKckCZy6YsCtDblrpj/w7B9nxGNELpg= 154 | golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 155 | golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 156 | golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 157 | golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 158 | golang.org/x/sys v0.0.0-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 159 | golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 160 | golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 161 | golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 162 | golang.org/x/sys v0.0.0-20211025201205-69cdffdb9359 h1:2B5p2L5IfGiD7+b9BOoRMC6DgObAVZV+Fsp050NqXik= 163 | golang.org/x/sys v0.0.0-20211025201205-69cdffdb9359/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 164 | golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= 165 | golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= 166 | golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= 167 | golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= 168 | golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= 169 | golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= 170 | golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= 171 | golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= 172 | golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 173 | golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 174 | golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 175 | golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE= 176 | golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 177 | google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= 178 | google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= 179 | google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= 180 | google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE= 181 | google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= 182 | google.golang.org/protobuf v1.23.0 h1:4MY060fB1DLGMB/7MBTLnwQUY6+F09GEiz6SsrNqyzM= 183 | google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= 184 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 185 | gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 186 | gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 187 | gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= 188 | gopkg.in/go-playground/assert.v1 v1.2.1/go.mod h1:9RXL0bg/zibRAgZUYszZSwO/z8Y/a8bDuhia5mkpMnE= 189 | gopkg.in/go-playground/validator.v9 v9.29.1/go.mod h1:+c9/zcJMFNgbLvly1L1V+PpxWdVbfP1avr/N00E2vyQ= 190 | gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= 191 | gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= 192 | gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= 193 | gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10= 194 | gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= 195 | gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= 196 | gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= 197 | gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= 198 | gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= 199 | -------------------------------------------------------------------------------- /webcodecs-quic/go.sum: -------------------------------------------------------------------------------- 1 | cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= 2 | cloud.google.com/go v0.31.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= 3 | cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= 4 | cloud.google.com/go v0.37.0/go.mod h1:TS1dMSSfndXH133OKGwekG838Om/cQT0BUHV3HcBgoo= 5 | dmitri.shuralyov.com/app/changes v0.0.0-20180602232624-0a106ad413e3/go.mod h1:Yl+fi1br7+Rr3LqpNJf1/uxUdtRUV+Tnj0o93V2B9MU= 6 | dmitri.shuralyov.com/html/belt v0.0.0-20180602232347-f7d459c86be0/go.mod h1:JLBrvjyP0v+ecvNYvCpyZgu5/xkfAUhi6wJj28eUfSU= 7 | dmitri.shuralyov.com/service/change v0.0.0-20181023043359-a85b471d5412/go.mod h1:a1inKt/atXimZ4Mv927x+r7UpyzRUf4emIoiiSC2TN4= 8 | dmitri.shuralyov.com/state v0.0.0-20180228185332-28bcc343414c/go.mod h1:0PRwlb0D6DFvNNtx+9ybjezNCa8XF0xaYcETyp6rHWU= 9 | git.apache.org/thrift.git v0.0.0-20180902110319-2566ecd5d999/go.mod h1:fPE2ZNJGynbRyZ4dJvy6G277gSllfV2HJqblrnkyeyg= 10 | github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= 11 | github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239/go.mod h1:2FmKhYUyUczH0OGQWaF5ceTx0UBShxjsH6f8oGKYe2c= 12 | github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= 13 | github.com/bradfitz/go-smtpd v0.0.0-20170404230938-deb6d6237625/go.mod h1:HYsPBTaaSFSlLx/70C2HPIMNZpVV8+vt/A+FMnYP11g= 14 | github.com/buger/jsonparser v0.0.0-20181115193947-bf1c66bbce23/go.mod h1:bbYlZJ7hK1yFx9hf58LP0zeX7UjIGs20ufpu3evjr+s= 15 | github.com/cheekybits/genny v1.0.0 h1:uGGa4nei+j20rOSeDeP5Of12XVm7TGUd4dJA9RDitfE= 16 | github.com/cheekybits/genny v1.0.0/go.mod h1:+tQajlRqAUrPI7DOSpB0XAqZYtQakVtB7wXkRAgjxjQ= 17 | github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= 18 | github.com/coreos/go-systemd v0.0.0-20181012123002-c6f51f82210d/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= 19 | github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 20 | github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 21 | github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= 22 | github.com/elazarl/go-bindata-assetfs v1.0.0/go.mod h1:v+YaWX3bdea5J/mo8dSETolEo7R71Vk1u8bnjau5yw4= 23 | github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568/go.mod h1:xEzjJPgXI435gkrCt3MPfRiAkVrwSbHsst4LCFVfpJc= 24 | github.com/francoispqt/gojay v1.2.13/go.mod h1:ehT5mTG4ua4581f1++1WLG0vPdaA9HaiDsoyrBGkyDY= 25 | github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= 26 | github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= 27 | github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= 28 | github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE= 29 | github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI= 30 | github.com/gin-contrib/static v0.0.0-20200916080430-d45d9a37d28e h1:8bZpGwoPxkaivQPrAbWl+7zjjUcbFUnYp7yQcx2r2N0= 31 | github.com/gin-contrib/static v0.0.0-20200916080430-d45d9a37d28e/go.mod h1:VhW/Ch/3FhimwZb8Oj+qJmdMmoB8r7lmJ5auRjm50oQ= 32 | github.com/gin-gonic/gin v1.5.0/go.mod h1:Nd6IXA8m5kNZdNEHMBd93KT+mdY3+bewLgRvmCsR2Do= 33 | github.com/gin-gonic/gin v1.6.3 h1:ahKqKTFpO5KTPHxWZjEdPScmYaGtLo8Y4DMHoEsnp14= 34 | github.com/gin-gonic/gin v1.6.3/go.mod h1:75u5sXoLsGZoRN5Sgbi1eraJ4GU3++wFwWzhwvtwp4M= 35 | github.com/gliderlabs/ssh v0.1.1/go.mod h1:U7qILu1NlMHj9FlMhZLlkCdDnU1DBEAqr0aevW3Awn0= 36 | github.com/go-errors/errors v1.0.1/go.mod h1:f4zRHt4oKfwPJE5k8C9vpYG+aDHdBFUsgrm6/TyX73Q= 37 | github.com/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4= 38 | github.com/go-playground/locales v0.12.1/go.mod h1:IUMDtCfWo/w/mtMfIE/IG2K+Ey3ygWanZIBtBW0W2TM= 39 | github.com/go-playground/locales v0.13.0 h1:HyWk6mgj5qFqCT5fjGBuRArbVDfE4hi8+e8ceBS/t7Q= 40 | github.com/go-playground/locales v0.13.0/go.mod h1:taPMhCMXrRLJO55olJkUXHZBHCxTMfnGwq/HNwmWNS8= 41 | github.com/go-playground/universal-translator v0.16.0/go.mod h1:1AnU7NaIRDWWzGEKwgtJRd2xk99HeFyHw3yid4rvQIY= 42 | github.com/go-playground/universal-translator v0.17.0 h1:icxd5fm+REJzpZx7ZfpaD876Lmtgy7VtROAbHHXk8no= 43 | github.com/go-playground/universal-translator v0.17.0/go.mod h1:UkSxE5sNxxRwHyU+Scu5vgOQjsIJAF8j9muTVoKLVtA= 44 | github.com/go-playground/validator/v10 v10.2.0 h1:KgJ0snyC2R9VXYN2rneOtQcw5aHQB1Vv0sFl1UcHBOY= 45 | github.com/go-playground/validator/v10 v10.2.0/go.mod h1:uOYAAleCW8F/7oMFd6aG0GOhaH6EGOAJShg8Id5JGkI= 46 | github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= 47 | github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= 48 | github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= 49 | github.com/golang/groupcache v0.0.0-20191027212112-611e8accdfc9/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= 50 | github.com/golang/lint v0.0.0-20180702182130-06c8688daad7/go.mod h1:tluoj9z5200jBnyusfRPU2LqT6J+DAorxEvtC7LHB+E= 51 | github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= 52 | github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= 53 | github.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= 54 | github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4= 55 | github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= 56 | github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= 57 | github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= 58 | github.com/golang/protobuf v1.3.3 h1:gyjaxf+svBWX08ZjK86iN9geUJF0H6gp2IRKX6Nf6/I= 59 | github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= 60 | github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= 61 | github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= 62 | github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= 63 | github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= 64 | github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= 65 | github.com/golang/protobuf v1.4.2 h1:+Z5KGCizgyZCbGh1KZqA0fcLLkwbsjIzS4aV2v7wJX0= 66 | github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= 67 | github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= 68 | github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= 69 | github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= 70 | github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= 71 | github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= 72 | github.com/google/go-github v17.0.0+incompatible/go.mod h1:zLgOLi98H3fifZn+44m+umXrS52loVEgC2AApnigrVQ= 73 | github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck= 74 | github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= 75 | github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= 76 | github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= 77 | github.com/googleapis/gax-go v2.0.0+incompatible/go.mod h1:SFVmujtThgffbyetf+mdk2eWhX2bMyUtNHzFKcPA9HY= 78 | github.com/googleapis/gax-go/v2 v2.0.3/go.mod h1:LLvjysVCY1JZeum8Z6l8qUty8fiNwE08qbEPm1M08qg= 79 | github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= 80 | github.com/gorilla/websocket v1.4.2 h1:+/TMaTYc4QFitKJxsQ7Yye35DkWvkdLcvGKqM+x0Ufc= 81 | github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= 82 | github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA= 83 | github.com/grpc-ecosystem/grpc-gateway v1.5.0/go.mod h1:RSKVYQBd5MCa4OVpNdGskqpgL2+G+NZTnrVHpWWfpdw= 84 | github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= 85 | github.com/jellevandenhooff/dkim v0.0.0-20150330215556-f50fe3d243e1/go.mod h1:E0B/fFc00Y+Rasa88328GlI/XbtyysCtTHZS8h7IrBU= 86 | github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= 87 | github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= 88 | github.com/json-iterator/go v1.1.9 h1:9yzud/Ht36ygwatGx56VwCZtlI/2AD15T1X2sjSuGns= 89 | github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= 90 | github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= 91 | github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= 92 | github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= 93 | github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= 94 | github.com/kr/pty v1.1.3/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= 95 | github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= 96 | github.com/leodido/go-urn v1.1.0/go.mod h1:+cyI34gQWZcE1eQU7NVgKkkzdXDQHr1dBMtdAPozLkw= 97 | github.com/leodido/go-urn v1.2.0 h1:hpXL4XnriNwQ/ABnpepYM/1vCLWNDfUNts8dX3xTG6Y= 98 | github.com/leodido/go-urn v1.2.0/go.mod h1:+8+nEpDfqqsY+g338gtMEUOtuK+4dEMhiQEgxpxOKII= 99 | github.com/lucas-clemente/quic-go v0.19.3 h1:eCDQqvGBB+kCTkA0XrAFtNe81FMa0/fn4QSoeAbmiF4= 100 | github.com/lucas-clemente/quic-go v0.19.3/go.mod h1:ADXpNbTQjq1hIzCpB+y/k5iz4n4z4IwqoLb94Kh5Hu8= 101 | github.com/lunixbochs/vtclean v1.0.0/go.mod h1:pHhQNgMf3btfWnGBVipUOjRYhoOsdGqdm/+2c2E2WMI= 102 | github.com/mailru/easyjson v0.0.0-20190312143242-1de009706dbe/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= 103 | github.com/marten-seemann/qpack v0.2.1/go.mod h1:F7Gl5L1jIgN1D11ucXefiuJS9UMVP2opoCp2jDKb7wc= 104 | github.com/marten-seemann/qtls v0.10.0 h1:ECsuYUKalRL240rRD4Ri33ISb7kAQ3qGDlrrl55b2pc= 105 | github.com/marten-seemann/qtls v0.10.0/go.mod h1:UvMd1oaYDACI99/oZUYLzMCkBXQVT0aGm99sJhbT8hs= 106 | github.com/marten-seemann/qtls-go1-15 v0.1.1 h1:LIH6K34bPVttyXnUWixk0bzH6/N07VxbSabxn5A5gZQ= 107 | github.com/marten-seemann/qtls-go1-15 v0.1.1/go.mod h1:GyFwywLKkRt+6mfU99csTEY1joMZz5vmB1WNZH3P81I= 108 | github.com/mattn/go-isatty v0.0.9/go.mod h1:YNRxwqDuOph6SZLI9vUUz6OYw3QyUt7WiY2yME+cCiQ= 109 | github.com/mattn/go-isatty v0.0.12 h1:wuysRhFDzyxgEmMf5xjvJ2M9dZoWAXNNr5LSBS7uHXY= 110 | github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= 111 | github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= 112 | github.com/microcosm-cc/bluemonday v1.0.1/go.mod h1:hsXNsILzKxV+sX77C5b8FSuKF00vh2OMYv+xgHpAMF4= 113 | github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421 h1:ZqeYNhU3OHLH3mGKHDcjJRFFRrJa6eAM5H+CtDdOsPc= 114 | github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= 115 | github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= 116 | github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= 117 | github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742 h1:Esafd1046DLDQ0W1YjYsBW+p8U2u7vzgW2SQVmlNazg= 118 | github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= 119 | github.com/modern-go/reflect2 v1.0.1 h1:9f412s+6RmYXLWZSEzVVgPGK7C2PphHj5RJrvfx9AWI= 120 | github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= 121 | github.com/neelance/astrewrite v0.0.0-20160511093645-99348263ae86/go.mod h1:kHJEU3ofeGjhHklVoIGuVj85JJwZ6kWPaJwCIxgnFmo= 122 | github.com/neelance/sourcemap v0.0.0-20151028013722-8c68805598ab/go.mod h1:Qr6/a/Q4r9LP1IltGz7tA7iOK1WonHEYhu1HRBA7ZiM= 123 | github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A= 124 | github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= 125 | github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk= 126 | github.com/onsi/ginkgo v1.14.0/go.mod h1:iSB4RoI2tjJc9BBv4NKIKWKya62Rps+oPG/Lv9klQyY= 127 | github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= 128 | github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= 129 | github.com/openzipkin/zipkin-go v0.1.1/go.mod h1:NtoC/o8u3JlF1lSlyPNswIbeQH9bJTmOf0Erfk+hxe8= 130 | github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= 131 | github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= 132 | github.com/prometheus/client_golang v0.8.0/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= 133 | github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= 134 | github.com/prometheus/common v0.0.0-20180801064454-c7de2306084e/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro= 135 | github.com/prometheus/procfs v0.0.0-20180725123919-05ee40e3a273/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= 136 | github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g= 137 | github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo= 138 | github.com/shurcooL/component v0.0.0-20170202220835-f88ec8f54cc4/go.mod h1:XhFIlyj5a1fBNx5aJTbKoIq0mNaPvOagO+HjB3EtxrY= 139 | github.com/shurcooL/events v0.0.0-20181021180414-410e4ca65f48/go.mod h1:5u70Mqkb5O5cxEA8nxTsgrgLehJeAw6Oc4Ab1c/P1HM= 140 | github.com/shurcooL/github_flavored_markdown v0.0.0-20181002035957-2122de532470/go.mod h1:2dOwnU2uBioM+SGy2aZoq1f/Sd1l9OkAeAUvjSyvgU0= 141 | github.com/shurcooL/go v0.0.0-20180423040247-9e1955d9fb6e/go.mod h1:TDJrrUr11Vxrven61rcy3hJMUqaf/CLWYhHNPmT14Lk= 142 | github.com/shurcooL/go-goon v0.0.0-20170922171312-37c2f522c041/go.mod h1:N5mDOmsrJOB+vfqUK+7DmDyjhSLIIBnXo9lvZJj3MWQ= 143 | github.com/shurcooL/gofontwoff v0.0.0-20180329035133-29b52fc0a18d/go.mod h1:05UtEgK5zq39gLST6uB0cf3NEHjETfB4Fgr3Gx5R9Vw= 144 | github.com/shurcooL/gopherjslib v0.0.0-20160914041154-feb6d3990c2c/go.mod h1:8d3azKNyqcHP1GaQE/c6dDgjkgSx2BZ4IoEi4F1reUI= 145 | github.com/shurcooL/highlight_diff v0.0.0-20170515013008-09bb4053de1b/go.mod h1:ZpfEhSmds4ytuByIcDnOLkTHGUI6KNqRNPDLHDk+mUU= 146 | github.com/shurcooL/highlight_go v0.0.0-20181028180052-98c3abbbae20/go.mod h1:UDKB5a1T23gOMUJrI+uSuH0VRDStOiUVSjBTRDVBVag= 147 | github.com/shurcooL/home v0.0.0-20181020052607-80b7ffcb30f9/go.mod h1:+rgNQw2P9ARFAs37qieuu7ohDNQ3gds9msbT2yn85sg= 148 | github.com/shurcooL/htmlg v0.0.0-20170918183704-d01228ac9e50/go.mod h1:zPn1wHpTIePGnXSHpsVPWEktKXHr6+SS6x/IKRb7cpw= 149 | github.com/shurcooL/httperror v0.0.0-20170206035902-86b7830d14cc/go.mod h1:aYMfkZ6DWSJPJ6c4Wwz3QtW22G7mf/PEgaB9k/ik5+Y= 150 | github.com/shurcooL/httpfs v0.0.0-20171119174359-809beceb2371/go.mod h1:ZY1cvUeJuFPAdZ/B6v7RHavJWZn2YPVFQ1OSXhCGOkg= 151 | github.com/shurcooL/httpgzip v0.0.0-20180522190206-b1c53ac65af9/go.mod h1:919LwcH0M7/W4fcZ0/jy0qGght1GIhqyS/EgWGH2j5Q= 152 | github.com/shurcooL/issues v0.0.0-20181008053335-6292fdc1e191/go.mod h1:e2qWDig5bLteJ4fwvDAc2NHzqFEthkqn7aOZAOpj+PQ= 153 | github.com/shurcooL/issuesapp v0.0.0-20180602232740-048589ce2241/go.mod h1:NPpHK2TI7iSaM0buivtFUc9offApnI0Alt/K8hcHy0I= 154 | github.com/shurcooL/notifications v0.0.0-20181007000457-627ab5aea122/go.mod h1:b5uSkrEVM1jQUspwbixRBhaIjIzL2xazXp6kntxYle0= 155 | github.com/shurcooL/octicon v0.0.0-20181028054416-fa4f57f9efb2/go.mod h1:eWdoE5JD4R5UVWDucdOPg1g2fqQRq78IQa9zlOV1vpQ= 156 | github.com/shurcooL/reactions v0.0.0-20181006231557-f2e0b4ca5b82/go.mod h1:TCR1lToEk4d2s07G3XGfz2QrgHXg4RJBvjrOozvoWfk= 157 | github.com/shurcooL/sanitized_anchor_name v0.0.0-20170918181015-86672fcb3f95/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= 158 | github.com/shurcooL/users v0.0.0-20180125191416-49c67e49c537/go.mod h1:QJTqeLYEDaXHZDBsXlPCDqdhQuJkuw4NOtaxYe3xii4= 159 | github.com/shurcooL/webdavfs v0.0.0-20170829043945-18c3829fa133/go.mod h1:hKmq5kWdCj2z2KEozexVbfEZIWiTjhE0+UjmZgPqehw= 160 | github.com/sourcegraph/annotate v0.0.0-20160123013949-f4cad6c6324d/go.mod h1:UdhH50NIW0fCiwBSr0co2m7BnFLdv4fQTgdqdJTHFeE= 161 | github.com/sourcegraph/syntaxhighlight v0.0.0-20170531221838-bd320f5d308e/go.mod h1:HuIsMU8RRBOtsCgI77wP899iHVBQpCmg4ErYMZB+2IA= 162 | github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= 163 | github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= 164 | github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= 165 | github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= 166 | github.com/tarm/serial v0.0.0-20180830185346-98f6abe2eb07/go.mod h1:kDXzergiv9cbyO7IOYJZWg1U88JhDg3PB6klq9Hg2pA= 167 | github.com/ugorji/go v1.1.7 h1:/68gy2h+1mWMrwZFeD1kQialdSzAb432dtpeJ42ovdo= 168 | github.com/ugorji/go v1.1.7/go.mod h1:kZn38zHttfInRq0xu/PH0az30d+z6vm202qpg1oXVMw= 169 | github.com/ugorji/go/codec v1.1.7 h1:2SvQaVZ1ouYrrKKwoSk2pzd4A9evlKJb9oTL+OaLUSs= 170 | github.com/ugorji/go/codec v1.1.7/go.mod h1:Ax+UKWsSmolVDwsd+7N3ZtXu+yMGCf907BLYF3GoBXY= 171 | github.com/viant/assertly v0.4.8/go.mod h1:aGifi++jvCrUaklKEKT0BU95igDNaqkvz+49uaYMPRU= 172 | github.com/viant/toolbox v0.24.0/go.mod h1:OxMCG57V0PXuIP2HNQrtJf2CjqdmbrOx5EkMILuUhzM= 173 | go.opencensus.io v0.18.0/go.mod h1:vKdFvxhtzZ9onBp9VKHK8z/sRpBMnKAsufL7wlDrCOA= 174 | go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= 175 | go4.org v0.0.0-20180809161055-417644f6feb5/go.mod h1:MkTOUMDaeVYJUOUsaDXIhWPZYa1yOyC1qaOBpL57BhE= 176 | golang.org/x/build v0.0.0-20190111050920-041ab4dc3f9d/go.mod h1:OWs+y06UdEOHN4y+MfF/py+xQ/tYqIWW03b70/CG9Rw= 177 | golang.org/x/crypto v0.0.0-20181030102418-4d3f4d9ffa16/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= 178 | golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= 179 | golang.org/x/crypto v0.0.0-20190313024323-a1f597ede03a/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= 180 | golang.org/x/crypto v0.0.0-20200221231518-2aa609cf4a9d/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= 181 | golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9 h1:psW17arqaxU48Z5kZ0CQnkZWQJsqcURM6tKiBApRjXI= 182 | golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= 183 | golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= 184 | golang.org/x/lint v0.0.0-20180702182130-06c8688daad7/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= 185 | golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= 186 | golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= 187 | golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= 188 | golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= 189 | golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= 190 | golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= 191 | golang.org/x/net v0.0.0-20181029044818-c44066c5c816/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= 192 | golang.org/x/net v0.0.0-20181106065722-10aee1819953/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= 193 | golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= 194 | golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= 195 | golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= 196 | golang.org/x/net v0.0.0-20190313220215-9f648a60d977/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= 197 | golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= 198 | golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 199 | golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= 200 | golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= 201 | golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= 202 | golang.org/x/oauth2 v0.0.0-20181017192945-9dcd33a902f4/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= 203 | golang.org/x/oauth2 v0.0.0-20181203162652-d668ce993890/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= 204 | golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= 205 | golang.org/x/perf v0.0.0-20180704124530-6e6d33e29852/go.mod h1:JLpeXjPJfIyPr5TlbXLkXWLhP8nz10XfvxElABhCtcw= 206 | golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 207 | golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 208 | golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 209 | golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 210 | golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 211 | golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 212 | golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 213 | golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 214 | golang.org/x/sys v0.0.0-20181029174526-d69651ed3497/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 215 | golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 216 | golang.org/x/sys v0.0.0-20190316082340-a2f829d7f35f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 217 | golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 218 | golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 219 | golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 220 | golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 221 | golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 222 | golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 223 | golang.org/x/sys v0.0.0-20200116001909-b77594299b42 h1:vEOn+mP2zCOVzKckCZy6YsCtDblrpj/w7B9nxGNELpg= 224 | golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 225 | golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 226 | golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 227 | golang.org/x/sys v0.0.0-20200519105757-fe76b779f299 h1:DYfZAGf2WMFjMxbgTjaC+2HC7NkNAQs+6Q8b9WEB/F4= 228 | golang.org/x/sys v0.0.0-20200519105757-fe76b779f299/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 229 | golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= 230 | golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= 231 | golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= 232 | golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= 233 | golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= 234 | golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= 235 | golang.org/x/tools v0.0.0-20180828015842-6cd1fcedba52/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= 236 | golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= 237 | golang.org/x/tools v0.0.0-20181030000716-a0a13e073c7b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= 238 | golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= 239 | golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= 240 | golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= 241 | golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= 242 | golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 243 | google.golang.org/api v0.0.0-20180910000450-7ca32eb868bf/go.mod h1:4mhQ8q/RsB7i+udVvVy5NUi08OU8ZlA0gRVgrF7VFY0= 244 | google.golang.org/api v0.0.0-20181030000543-1d582fd0359e/go.mod h1:4mhQ8q/RsB7i+udVvVy5NUi08OU8ZlA0gRVgrF7VFY0= 245 | google.golang.org/api v0.1.0/go.mod h1:UGEZY7KEX120AnNLIHFMKIo4obdJhkp2tPbaPlQx13Y= 246 | google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= 247 | google.golang.org/appengine v1.2.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= 248 | google.golang.org/appengine v1.3.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= 249 | google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= 250 | google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= 251 | google.golang.org/genproto v0.0.0-20180831171423-11092d34479b/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= 252 | google.golang.org/genproto v0.0.0-20181029155118-b69ba1387ce2/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= 253 | google.golang.org/genproto v0.0.0-20181202183823-bd91e49a0898/go.mod h1:7Ep/1NZk928CDR8SjdVbjWNpdIf6nzjE3BTgJDr2Atg= 254 | google.golang.org/genproto v0.0.0-20190306203927-b5d61aea6440/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= 255 | google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= 256 | google.golang.org/grpc v1.14.0/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw= 257 | google.golang.org/grpc v1.16.0/go.mod h1:0JHn/cJsOMiMfNA9+DeHDlAU7KAAB5GDlYFpa9MZMio= 258 | google.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs= 259 | google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= 260 | google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= 261 | google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= 262 | google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= 263 | google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= 264 | google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE= 265 | google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= 266 | google.golang.org/protobuf v1.23.0 h1:4MY060fB1DLGMB/7MBTLnwQUY6+F09GEiz6SsrNqyzM= 267 | google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= 268 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 269 | gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 270 | gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= 271 | gopkg.in/go-playground/assert.v1 v1.2.1/go.mod h1:9RXL0bg/zibRAgZUYszZSwO/z8Y/a8bDuhia5mkpMnE= 272 | gopkg.in/go-playground/validator.v9 v9.29.1/go.mod h1:+c9/zcJMFNgbLvly1L1V+PpxWdVbfP1avr/N00E2vyQ= 273 | gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= 274 | gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= 275 | gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= 276 | gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= 277 | gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= 278 | gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10= 279 | gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= 280 | gopkg.in/yaml.v2 v2.3.0 h1:clyUAQHOM3G0M3f5vQj7LuJrETvjVot3Z5el9nffUtU= 281 | gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= 282 | grpc.go4.org v0.0.0-20170609214715-11d0a25b4919/go.mod h1:77eQGdRu53HpSqPFJFmuJdjuHRquDANNeA4x7B8WQ9o= 283 | honnef.co/go/tools v0.0.0-20180728063816-88497007e858/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= 284 | honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= 285 | honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= 286 | rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= 287 | rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= 288 | sourcegraph.com/sourcegraph/go-diff v0.5.0/go.mod h1:kuch7UrkMzY0X+p9CRK03kfuPQ2zzQcaEFbx8wA8rck= 289 | sourcegraph.com/sqs/pbtypes v0.0.0-20180604144634-d3ebe8f20ae4/go.mod h1:ketZ/q3QxT9HOBeFhu6RdvsftgpsbFHBF5Cas6cDKZ0= 290 | --------------------------------------------------------------------------------