summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--bundle/src/Server.ts28
-rw-r--r--util/src/util/Constants.ts3
-rw-r--r--webrtc/.vscode/launch.json23
-rw-r--r--webrtc/package-lock.json573
-rw-r--r--webrtc/package.json4
-rw-r--r--webrtc/src/Server.ts36
-rw-r--r--webrtc/src/opcodes/Connect.ts5
-rw-r--r--webrtc/src/opcodes/Heartbeat.ts7
-rw-r--r--webrtc/src/opcodes/Identify.ts20
-rw-r--r--webrtc/src/opcodes/Resume.ts5
-rw-r--r--webrtc/src/opcodes/SelectProtocol.ts16
-rw-r--r--webrtc/src/opcodes/Speaking.ts6
-rw-r--r--webrtc/src/opcodes/index.ts35
-rw-r--r--webrtc/src/start.ts1
-rw-r--r--webrtc/src/util/Heartbeat.ts18
-rw-r--r--webrtc/src/util/index.ts1
-rw-r--r--webrtc/tsconfig.json19
17 files changed, 556 insertions, 244 deletions
diff --git a/bundle/src/Server.ts b/bundle/src/Server.ts
index 71a60d49..bc1d7cbc 100644
--- a/bundle/src/Server.ts
+++ b/bundle/src/Server.ts
@@ -50,20 +50,20 @@ async function main() {
 				endpointPublic: `ws://localhost:${port}`,
 			}),
 		},
-		// regions: {
-		// 	default: "fosscord",
-		// 	useDefaultAsOptimal: true,
-		// 	available: [
-		// 		{
-		// 			id: "fosscord",
-		// 			name: "Fosscord",
-		// 			endpoint: "127.0.0.1:3001",
-		// 			vip: false,
-		// 			custom: false,
-		// 			deprecated: false,
-		// 		},
-		// 	],
-		// },
+		regions: {
+			default: "fosscord",
+			useDefaultAsOptimal: true,
+			available: [
+				{
+					id: "fosscord",
+					name: "Fosscord",
+					endpoint: "127.0.0.1:3004",
+					vip: false,
+					custom: false,
+					deprecated: false,
+				},
+			],
+		},
 	} as any);
 
 	//Sentry
diff --git a/util/src/util/Constants.ts b/util/src/util/Constants.ts
index 5fdf5bc0..a1892105 100644
--- a/util/src/util/Constants.ts
+++ b/util/src/util/Constants.ts
@@ -73,7 +73,10 @@ export const VoiceOPCodes = {
 	HEARTBEAT: 3,
 	SESSION_DESCRIPTION: 4,
 	SPEAKING: 5,
+	HEARTBEAT_ACK: 6,
+	RESUME: 7,
 	HELLO: 8,
+	RESUMED: 9,
 	CLIENT_CONNECT: 12,
 	CLIENT_DISCONNECT: 13,
 };
diff --git a/webrtc/.vscode/launch.json b/webrtc/.vscode/launch.json
new file mode 100644
index 00000000..92403164
--- /dev/null
+++ b/webrtc/.vscode/launch.json
@@ -0,0 +1,23 @@
+{
+	// Use IntelliSense to learn about possible attributes.
+	// Hover to view descriptions of existing attributes.
+	// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
+	"version": "0.2.0",
+	"configurations": [
+		{
+			"name": "ts-node",
+			"type": "node",
+			"request": "launch",
+			"args": [
+				"src/start.ts"
+			],
+			"runtimeArgs": [
+				"-r",
+				"ts-node/register"
+			],
+			"cwd": "${workspaceRoot}",
+			"protocol": "inspector",
+			"internalConsoleOptions": "openOnSessionStart"
+		}
+	]
+}
\ No newline at end of file
diff --git a/webrtc/package-lock.json b/webrtc/package-lock.json
index a5db2de1..6c3726dc 100644
--- a/webrtc/package-lock.json
+++ b/webrtc/package-lock.json
@@ -9,16 +9,68 @@
 			"version": "1.0.0",
 			"license": "ISC",
 			"dependencies": {
-				"mediasoup": "^3.7.16",
+				"mediasoup": "^3.9.5",
 				"node-turn": "^0.0.6",
+				"tsconfig-paths": "^3.12.0",
 				"ws": "^7.4.6"
 			},
 			"devDependencies": {
 				"@types/node": "^15.6.1",
 				"@types/ws": "^7.4.4",
+				"ts-node": "^10.4.0",
 				"typescript": "^4.3.2"
 			}
 		},
+		"node_modules/@cspotcode/source-map-consumer": {
+			"version": "0.8.0",
+			"resolved": "https://registry.npmjs.org/@cspotcode/source-map-consumer/-/source-map-consumer-0.8.0.tgz",
+			"integrity": "sha512-41qniHzTU8yAGbCp04ohlmSrZf8bkf/iJsl3V0dRGsQN/5GFfx+LbCSsCpp2gqrqjTVg/K6O8ycoV35JIwAzAg==",
+			"dev": true,
+			"engines": {
+				"node": ">= 12"
+			}
+		},
+		"node_modules/@cspotcode/source-map-support": {
+			"version": "0.7.0",
+			"resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.7.0.tgz",
+			"integrity": "sha512-X4xqRHqN8ACt2aHVe51OxeA2HjbcL4MqFqXkrmQszJ1NOUuUu5u6Vqx/0lZSVNku7velL5FC/s5uEAj1lsBMhA==",
+			"dev": true,
+			"dependencies": {
+				"@cspotcode/source-map-consumer": "0.8.0"
+			},
+			"engines": {
+				"node": ">=12"
+			}
+		},
+		"node_modules/@tsconfig/node10": {
+			"version": "1.0.8",
+			"resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.8.tgz",
+			"integrity": "sha512-6XFfSQmMgq0CFLY1MslA/CPUfhIL919M1rMsa5lP2P097N2Wd1sSX0tx1u4olM16fLNhtHZpRhedZJphNJqmZg==",
+			"dev": true
+		},
+		"node_modules/@tsconfig/node12": {
+			"version": "1.0.9",
+			"resolved": "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.9.tgz",
+			"integrity": "sha512-/yBMcem+fbvhSREH+s14YJi18sp7J9jpuhYByADT2rypfajMZZN4WQ6zBGgBKp53NKmqI36wFYDb3yaMPurITw==",
+			"dev": true
+		},
+		"node_modules/@tsconfig/node14": {
+			"version": "1.0.1",
+			"resolved": "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.1.tgz",
+			"integrity": "sha512-509r2+yARFfHHE7T6Puu2jjkoycftovhXRqW328PDXTVGKihlb1P8Z9mMZH04ebyajfRY7dedfGynlrFHJUQCg==",
+			"dev": true
+		},
+		"node_modules/@tsconfig/node16": {
+			"version": "1.0.2",
+			"resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.2.tgz",
+			"integrity": "sha512-eZxlbI8GZscaGS7kkc/trHTT5xgrjH3/1n2JDwusC9iahPKWMRvRjJSAN5mCXviuTGQ/lHnhvv8Q1YTpnfz9gA==",
+			"dev": true
+		},
+		"node_modules/@types/json5": {
+			"version": "0.0.29",
+			"resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz",
+			"integrity": "sha1-7ihweulOEdK4J7y+UnC86n8+ce4="
+		},
 		"node_modules/@types/node": {
 			"version": "15.6.1",
 			"resolved": "https://registry.npmjs.org/@types/node/-/node-15.6.1.tgz",
@@ -34,6 +86,33 @@
 				"@types/node": "*"
 			}
 		},
+		"node_modules/acorn": {
+			"version": "8.7.0",
+			"resolved": "https://registry.npmjs.org/acorn/-/acorn-8.7.0.tgz",
+			"integrity": "sha512-V/LGr1APy+PXIwKebEWrkZPwoeoF+w1jiOBUmuxuiUIaOHtob8Qc9BTrYo7VuI5fR8tqsy+buA2WFooR5olqvQ==",
+			"dev": true,
+			"bin": {
+				"acorn": "bin/acorn"
+			},
+			"engines": {
+				"node": ">=0.4.0"
+			}
+		},
+		"node_modules/acorn-walk": {
+			"version": "8.2.0",
+			"resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.2.0.tgz",
+			"integrity": "sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA==",
+			"dev": true,
+			"engines": {
+				"node": ">=0.4.0"
+			}
+		},
+		"node_modules/arg": {
+			"version": "4.1.3",
+			"resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz",
+			"integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==",
+			"dev": true
+		},
 		"node_modules/argparse": {
 			"version": "1.0.10",
 			"resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz",
@@ -42,14 +121,6 @@
 				"sprintf-js": "~1.0.2"
 			}
 		},
-		"node_modules/awaitqueue": {
-			"version": "2.3.3",
-			"resolved": "https://registry.npmjs.org/awaitqueue/-/awaitqueue-2.3.3.tgz",
-			"integrity": "sha512-RbzQg6VtPUtyErm55iuQLTrBJ2uihy5BKBOEkyBwv67xm5Fn2o/j+Bz+a5BmfSoe2oZ5dcz9Z3fExS8pL+LLhw==",
-			"engines": {
-				"node": ">=8.0.0"
-			}
-		},
 		"node_modules/base64-js": {
 			"version": "1.5.1",
 			"resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz",
@@ -100,6 +171,12 @@
 				"buffer": "^5.1.0"
 			}
 		},
+		"node_modules/create-require": {
+			"version": "1.1.1",
+			"resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz",
+			"integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==",
+			"dev": true
+		},
 		"node_modules/date-format": {
 			"version": "3.0.0",
 			"resolved": "https://registry.npmjs.org/date-format/-/date-format-3.0.0.tgz",
@@ -108,6 +185,31 @@
 				"node": ">=4.0"
 			}
 		},
+		"node_modules/debug": {
+			"version": "4.3.3",
+			"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.3.tgz",
+			"integrity": "sha512-/zxw5+vh1Tfv+4Qn7a5nsbcJKPaSvCDhojn6FEl9vupwK2VCSDtEiEtqr8DFtzYFOdz63LBkxec7DYuc2jon6Q==",
+			"dependencies": {
+				"ms": "2.1.2"
+			},
+			"engines": {
+				"node": ">=6.0"
+			},
+			"peerDependenciesMeta": {
+				"supports-color": {
+					"optional": true
+				}
+			}
+		},
+		"node_modules/diff": {
+			"version": "4.0.2",
+			"resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz",
+			"integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==",
+			"dev": true,
+			"engines": {
+				"node": ">=0.3.1"
+			}
+		},
 		"node_modules/esprima": {
 			"version": "4.0.1",
 			"resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz",
@@ -154,35 +256,6 @@
 				"node": ">=8.0.0"
 			}
 		},
-		"node_modules/h264-profile-level-id/node_modules/debug": {
-			"version": "4.3.1",
-			"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.1.tgz",
-			"integrity": "sha512-doEwdvm4PCeK4K3RQN2ZC2BYUBaxwLARCqZmMjtF8a51J2Rb0xpVloFRnCODwqjpwnAoao4pelN8l3RJdv3gRQ==",
-			"dependencies": {
-				"ms": "2.1.2"
-			},
-			"engines": {
-				"node": ">=6.0"
-			},
-			"peerDependenciesMeta": {
-				"supports-color": {
-					"optional": true
-				}
-			}
-		},
-		"node_modules/h264-profile-level-id/node_modules/ms": {
-			"version": "2.1.2",
-			"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
-			"integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w=="
-		},
-		"node_modules/has-flag": {
-			"version": "4.0.0",
-			"resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
-			"integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
-			"engines": {
-				"node": ">=8"
-			}
-		},
 		"node_modules/ieee754": {
 			"version": "1.2.1",
 			"resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz",
@@ -214,6 +287,17 @@
 				"js-yaml": "bin/js-yaml.js"
 			}
 		},
+		"node_modules/json5": {
+			"version": "1.0.1",
+			"resolved": "https://registry.npmjs.org/json5/-/json5-1.0.1.tgz",
+			"integrity": "sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==",
+			"dependencies": {
+				"minimist": "^1.2.0"
+			},
+			"bin": {
+				"json5": "lib/cli.js"
+			}
+		},
 		"node_modules/jsonfile": {
 			"version": "4.0.0",
 			"resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz",
@@ -237,44 +321,27 @@
 				"node": ">=8.0"
 			}
 		},
-		"node_modules/log4js/node_modules/debug": {
-			"version": "4.3.1",
-			"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.1.tgz",
-			"integrity": "sha512-doEwdvm4PCeK4K3RQN2ZC2BYUBaxwLARCqZmMjtF8a51J2Rb0xpVloFRnCODwqjpwnAoao4pelN8l3RJdv3gRQ==",
-			"dependencies": {
-				"ms": "2.1.2"
-			},
-			"engines": {
-				"node": ">=6.0"
-			},
-			"peerDependenciesMeta": {
-				"supports-color": {
-					"optional": true
-				}
-			}
-		},
-		"node_modules/log4js/node_modules/ms": {
-			"version": "2.1.2",
-			"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
-			"integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w=="
+		"node_modules/make-error": {
+			"version": "1.3.6",
+			"resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz",
+			"integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==",
+			"dev": true
 		},
 		"node_modules/mediasoup": {
-			"version": "3.7.16",
-			"resolved": "https://registry.npmjs.org/mediasoup/-/mediasoup-3.7.16.tgz",
-			"integrity": "sha512-eD7VJj117zVYF8f4KYgQh2DzaYyzTvBtNa4ocT45eCjt0Y47dveKmfL5LW0LQL1LMYkBhfx/etHLjE/1AhNmwg==",
+			"version": "3.9.5",
+			"resolved": "https://registry.npmjs.org/mediasoup/-/mediasoup-3.9.5.tgz",
+			"integrity": "sha512-8lISnN5cbtSvdqHeuyxhCTFTHudoq/EpgLcDB0d0pT5RG18mZlHF5BwIBSkGxB/nWyeTfTGPpGBiNtKoubbRXA==",
 			"hasInstallScript": true,
 			"dependencies": {
-				"@types/node": "^14.14.43",
-				"awaitqueue": "^2.3.3",
-				"debug": "^4.3.1",
+				"@types/node": "^16.11.10",
+				"debug": "^4.3.3",
 				"h264-profile-level-id": "^1.0.1",
-				"netstring": "^0.3.0",
 				"random-number": "^0.0.9",
-				"supports-color": "^8.1.1",
+				"supports-color": "^9.2.1",
 				"uuid": "^8.3.2"
 			},
 			"engines": {
-				"node": ">=10"
+				"node": ">=12"
 			},
 			"funding": {
 				"type": "opencollective",
@@ -282,39 +349,20 @@
 			}
 		},
 		"node_modules/mediasoup/node_modules/@types/node": {
-			"version": "14.17.3",
-			"resolved": "https://registry.npmjs.org/@types/node/-/node-14.17.3.tgz",
-			"integrity": "sha512-e6ZowgGJmTuXa3GyaPbTGxX17tnThl2aSSizrFthQ7m9uLGZBXiGhgE55cjRZTF5kjZvYn9EOPOMljdjwbflxw=="
-		},
-		"node_modules/mediasoup/node_modules/debug": {
-			"version": "4.3.1",
-			"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.1.tgz",
-			"integrity": "sha512-doEwdvm4PCeK4K3RQN2ZC2BYUBaxwLARCqZmMjtF8a51J2Rb0xpVloFRnCODwqjpwnAoao4pelN8l3RJdv3gRQ==",
-			"dependencies": {
-				"ms": "2.1.2"
-			},
-			"engines": {
-				"node": ">=6.0"
-			},
-			"peerDependenciesMeta": {
-				"supports-color": {
-					"optional": true
-				}
-			}
+			"version": "16.11.19",
+			"resolved": "https://registry.npmjs.org/@types/node/-/node-16.11.19.tgz",
+			"integrity": "sha512-BPAcfDPoHlRQNKktbsbnpACGdypPFBuX4xQlsWDE7B8XXcfII+SpOLay3/qZmCLb39kV5S1RTYwXdkx2lwLYng=="
+		},
+		"node_modules/minimist": {
+			"version": "1.2.5",
+			"resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz",
+			"integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw=="
 		},
-		"node_modules/mediasoup/node_modules/ms": {
+		"node_modules/ms": {
 			"version": "2.1.2",
 			"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
 			"integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w=="
 		},
-		"node_modules/netstring": {
-			"version": "0.3.0",
-			"resolved": "https://registry.npmjs.org/netstring/-/netstring-0.3.0.tgz",
-			"integrity": "sha1-ho3FsgxY0/cwVTHUk2jqqr0ZtxI=",
-			"engines": {
-				"node": ">=0.6"
-			}
-		},
 		"node_modules/node-turn": {
 			"version": "0.0.6",
 			"resolved": "https://registry.npmjs.org/node-turn/-/node-turn-0.0.6.tgz",
@@ -361,39 +409,75 @@
 				"node": ">=4.0"
 			}
 		},
-		"node_modules/streamroller/node_modules/debug": {
-			"version": "4.3.1",
-			"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.1.tgz",
-			"integrity": "sha512-doEwdvm4PCeK4K3RQN2ZC2BYUBaxwLARCqZmMjtF8a51J2Rb0xpVloFRnCODwqjpwnAoao4pelN8l3RJdv3gRQ==",
+		"node_modules/strip-bom": {
+			"version": "3.0.0",
+			"resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz",
+			"integrity": "sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=",
+			"engines": {
+				"node": ">=4"
+			}
+		},
+		"node_modules/supports-color": {
+			"version": "9.2.1",
+			"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-9.2.1.tgz",
+			"integrity": "sha512-Obv7ycoCTG51N7y175StI9BlAXrmgZrFhZOb0/PyjHBher/NmsdBgbbQ1Inhq+gIhz6+7Gb+jWF2Vqi7Mf1xnQ==",
+			"engines": {
+				"node": ">=12"
+			},
+			"funding": {
+				"url": "https://github.com/chalk/supports-color?sponsor=1"
+			}
+		},
+		"node_modules/ts-node": {
+			"version": "10.4.0",
+			"resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.4.0.tgz",
+			"integrity": "sha512-g0FlPvvCXSIO1JDF6S232P5jPYqBkRL9qly81ZgAOSU7rwI0stphCgd2kLiCrU9DjQCrJMWEqcNSjQL02s6d8A==",
+			"dev": true,
 			"dependencies": {
-				"ms": "2.1.2"
+				"@cspotcode/source-map-support": "0.7.0",
+				"@tsconfig/node10": "^1.0.7",
+				"@tsconfig/node12": "^1.0.7",
+				"@tsconfig/node14": "^1.0.0",
+				"@tsconfig/node16": "^1.0.2",
+				"acorn": "^8.4.1",
+				"acorn-walk": "^8.1.1",
+				"arg": "^4.1.0",
+				"create-require": "^1.1.0",
+				"diff": "^4.0.1",
+				"make-error": "^1.1.1",
+				"yn": "3.1.1"
 			},
-			"engines": {
-				"node": ">=6.0"
+			"bin": {
+				"ts-node": "dist/bin.js",
+				"ts-node-cwd": "dist/bin-cwd.js",
+				"ts-node-script": "dist/bin-script.js",
+				"ts-node-transpile-only": "dist/bin-transpile.js",
+				"ts-script": "dist/bin-script-deprecated.js"
+			},
+			"peerDependencies": {
+				"@swc/core": ">=1.2.50",
+				"@swc/wasm": ">=1.2.50",
+				"@types/node": "*",
+				"typescript": ">=2.7"
 			},
 			"peerDependenciesMeta": {
-				"supports-color": {
+				"@swc/core": {
+					"optional": true
+				},
+				"@swc/wasm": {
 					"optional": true
 				}
 			}
 		},
-		"node_modules/streamroller/node_modules/ms": {
-			"version": "2.1.2",
-			"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
-			"integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w=="
-		},
-		"node_modules/supports-color": {
-			"version": "8.1.1",
-			"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz",
-			"integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==",
+		"node_modules/tsconfig-paths": {
+			"version": "3.12.0",
+			"resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.12.0.tgz",
+			"integrity": "sha512-e5adrnOYT6zqVnWqZu7i/BQ3BnhzvGbjEjejFXO20lKIKpwTaupkCPgEfv4GZK1IBciJUEhYs3J3p75FdaTFVg==",
 			"dependencies": {
-				"has-flag": "^4.0.0"
-			},
-			"engines": {
-				"node": ">=10"
-			},
-			"funding": {
-				"url": "https://github.com/chalk/supports-color?sponsor=1"
+				"@types/json5": "^0.0.29",
+				"json5": "^1.0.1",
+				"minimist": "^1.2.0",
+				"strip-bom": "^3.0.0"
 			}
 		},
 		"node_modules/typescript": {
@@ -444,9 +528,62 @@
 					"optional": true
 				}
 			}
+		},
+		"node_modules/yn": {
+			"version": "3.1.1",
+			"resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz",
+			"integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==",
+			"dev": true,
+			"engines": {
+				"node": ">=6"
+			}
 		}
 	},
 	"dependencies": {
+		"@cspotcode/source-map-consumer": {
+			"version": "0.8.0",
+			"resolved": "https://registry.npmjs.org/@cspotcode/source-map-consumer/-/source-map-consumer-0.8.0.tgz",
+			"integrity": "sha512-41qniHzTU8yAGbCp04ohlmSrZf8bkf/iJsl3V0dRGsQN/5GFfx+LbCSsCpp2gqrqjTVg/K6O8ycoV35JIwAzAg==",
+			"dev": true
+		},
+		"@cspotcode/source-map-support": {
+			"version": "0.7.0",
+			"resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.7.0.tgz",
+			"integrity": "sha512-X4xqRHqN8ACt2aHVe51OxeA2HjbcL4MqFqXkrmQszJ1NOUuUu5u6Vqx/0lZSVNku7velL5FC/s5uEAj1lsBMhA==",
+			"dev": true,
+			"requires": {
+				"@cspotcode/source-map-consumer": "0.8.0"
+			}
+		},
+		"@tsconfig/node10": {
+			"version": "1.0.8",
+			"resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.8.tgz",
+			"integrity": "sha512-6XFfSQmMgq0CFLY1MslA/CPUfhIL919M1rMsa5lP2P097N2Wd1sSX0tx1u4olM16fLNhtHZpRhedZJphNJqmZg==",
+			"dev": true
+		},
+		"@tsconfig/node12": {
+			"version": "1.0.9",
+			"resolved": "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.9.tgz",
+			"integrity": "sha512-/yBMcem+fbvhSREH+s14YJi18sp7J9jpuhYByADT2rypfajMZZN4WQ6zBGgBKp53NKmqI36wFYDb3yaMPurITw==",
+			"dev": true
+		},
+		"@tsconfig/node14": {
+			"version": "1.0.1",
+			"resolved": "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.1.tgz",
+			"integrity": "sha512-509r2+yARFfHHE7T6Puu2jjkoycftovhXRqW328PDXTVGKihlb1P8Z9mMZH04ebyajfRY7dedfGynlrFHJUQCg==",
+			"dev": true
+		},
+		"@tsconfig/node16": {
+			"version": "1.0.2",
+			"resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.2.tgz",
+			"integrity": "sha512-eZxlbI8GZscaGS7kkc/trHTT5xgrjH3/1n2JDwusC9iahPKWMRvRjJSAN5mCXviuTGQ/lHnhvv8Q1YTpnfz9gA==",
+			"dev": true
+		},
+		"@types/json5": {
+			"version": "0.0.29",
+			"resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz",
+			"integrity": "sha1-7ihweulOEdK4J7y+UnC86n8+ce4="
+		},
 		"@types/node": {
 			"version": "15.6.1",
 			"resolved": "https://registry.npmjs.org/@types/node/-/node-15.6.1.tgz",
@@ -462,6 +599,24 @@
 				"@types/node": "*"
 			}
 		},
+		"acorn": {
+			"version": "8.7.0",
+			"resolved": "https://registry.npmjs.org/acorn/-/acorn-8.7.0.tgz",
+			"integrity": "sha512-V/LGr1APy+PXIwKebEWrkZPwoeoF+w1jiOBUmuxuiUIaOHtob8Qc9BTrYo7VuI5fR8tqsy+buA2WFooR5olqvQ==",
+			"dev": true
+		},
+		"acorn-walk": {
+			"version": "8.2.0",
+			"resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.2.0.tgz",
+			"integrity": "sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA==",
+			"dev": true
+		},
+		"arg": {
+			"version": "4.1.3",
+			"resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz",
+			"integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==",
+			"dev": true
+		},
 		"argparse": {
 			"version": "1.0.10",
 			"resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz",
@@ -470,11 +625,6 @@
 				"sprintf-js": "~1.0.2"
 			}
 		},
-		"awaitqueue": {
-			"version": "2.3.3",
-			"resolved": "https://registry.npmjs.org/awaitqueue/-/awaitqueue-2.3.3.tgz",
-			"integrity": "sha512-RbzQg6VtPUtyErm55iuQLTrBJ2uihy5BKBOEkyBwv67xm5Fn2o/j+Bz+a5BmfSoe2oZ5dcz9Z3fExS8pL+LLhw=="
-		},
 		"base64-js": {
 			"version": "1.5.1",
 			"resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz",
@@ -497,11 +647,31 @@
 				"buffer": "^5.1.0"
 			}
 		},
+		"create-require": {
+			"version": "1.1.1",
+			"resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz",
+			"integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==",
+			"dev": true
+		},
 		"date-format": {
 			"version": "3.0.0",
 			"resolved": "https://registry.npmjs.org/date-format/-/date-format-3.0.0.tgz",
 			"integrity": "sha512-eyTcpKOcamdhWJXj56DpQMo1ylSQpcGtGKXcU0Tb97+K56/CF5amAqqqNj0+KvA0iw2ynxtHWFsPDSClCxe48w=="
 		},
+		"debug": {
+			"version": "4.3.3",
+			"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.3.tgz",
+			"integrity": "sha512-/zxw5+vh1Tfv+4Qn7a5nsbcJKPaSvCDhojn6FEl9vupwK2VCSDtEiEtqr8DFtzYFOdz63LBkxec7DYuc2jon6Q==",
+			"requires": {
+				"ms": "2.1.2"
+			}
+		},
+		"diff": {
+			"version": "4.0.2",
+			"resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz",
+			"integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==",
+			"dev": true
+		},
 		"esprima": {
 			"version": "4.0.1",
 			"resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz",
@@ -533,28 +703,8 @@
 			"integrity": "sha512-D3Rln/jKNjKDW5ZTJTK3niSoOGE+pFqPvRHHVgQN3G7umcn/zWGPUo8Q8VpDj16x3hKz++zVviRNRmXu5cpN+Q==",
 			"requires": {
 				"debug": "^4.1.1"
-			},
-			"dependencies": {
-				"debug": {
-					"version": "4.3.1",
-					"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.1.tgz",
-					"integrity": "sha512-doEwdvm4PCeK4K3RQN2ZC2BYUBaxwLARCqZmMjtF8a51J2Rb0xpVloFRnCODwqjpwnAoao4pelN8l3RJdv3gRQ==",
-					"requires": {
-						"ms": "2.1.2"
-					}
-				},
-				"ms": {
-					"version": "2.1.2",
-					"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
-					"integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w=="
-				}
 			}
 		},
-		"has-flag": {
-			"version": "4.0.0",
-			"resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
-			"integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ=="
-		},
 		"ieee754": {
 			"version": "1.2.1",
 			"resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz",
@@ -569,6 +719,14 @@
 				"esprima": "^4.0.0"
 			}
 		},
+		"json5": {
+			"version": "1.0.1",
+			"resolved": "https://registry.npmjs.org/json5/-/json5-1.0.1.tgz",
+			"integrity": "sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==",
+			"requires": {
+				"minimist": "^1.2.0"
+			}
+		},
 		"jsonfile": {
 			"version": "4.0.0",
 			"resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz",
@@ -587,62 +745,43 @@
 				"flatted": "^2.0.1",
 				"rfdc": "^1.1.4",
 				"streamroller": "^2.2.4"
-			},
-			"dependencies": {
-				"debug": {
-					"version": "4.3.1",
-					"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.1.tgz",
-					"integrity": "sha512-doEwdvm4PCeK4K3RQN2ZC2BYUBaxwLARCqZmMjtF8a51J2Rb0xpVloFRnCODwqjpwnAoao4pelN8l3RJdv3gRQ==",
-					"requires": {
-						"ms": "2.1.2"
-					}
-				},
-				"ms": {
-					"version": "2.1.2",
-					"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
-					"integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w=="
-				}
 			}
 		},
+		"make-error": {
+			"version": "1.3.6",
+			"resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz",
+			"integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==",
+			"dev": true
+		},
 		"mediasoup": {
-			"version": "3.7.16",
-			"resolved": "https://registry.npmjs.org/mediasoup/-/mediasoup-3.7.16.tgz",
-			"integrity": "sha512-eD7VJj117zVYF8f4KYgQh2DzaYyzTvBtNa4ocT45eCjt0Y47dveKmfL5LW0LQL1LMYkBhfx/etHLjE/1AhNmwg==",
+			"version": "3.9.5",
+			"resolved": "https://registry.npmjs.org/mediasoup/-/mediasoup-3.9.5.tgz",
+			"integrity": "sha512-8lISnN5cbtSvdqHeuyxhCTFTHudoq/EpgLcDB0d0pT5RG18mZlHF5BwIBSkGxB/nWyeTfTGPpGBiNtKoubbRXA==",
 			"requires": {
-				"@types/node": "^14.14.43",
-				"awaitqueue": "^2.3.3",
-				"debug": "^4.3.1",
+				"@types/node": "^16.11.10",
+				"debug": "^4.3.3",
 				"h264-profile-level-id": "^1.0.1",
-				"netstring": "^0.3.0",
 				"random-number": "^0.0.9",
-				"supports-color": "^8.1.1",
+				"supports-color": "^9.2.1",
 				"uuid": "^8.3.2"
 			},
 			"dependencies": {
 				"@types/node": {
-					"version": "14.17.3",
-					"resolved": "https://registry.npmjs.org/@types/node/-/node-14.17.3.tgz",
-					"integrity": "sha512-e6ZowgGJmTuXa3GyaPbTGxX17tnThl2aSSizrFthQ7m9uLGZBXiGhgE55cjRZTF5kjZvYn9EOPOMljdjwbflxw=="
-				},
-				"debug": {
-					"version": "4.3.1",
-					"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.1.tgz",
-					"integrity": "sha512-doEwdvm4PCeK4K3RQN2ZC2BYUBaxwLARCqZmMjtF8a51J2Rb0xpVloFRnCODwqjpwnAoao4pelN8l3RJdv3gRQ==",
-					"requires": {
-						"ms": "2.1.2"
-					}
-				},
-				"ms": {
-					"version": "2.1.2",
-					"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
-					"integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w=="
+					"version": "16.11.19",
+					"resolved": "https://registry.npmjs.org/@types/node/-/node-16.11.19.tgz",
+					"integrity": "sha512-BPAcfDPoHlRQNKktbsbnpACGdypPFBuX4xQlsWDE7B8XXcfII+SpOLay3/qZmCLb39kV5S1RTYwXdkx2lwLYng=="
 				}
 			}
 		},
-		"netstring": {
-			"version": "0.3.0",
-			"resolved": "https://registry.npmjs.org/netstring/-/netstring-0.3.0.tgz",
-			"integrity": "sha1-ho3FsgxY0/cwVTHUk2jqqr0ZtxI="
+		"minimist": {
+			"version": "1.2.5",
+			"resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz",
+			"integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw=="
+		},
+		"ms": {
+			"version": "2.1.2",
+			"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
+			"integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w=="
 		},
 		"node-turn": {
 			"version": "0.0.6",
@@ -683,28 +822,48 @@
 					"version": "2.1.0",
 					"resolved": "https://registry.npmjs.org/date-format/-/date-format-2.1.0.tgz",
 					"integrity": "sha512-bYQuGLeFxhkxNOF3rcMtiZxvCBAquGzZm6oWA1oZ0g2THUzivaRhv8uOhdr19LmoobSOLoIAxeUK2RdbM8IFTA=="
-				},
-				"debug": {
-					"version": "4.3.1",
-					"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.1.tgz",
-					"integrity": "sha512-doEwdvm4PCeK4K3RQN2ZC2BYUBaxwLARCqZmMjtF8a51J2Rb0xpVloFRnCODwqjpwnAoao4pelN8l3RJdv3gRQ==",
-					"requires": {
-						"ms": "2.1.2"
-					}
-				},
-				"ms": {
-					"version": "2.1.2",
-					"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
-					"integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w=="
 				}
 			}
 		},
+		"strip-bom": {
+			"version": "3.0.0",
+			"resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz",
+			"integrity": "sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM="
+		},
 		"supports-color": {
-			"version": "8.1.1",
-			"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz",
-			"integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==",
+			"version": "9.2.1",
+			"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-9.2.1.tgz",
+			"integrity": "sha512-Obv7ycoCTG51N7y175StI9BlAXrmgZrFhZOb0/PyjHBher/NmsdBgbbQ1Inhq+gIhz6+7Gb+jWF2Vqi7Mf1xnQ=="
+		},
+		"ts-node": {
+			"version": "10.4.0",
+			"resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.4.0.tgz",
+			"integrity": "sha512-g0FlPvvCXSIO1JDF6S232P5jPYqBkRL9qly81ZgAOSU7rwI0stphCgd2kLiCrU9DjQCrJMWEqcNSjQL02s6d8A==",
+			"dev": true,
 			"requires": {
-				"has-flag": "^4.0.0"
+				"@cspotcode/source-map-support": "0.7.0",
+				"@tsconfig/node10": "^1.0.7",
+				"@tsconfig/node12": "^1.0.7",
+				"@tsconfig/node14": "^1.0.0",
+				"@tsconfig/node16": "^1.0.2",
+				"acorn": "^8.4.1",
+				"acorn-walk": "^8.1.1",
+				"arg": "^4.1.0",
+				"create-require": "^1.1.0",
+				"diff": "^4.0.1",
+				"make-error": "^1.1.1",
+				"yn": "3.1.1"
+			}
+		},
+		"tsconfig-paths": {
+			"version": "3.12.0",
+			"resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.12.0.tgz",
+			"integrity": "sha512-e5adrnOYT6zqVnWqZu7i/BQ3BnhzvGbjEjejFXO20lKIKpwTaupkCPgEfv4GZK1IBciJUEhYs3J3p75FdaTFVg==",
+			"requires": {
+				"@types/json5": "^0.0.29",
+				"json5": "^1.0.1",
+				"minimist": "^1.2.0",
+				"strip-bom": "^3.0.0"
 			}
 		},
 		"typescript": {
@@ -728,6 +887,12 @@
 			"resolved": "https://registry.npmjs.org/ws/-/ws-7.4.6.tgz",
 			"integrity": "sha512-YmhHDO4MzaDLB+M9ym/mDA5z0naX8j7SIlT8f8z+I0VtzsRbekxEutHSme7NPS2qE8StCYQNUnfWdXta/Yu85A==",
 			"requires": {}
+		},
+		"yn": {
+			"version": "3.1.1",
+			"resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz",
+			"integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==",
+			"dev": true
 		}
 	}
 }
diff --git a/webrtc/package.json b/webrtc/package.json
index 0f700728..8c66245d 100644
--- a/webrtc/package.json
+++ b/webrtc/package.json
@@ -14,11 +14,13 @@
 	"devDependencies": {
 		"@types/node": "^15.6.1",
 		"@types/ws": "^7.4.4",
+		"ts-node": "^10.4.0",
 		"typescript": "^4.3.2"
 	},
 	"dependencies": {
-		"mediasoup": "^3.7.16",
+		"mediasoup": "^3.9.5",
 		"node-turn": "^0.0.6",
+		"tsconfig-paths": "^3.12.0",
 		"ws": "^7.4.6"
 	}
 }
diff --git a/webrtc/src/Server.ts b/webrtc/src/Server.ts
index 6591691c..06a36df9 100644
--- a/webrtc/src/Server.ts
+++ b/webrtc/src/Server.ts
@@ -1,5 +1,8 @@
 import { Server as WebSocketServer } from "ws";
-import { Config, db } from "@fosscord/util";
+import { WebSocket, CLOSECODES, Payload, OPCODES } from "@fosscord/gateway";
+import { Config, initDatabase } from "@fosscord/util";
+import OPCodeHandlers from "./opcodes";
+import { setHeartbeat } from "./util"
 import mediasoup from "mediasoup";
 
 var port = Number(process.env.PORT);
@@ -7,38 +10,29 @@ if (isNaN(port)) port = 3004;
 
 export class Server {
 	public ws: WebSocketServer;
-	public turn: any;
 
 	constructor() {
 		this.ws = new WebSocketServer({
 			port,
 			maxPayload: 4096,
 		});
-		this.ws.on("connection", (socket) => {
-			socket.on("message", (message) => {
-				socket.emit(
-					JSON.stringify({
-						op: 2,
-						d: {
-							ssrc: 1,
-							ip: "127.0.0.1",
-							port: 3004,
-							modes: [
-								"xsalsa20_poly1305",
-								"xsalsa20_poly1305_suffix",
-								"xsalsa20_poly1305_lite",
-							],
-							heartbeat_interval: 1,
-						},
-					})
-				);
+		this.ws.on("connection", async (socket: WebSocket) => {
+			await setHeartbeat(socket);
+
+			socket.on("message", async (message: string) => {
+				const payload: Payload = JSON.parse(message);
+
+				if (OPCodeHandlers[payload.op])
+					await OPCodeHandlers[payload.op](socket, payload);
+				else
+					console.error(`Unimplemented`, payload)
 			});
 		});
 	}
 
 	async listen(): Promise<void> {
 		// @ts-ignore
-		await (db as Promise<Connection>);
+		await initDatabase();
 		await Config.init();
 		console.log("[DB] connected");
 		console.log(`[WebRTC] online on 0.0.0.0:${port}`);
diff --git a/webrtc/src/opcodes/Connect.ts b/webrtc/src/opcodes/Connect.ts
new file mode 100644
index 00000000..5cc66506
--- /dev/null
+++ b/webrtc/src/opcodes/Connect.ts
@@ -0,0 +1,5 @@
+import { WebSocket } from "@fosscord/gateway";
+import { Payload } from "./index";
+
+export async function onConnect(socket: WebSocket, data: Payload) {
+}
\ No newline at end of file
diff --git a/webrtc/src/opcodes/Heartbeat.ts b/webrtc/src/opcodes/Heartbeat.ts
new file mode 100644
index 00000000..04150e36
--- /dev/null
+++ b/webrtc/src/opcodes/Heartbeat.ts
@@ -0,0 +1,7 @@
+import { WebSocket } from "@fosscord/gateway";
+import { Payload } from "./index";
+import { setHeartbeat } from "./../util";
+
+export async function onHeartbeat(socket: WebSocket, data: Payload) {
+	await setHeartbeat(socket);
+}
\ No newline at end of file
diff --git a/webrtc/src/opcodes/Identify.ts b/webrtc/src/opcodes/Identify.ts
new file mode 100644
index 00000000..2026d7c9
--- /dev/null
+++ b/webrtc/src/opcodes/Identify.ts
@@ -0,0 +1,20 @@
+import { WebSocket } from "@fosscord/gateway";
+import { Payload } from "./index"
+import { VoiceOPCodes } from "@fosscord/util";
+
+export async function onIdentify(socket: WebSocket, data: Payload) {
+	socket.send(JSON.stringify({
+		op: VoiceOPCodes.READY,
+		d: {
+			ssrc: 1,
+			ip: "127.0.0.1",
+			port: 3005,
+			modes: [
+				"xsalsa20_poly1305",
+				"xsalsa20_poly1305_suffix",
+				"xsalsa20_poly1305_lite",
+			],
+			heartbeat_interval: 1,
+		},
+	}));
+}
\ No newline at end of file
diff --git a/webrtc/src/opcodes/Resume.ts b/webrtc/src/opcodes/Resume.ts
new file mode 100644
index 00000000..de21eba6
--- /dev/null
+++ b/webrtc/src/opcodes/Resume.ts
@@ -0,0 +1,5 @@
+import { WebSocket } from "@fosscord/gateway";
+import { Payload } from "./index";
+
+export async function onResume(socket: WebSocket, data: Payload) {
+}
\ No newline at end of file
diff --git a/webrtc/src/opcodes/SelectProtocol.ts b/webrtc/src/opcodes/SelectProtocol.ts
new file mode 100644
index 00000000..f1732dd9
--- /dev/null
+++ b/webrtc/src/opcodes/SelectProtocol.ts
@@ -0,0 +1,16 @@
+import { WebSocket } from "@fosscord/gateway";
+import { Payload } from "./index";
+import { VoiceOPCodes } from "@fosscord/util";
+
+export async function onSelectProtocol(socket: WebSocket, data: Payload) {
+	socket.send(JSON.stringify({
+		op: VoiceOPCodes.SESSION_DESCRIPTION,
+		d: {
+			video_codec: "H264",
+			secret_key: new Array(32).fill(null).map(x => Math.random() * 256),
+			mode: "aead_aes256_gcm_rtpsize",
+			media_session_id: "d8eb5c84d987c6642ec4ce72ffa97f00",
+			audio_codec: "opus",
+		}
+	}));
+}
\ No newline at end of file
diff --git a/webrtc/src/opcodes/Speaking.ts b/webrtc/src/opcodes/Speaking.ts
new file mode 100644
index 00000000..14f86b3c
--- /dev/null
+++ b/webrtc/src/opcodes/Speaking.ts
@@ -0,0 +1,6 @@
+import { WebSocket } from "@fosscord/gateway";
+import { Payload } from "./index"
+import { VoiceOPCodes } from "@fosscord/util";
+
+export async function onSpeaking(socket: WebSocket, data: Payload) {
+}
\ No newline at end of file
diff --git a/webrtc/src/opcodes/index.ts b/webrtc/src/opcodes/index.ts
new file mode 100644
index 00000000..2fe69c38
--- /dev/null
+++ b/webrtc/src/opcodes/index.ts
@@ -0,0 +1,35 @@
+import { WebSocket } from "@fosscord/gateway";
+import { VoiceOPCodes } from "@fosscord/util";
+
+export interface Payload {
+	op: number;
+	d?: any;
+	s?: number;
+	t?: string;
+}
+
+import { onIdentify } from "./Identify";
+import { onSelectProtocol } from "./SelectProtocol";
+import { onHeartbeat } from "./Heartbeat";
+import { onSpeaking } from "./Speaking";
+import { onResume } from "./Resume";
+import { onConnect } from "./Connect";
+
+export type OPCodeHandler = (this: WebSocket, data: Payload) => any;
+
+export default {
+	[VoiceOPCodes.IDENTIFY]: onIdentify,				//op 0
+	[VoiceOPCodes.SELECT_PROTOCOL]: onSelectProtocol,	//op 1
+	//op 2 voice_ready
+	[VoiceOPCodes.HEARTBEAT]: onHeartbeat,				//op 3
+	//op 4 session_description
+	[VoiceOPCodes.SPEAKING]: onSpeaking,				//op 5
+	//op 6 heartbeat_ack 
+	[VoiceOPCodes.RESUME]: onResume,					//op 7
+	//op 8 hello
+	//op 9 resumed
+	//op 10?
+	//op 11?
+	[VoiceOPCodes.CLIENT_CONNECT]: onConnect,			//op 12
+	//op 13?
+};
\ No newline at end of file
diff --git a/webrtc/src/start.ts b/webrtc/src/start.ts
index 68867a2c..5614982d 100644
--- a/webrtc/src/start.ts
+++ b/webrtc/src/start.ts
@@ -1,3 +1,4 @@
 import { Server } from "./Server";
 
 const server = new Server();
+server.listen();
\ No newline at end of file
diff --git a/webrtc/src/util/Heartbeat.ts b/webrtc/src/util/Heartbeat.ts
new file mode 100644
index 00000000..7b5ed9cd
--- /dev/null
+++ b/webrtc/src/util/Heartbeat.ts
@@ -0,0 +1,18 @@
+import { WebSocket, CLOSECODES } from "@fosscord/gateway";
+import { VoiceOPCodes } from "@fosscord/util";
+
+export async function setHeartbeat(socket: WebSocket) {
+	if (socket.heartbeatTimeout) clearTimeout(socket.heartbeatTimeout);
+
+	socket.heartbeatTimeout = setTimeout(() => {
+		return socket.close(CLOSECODES.Session_timed_out);
+	}, 1000 * 45);
+
+	socket.send(JSON.stringify({
+		op: VoiceOPCodes.HEARTBEAT_ACK,
+		d: {
+			v: 6,
+			heartbeat_interval: 13750,
+		}
+	}));
+}
\ No newline at end of file
diff --git a/webrtc/src/util/index.ts b/webrtc/src/util/index.ts
new file mode 100644
index 00000000..e8557452
--- /dev/null
+++ b/webrtc/src/util/index.ts
@@ -0,0 +1 @@
+export * from "./Heartbeat"
\ No newline at end of file
diff --git a/webrtc/tsconfig.json b/webrtc/tsconfig.json
index 77353db0..fb93b0bd 100644
--- a/webrtc/tsconfig.json
+++ b/webrtc/tsconfig.json
@@ -1,5 +1,8 @@
 {
 	"include": ["src/**/*.ts"],
+	"ts-node": {
+		"require": ["tsconfig-paths/register"],
+	},
 	"compilerOptions": {
 		/* Visit https://aka.ms/tsconfig.json to read more about this file */
 
@@ -18,7 +21,7 @@
 		"sourceMap": true /* Generates corresponding '.map' file. */,
 		// "outFile": "./",                       /* Concatenate and emit output to single file. */
 		"outDir": "./dist/" /* Redirect output structure to the directory. */,
-		"rootDir": "./src/" /* Specify the root directory of input files. Use to control the output directory structure with --outDir. */,
+		"rootDir": "../" /* Specify the root directory of input files. Use to control the output directory structure with --outDir. */,
 		// "composite": true,                     /* Enable project compilation */
 		// "tsBuildInfoFile": "./",               /* Specify file to store incremental compilation information */
 		// "removeComments": true,                /* Do not emit comments to output. */
@@ -62,11 +65,19 @@
 		// "inlineSources": true,                 /* Emit the source alongside the sourcemaps within a single file; requires '--inlineSourceMap' or '--sourceMap' to be set. */
 
 		/* Experimental Options */
-		// "experimentalDecorators": true,        /* Enables experimental support for ES7 decorators. */
-		// "emitDecoratorMetadata": true,         /* Enables experimental support for emitting type metadata for decorators. */
+		"experimentalDecorators": true,        /* Enables experimental support for ES7 decorators. */
+		"emitDecoratorMetadata": true,         /* Enables experimental support for emitting type metadata for decorators. */
 
 		/* Advanced Options */
 		"skipLibCheck": true /* Skip type checking of declaration files. */,
-		"forceConsistentCasingInFileNames": true /* Disallow inconsistently-cased references to the same file. */
+		"forceConsistentCasingInFileNames": true, /* Disallow inconsistently-cased references to the same file. */
+
+		"baseUrl": "../",
+		"paths": {
+			"@fosscord/api": ["api/src/index"],
+			"@fosscord/gateway": ["gateway/src/index"],
+			"@fosscord/cdn": ["cdn/src/index"],
+			"@fosscord/util": ["util/src/index"]
+		},
 	}
 }