├── 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 |
--------------------------------------------------------------------------------