From d45b9d7caae80ad8384742118cd3587c99c52e79 Mon Sep 17 00:00:00 2001
From: Madeline <46743919+MaddyUnderStars@users.noreply.github.com>
Date: Wed, 30 Mar 2022 23:28:04 +1100
Subject: [PATCH 1/4] changes from yonks ago that I forgot to commit
---
gateway/src/opcodes/Identify.ts | 2 +
webrtc/package-lock.json | Bin 33275 -> 38390 bytes
webrtc/src/Server.ts | 33 ++++++++++++--
webrtc/src/opcodes/Identify.ts | 5 +-
webrtc/src/opcodes/SelectProtocol.ts | 66 +++++++++++++--------------
webrtc/src/start.ts | 7 +--
6 files changed, 67 insertions(+), 46 deletions(-)
diff --git a/gateway/src/opcodes/Identify.ts b/gateway/src/opcodes/Identify.ts
index eb15c28f..42b3713c 100644
--- a/gateway/src/opcodes/Identify.ts
+++ b/gateway/src/opcodes/Identify.ts
@@ -34,6 +34,8 @@ import { Recipient } from "@fosscord/util";
// TODO: check if already identified
export async function onIdentify(this: WebSocket, data: Payload) {
+ console.log(data);
+
clearTimeout(this.readyTimeout);
check.call(this, IdentifySchema, data.d);
diff --git a/webrtc/package-lock.json b/webrtc/package-lock.json
index afba7e761c8a7595e1dff36c4faee723403a8d91..d09123eea0bcc24d808ededce6a4dff0cdda282c 100644
GIT binary patch
delta 2722
zcmd6o-*4Mg6vx$WS=Wxyt!ulLb!(GuOe2ebC61j=gT{@Uq)F=hjuW(k6DN)n+p*(c
zO{8f%RmZX$@0DDT;Kb>=brPq
zzrQ>A+vk&Cd^GLhn{`tF+?jchy>NPh0NMI#6-C>#(*|#4vxdZwO{<^8W069b)3@@Qxv=H8
zRk4(++kPvh4ZsR@Yf9FA>#M%kfY);!d^r6rD4>fT1R|gyh*n|n>CDu5S$71pS
zt*w?tu_UC1{HvADYgeVm7*BBJD_YU
zOzg?{mV))*j-ML(Ih>MPg&x>c<
zoE~UN+(8np-ws|nGB|>cn&8oGFL+w@lm^}HBAi20onob7sH%{R3atWz7^$*ZD|OmJ
zrtd^RE1Ggf3P)R3kWLn)W{J>hrD2baZ55-5Vr(
zHxtl#HBj%1yx@lDR1gY-cg`*Ff@t`4y}b^@PHV$?+h!eV^kmp-_I1t>8yqY*d6Cn5
zrg}0(6LLnb)ln{l)FVU-BkI8xkD+8R7;1%(P>AHhC{G|Ek{}{D_V@z~yg^OPj*7<3
z=3TdNaIm{^d1Dt1K?sEV?#xU(k8i^ms7-y8KBIx8<3x^}CucbFVa_BdxG2wqr=4@)
zHgpTjPF$WqfFfVLNI1UZ|3+#0*jfbNlUFBE1bhcc;Ny)&@W>A`?=!~PCbk_asEDGMv%^h~1EU%WeP)ADU3A9~OD@7&VW-AS@D|Bnk1Q*=g
z>@;!>#T=H%3>iVGXeEku65>!4D|D9b@Po(uYJMlGqjpB-Kw529@9GSBX*8EgY+S
zMhpzr?!pe1R%bEr-rdzx1cZU?lDDj>n^7w-MRdbt5>_*%D?~zRZ09WtM^G)vHB!Tz
z#K8Wvz1N8N5e>7`11l73Sq6!~v8;lr8bj&Zd`#>KY&;+FGnSpV!78;fca*b-XXqRa
z_yoE&LAn9kPrz5a{{v=5h2{CfEILG|&rPidAe;T>Mc`Q(4?OREmAm<(z^sl1nD)JU
zzWs%Q?;pUjIv!ZMf*>}3{%>)T9SbL2DRwhIJ@-88TwFf {
+ // if (msg[0] === 0 && msg[1] === 1 && msg[2] === 0) { //idk stun?
+
+ // }
+ // })
}
async listen(): Promise {
@@ -59,7 +67,7 @@ export class Server {
async createWorkers(): Promise {
const numWorkers = 1;
for (let i = 0; i < numWorkers; i++) {
- const worker = await mediasoup.createWorker({ logLevel: "debug" });
+ const worker = await mediasoup.createWorker({ logLevel: "debug", logTags: ["dtls", "ice", "info", "message", "bwe"] });
if (!worker) return;
worker.on("died", () => {
@@ -76,10 +84,24 @@ export class Server {
await transport.enableTraceEvent();
- transport.on("connect", () => {
- console.log("transport connect")
+ transport.on('dtlsstatechange', (dtlsstate) => {
+ console.log(dtlsstate);
})
+ transport.on("sctpstatechange", (sctpstate) => {
+ console.log(sctpstate)
+ })
+
+ router.observer.on("newrtpobserver", (rtpObserver: MediasoupTypes.RtpObserver) => {
+ console.log("new RTP observer created [id:%s]", rtpObserver.id);
+
+ // rtpObserver.observer.on("")
+ })
+
+ transport.on("connect", () => {
+ console.log("transport connect");
+ });
+
transport.observer.on("newproducer", (producer: MediasoupTypes.Producer) => {
console.log("new producer created [id:%s]", producer.id);
@@ -114,9 +136,10 @@ export class Server {
kind: "audio",
mimeType: "audio/opus",
clockRate: 48000,
- channels: 2
+ channels: 2,
+ preferredPayloadType: 111,
},
- ]
+ ],
});
this.mediasoupWorkers.push(worker);
diff --git a/webrtc/src/opcodes/Identify.ts b/webrtc/src/opcodes/Identify.ts
index 9baa16e3..82a82dc1 100644
--- a/webrtc/src/opcodes/Identify.ts
+++ b/webrtc/src/opcodes/Identify.ts
@@ -34,11 +34,8 @@ export async function onIdentify(this: Server, socket: WebSocket, data: Identify
return socket.close(CLOSECODES.Invalid_intent);
var transport = this.mediasoupTransports[0] || await this.mediasoupRouters[0].createWebRtcTransport({
- listenIps: [{ ip: "10.22.64.69" }],
+ listenIps: [{ ip: "10.22.64.63" }],
enableUdp: true,
- enableTcp: true,
- preferUdp: true,
- enableSctp: true,
});
socket.send(JSON.stringify({
diff --git a/webrtc/src/opcodes/SelectProtocol.ts b/webrtc/src/opcodes/SelectProtocol.ts
index dc9d2b88..98899caf 100644
--- a/webrtc/src/opcodes/SelectProtocol.ts
+++ b/webrtc/src/opcodes/SelectProtocol.ts
@@ -6,7 +6,6 @@ import * as mediasoup from "mediasoup";
import { RtpCodecCapability } from "mediasoup/node/lib/RtpParameters";
import * as sdpTransform from 'sdp-transform';
-
/*
Sent by client:
@@ -68,31 +67,8 @@ import * as sdpTransform from 'sdp-transform';
"rtc_connection_id": "3faa0b80-b3e2-4bae-b291-273801fbb7ab"
}
}
-
-Sent by server:
-
-{
- "op": 4,
- "d": {
- "video_codec": "H264",
- "sdp": "
- m=audio 50001 ICE/SDP
- a=fingerprint:sha-256 4A:79:94:16:44:3F:BD:05:41:5A:C7:20:F3:12:54:70:00:73:5D:33:00:2D:2C:80:9B:39:E1:9F:2D:A7:49:87
- c=IN IP4 109.200.214.158
- a=rtcp:50001
- a=ice-ufrag:CLzn
- a=ice-pwd:qEmIcNwigd07mu46Ok0XCh
- a=fingerprint:sha-256 4A:79:94:16:44:3F:BD:05:41:5A:C7:20:F3:12:54:70:00:73:5D:33:00:2D:2C:80:9B:39:E1:9F:2D:A7:49:87
- a=candidate:1 1 UDP 4261412862 109.200.214.158 50001 typ host
- ",
- "media_session_id": "807955cb953e98c5b90704cf048e81ec",
- "audio_codec": "opus"
- }
-}
-
*/
-
export async function onSelectProtocol(this: Server, socket: WebSocket, data: Payload) {
const rtpCapabilities = this.mediasoupRouters[0].rtpCapabilities;
const codecs = rtpCapabilities.codecs as RtpCodecCapability[];
@@ -124,27 +100,49 @@ export async function onSelectProtocol(this: Server, socket: WebSocket, data: Pa
console.log("can consume: " + this.mediasoupRouters[0].canConsume({ producerId: producer.id, rtpCapabilities: rtpCapabilities }));
- const consumer = this.mediasoupConsumers[0] || await transport.consume({
- producerId: producer.id,
- paused: false,
- rtpCapabilities,
- });
+ // const consumer = this.mediasoupConsumers[0] || await transport.consume({
+ // producerId: producer.id,
+ // paused: false,
+ // rtpCapabilities,
+ // });
+
+ /*
+ {
+ "video_codec":"H264",
+ "sdp":
+ "
+ m=audio 50010 ICE/SDP
+ a=fingerprint:sha-256 4A:79:94:16:44:3F:BD:05:41:5A:C7:20:F3:12:54:70:00:73:5D:33:00:2D:2C:80:9B:39:E1:9F:2D:A7:49:87
+ c=IN IP4 109.200.214.158
+ a=rtcp:50010
+ a=ice-ufrag:+npq
+ a=ice-pwd:+jf7jAesMeHHby43FRqWTy
+ a=fingerprint:sha-256 4A:79:94:16:44:3F:BD:05:41:5A:C7:20:F3:12:54:70:00:73:5D:33:00:2D:2C:80:9B:39:E1:9F:2D:A7:49:87
+ a=candidate:1 1 UDP 4261412862 109.200.214.158 50010 typ host",
+ "media_session_id":"59265c94fa13e313492c372c4c8da801
+ ",
+ "audio_codec":"opus"
+ }
+ */
socket.send(JSON.stringify({
op: VoiceOPCodes.SESSION_DESCRIPTION,
d: {
video_codec: videoCodec?.mimeType?.substring(6) || undefined,
- mode: "xsalsa20_poly1305_lite",
+ // mode: "xsalsa20_poly1305_lite",
media_session_id: transport.id,
audio_codec: audioCodec?.mimeType.substring(6),
sdp: `m=audio ${transport.iceCandidates[0].port} ICE/SDP\n`
+ `a=fingerprint:sha-256 ${transport.dtlsParameters.fingerprints.find(x => x.algorithm === "sha-256")?.value}\n`
- + `c=IN IPV4 ${transport.iceCandidates[0].ip}\n`
- + `a=rtcp: ${transport.iceCandidates[0].port}\n`
+ + `c=IN IP4 ${transport.iceCandidates[0].ip}\n`
+ + `t=0 0\n`
+ + `a=ice-lite\n`
+ + `a=rtcp-mux\n`
+ + `a=rtcp:${transport.iceCandidates[0].port}\n`
+ `a=ice-ufrag:${transport.iceParameters.usernameFragment}\n`
+ `a=ice-pwd:${transport.iceParameters.password}\n`
- + `a=fingerprint:sha-1 ${transport.dtlsParameters.fingerprints[0].value}\n`
- + `a=candidate:1 1 ${transport.iceCandidates[0].protocol} ${transport.iceCandidates[0].priority} ${transport.iceCandidates[0].ip} ${transport.iceCandidates[0].port} typ ${transport.iceCandidates[0].type}`
+ + `a=fingerprint:sha-256 ${transport.dtlsParameters.fingerprints.find(x => x.algorithm === "sha-256")?.value}\n`
+ + `a=candidate:1 1 ${transport.iceCandidates[0].protocol.toUpperCase()} ${transport.iceCandidates[0].priority} ${transport.iceCandidates[0].ip} ${transport.iceCandidates[0].port} typ ${transport.iceCandidates[0].type}`
}
}));
}
\ No newline at end of file
diff --git a/webrtc/src/start.ts b/webrtc/src/start.ts
index 98f06ad5..f902ec1b 100644
--- a/webrtc/src/start.ts
+++ b/webrtc/src/start.ts
@@ -1,9 +1,10 @@
-//testing
-process.env.DATABASE = "../bundle/database.db";
-
import { config } from "dotenv";
config();
+//testing
+process.env.DATABASE = "../bundle/database.db";
+process.env.DEBUG = "mediasoup*"
+
import { Server } from "./Server";
const server = new Server();
From cf97e182df4d89b758c9c2bea752e59c05c8f0e0 Mon Sep 17 00:00:00 2001
From: Madeline <46743919+MaddyUnderStars@users.noreply.github.com>
Date: Tue, 5 Apr 2022 00:53:32 +1000
Subject: [PATCH 2/4] Trying my hand at implementing desktop voice, magic
packets courtesy of that one reverse engineering discord medium post
---
util/src/entities/Member.ts | 6 +-
webrtc/package-lock.json | Bin 38390 -> 35084 bytes
webrtc/package.json | 3 +
webrtc/src/Server.ts | 62 +++++++++++---
webrtc/src/opcodes/Identify.ts | 16 ++--
webrtc/src/opcodes/SelectProtocol.ts | 116 ++++++++++++++++-----------
6 files changed, 136 insertions(+), 67 deletions(-)
diff --git a/util/src/entities/Member.ts b/util/src/entities/Member.ts
index 928a25d7..a246b891 100644
--- a/util/src/entities/Member.ts
+++ b/util/src/entities/Member.ts
@@ -85,8 +85,8 @@ export class Member extends BaseClassWithoutId {
@Column()
joined_at: Date;
- @Column()
- premium_since?: Date;
+ @Column({ type: "bigint", nullable: true })
+ premium_since?: number;
@Column()
deaf: boolean;
@@ -245,7 +245,7 @@ export class Member extends BaseClassWithoutId {
nick: undefined,
roles: [guild_id], // @everyone role
joined_at: new Date(),
- premium_since: new Date(),
+ premium_since: (new Date()).getTime(),
deaf: false,
mute: false,
pending: false,
diff --git a/webrtc/package-lock.json b/webrtc/package-lock.json
index d09123eea0bcc24d808ededce6a4dff0cdda282c..e6b10d69a1aae4278b9a6a5162cccbefadfba3ec 100644
GIT binary patch
delta 1224
zcmeyinyF_J(}V+){f*h>ax#;O^HVZQb9Kv$5(^4ai;9)36qMo&^vv}vm2@WVlDCAb
zfJ+z}DCux<0)Y}-4pXty%g4YwDK(@Z#Wky0B-y$d=Ev4Lcay+;E2xi@Uq{&Da0H0N%
ALjV8(
delta 2716
zcmd6p+lw1j9LLFS*X?d?b=`K|wp(_Swzf28ZkfqUs=Z8-$vr!{O>WxiB$G@g*O|;E
zo4{JZS1H||2SM;J@I}ar;)7MF4}xG{MGE^Mh}DO_DEOexWSh27p(;ci80OqK=X-wV
z`}>@E_vXwmAI{vkwR7+2h_QXTA6zOQpG6@OEFC14g=$$BVHZ69x^T#9zjJgw=cT(H
zZaBy`3WYku@<^bg$itH4$%R`=ETQ&A-pdpka-q{vw)$~RFp^2F#ZpzH7a;=PjE7f)
zX@AONIQz21#marB5mN>txCO26+?tW=UzX@j%3ArKGs0rRgQXtA#3gx7e3E1u9zB
zCA}VOF`;%lSYQgxO#<;73dyPz6)9o{A~XX^p_tE!;B))2(YFWi8E`qWX2Y$3Ea|!=
zn2TE<7X`T?+zJO*fg@BYT_(_mQ!a*Ro$&X9iS(9I!kSflfQdcE#}YKx5Hrn8)2U=J
zhIg_;o@otXR!Y=}#HQTA$|%{?bH08lo{AQRQXSkUj*aFIeLuIz_jyTE^r~J3ym!S6
z#O@M$>|vWJ=g|NcW=2GQ&CaFE!<6XBX-Q5SFugWGNO~%s?fIgZF4YHwFXm&J=D^oC
zJmglJ2zIb8+;IAaPM+|!Yng5p>y`+iGW3?*HD)VA$#G{qUI*yO{(y4yDCV$+STR9W`N9*C(9_0BV{jH!^pC`CSWM#cH=c1!EuWBpaO~D6iIps
zZ0EXnX`CvSf3I5ULO5OqceKN_<0^_nh*e!&FdxTdZ6H_Gv5&@MDYFxqbUr%HaUW*R
zgMtr~bwF!pR;|rxJ-(yXy1n+K-<%s<(~d8Z=Fo@JSSAJ6Uqxq71iX*6z?W+);JdSn
zfU!NlkAP6Z3L98+FFgC$c46@K0oOC8a>`tiCaiorJik}P##UGGMk|sg(K;vRvz<`A
zkgxDfv018ydAHx+sH7?#eaKM>%8UBwJdHKN(omA}Op<8|8A1-KLo)0QN2LMf>%~aT
zm)`6ZNh{NyRPyUZc$S1PKwm^b>C*aM*tv078hi$AyfAU?
zgX1%g1Sr^<2L@YnuiF0(9J#5$5$wLc27b0#@UzsNb67sw2B)%LJROg@so;?w{lLBS
zR5li;!p8oE3y#t6dB?wEV{s~M97}rfO8VeG;$m?+T(rXTX5+biqxWS0-11*w4eZVz
zzV=@ragS+^TCY2X)#FPRriEc}U)}isad-uMyuD)n-hjK>@d;9I>VZiS#B}=`Q=uzu
zx?z0lY=gJ8RdD0l+_HHCS=XM_?N~4|Aqyclbp#YIZR}C@t&>-#LRl+GtQ!#QzH{V+
SDdI`s?kQc^9^KYM%YOp3$7wkL
diff --git a/webrtc/package.json b/webrtc/package.json
index b9bac356..82651b7c 100644
--- a/webrtc/package.json
+++ b/webrtc/package.json
@@ -19,7 +19,10 @@
"typescript": "^4.3.2"
},
"dependencies": {
+ "@types/libsodium-wrappers": "^0.7.9",
"dotenv": "^12.0.4",
+ "libsodium": "^0.7.10",
+ "libsodium-wrappers": "^0.7.10",
"mediasoup": "^3.9.5",
"node-turn": "^0.0.6",
"sdp-transform": "^2.14.1",
diff --git a/webrtc/src/Server.ts b/webrtc/src/Server.ts
index 5b76759a..67f60f9f 100644
--- a/webrtc/src/Server.ts
+++ b/webrtc/src/Server.ts
@@ -5,8 +5,8 @@ import OPCodeHandlers, { Payload } from "./opcodes";
import { setHeartbeat } from "./util";
import * as mediasoup from "mediasoup";
import { types as MediasoupTypes } from "mediasoup";
-
import udp from "dgram";
+import sodium from "libsodium-wrappers";
var port = Number(process.env.PORT);
if (isNaN(port)) port = 3004;
@@ -47,19 +47,59 @@ export class Server {
});
});
- // this.testUdp.bind(50001);
- // this.testUdp.on("message", (msg, rinfo) => {
- // if (msg[0] === 0 && msg[1] === 1 && msg[2] === 0) { //idk stun?
+ this.testUdp.bind(50001);
+ this.testUdp.on("message", (msg, rinfo) => {
+ //random key from like, the libsodium examples on npm lol
+ const decryptKey = sodium.from_hex("724b092810ec86d7e35c9d067702b31ef90bc43a7b598626749914d6a3e033ed");
- // }
- // })
+ //give me my remote port?
+ if (sodium.to_hex(msg) == "0001004600000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000") {
+ this.testUdp.send(Buffer.from([rinfo.port, 0]), rinfo.port, rinfo.address);
+ console.log(`got magic packet to send remote port? ${rinfo.address}:${rinfo.port}`);
+ return;
+ }
+
+ //Hello
+ if (sodium.to_hex(msg) == "0100000000000000") {
+ console.log(`[UDP] client helloed`);
+ return;
+ }
+
+ const nonce = Buffer.concat([msg.slice(-4), Buffer.from("\x00".repeat(20))]);
+ console.log(`[UDP] nonce for this message: ${nonce}`);
+
+ console.log(sodium.to_hex(msg));
+ if (sodium.to_hex(msg).indexOf("80c8000600000001") == 0) {
+ //call status
+ const encrypted = msg.slice(8, -4);
+ const currentPacket = msg.slice(-4);
+ console.log(`[UDP] Current packet: ${currentPacket}`);
+ try {
+ console.log(`[UDP] Encrypted bytes: ${encrypted.toString("base64")}`);
+ const decrypted = sodium.crypto_secretbox_open_easy(encrypted, nonce, decryptKey);
+ console.log("[UDP] [ call status ]" + decrypted);
+ }
+ catch (e) {
+ console.error(`[UDP] decrypt failure\n${e}\n${encrypted.toString("base64")}`);
+ }
+ return;
+ }
+
+ try {
+ const decrypted = sodium.crypto_secretbox_open_easy(msg, nonce, decryptKey);
+ console.log("[UDP] " + decrypted);
+ }
+ catch (e) {
+ console.error(`[UDP] decrypt failure\n${e}\n${msg.toString("base64")}`);
+ }
+ });
}
async listen(): Promise {
// @ts-ignore
await initDatabase();
await Config.init();
- await this.createWorkers();
+ //await this.createWorkers();
console.log("[DB] connected");
console.log(`[WebRTC] online on 0.0.0.0:${port}`);
}
@@ -86,17 +126,17 @@ export class Server {
transport.on('dtlsstatechange', (dtlsstate) => {
console.log(dtlsstate);
- })
+ });
transport.on("sctpstatechange", (sctpstate) => {
- console.log(sctpstate)
- })
+ console.log(sctpstate);
+ });
router.observer.on("newrtpobserver", (rtpObserver: MediasoupTypes.RtpObserver) => {
console.log("new RTP observer created [id:%s]", rtpObserver.id);
// rtpObserver.observer.on("")
- })
+ });
transport.on("connect", () => {
console.log("transport connect");
diff --git a/webrtc/src/opcodes/Identify.ts b/webrtc/src/opcodes/Identify.ts
index 82a82dc1..68452d4f 100644
--- a/webrtc/src/opcodes/Identify.ts
+++ b/webrtc/src/opcodes/Identify.ts
@@ -33,18 +33,18 @@ export async function onIdentify(this: Server, socket: WebSocket, data: Identify
if (!guild.members.find(x => x.id === user.id))
return socket.close(CLOSECODES.Invalid_intent);
- var transport = this.mediasoupTransports[0] || await this.mediasoupRouters[0].createWebRtcTransport({
- listenIps: [{ ip: "10.22.64.63" }],
- enableUdp: true,
- });
-
+ // var transport = this.mediasoupTransports[0] || await this.mediasoupRouters[0].createWebRtcTransport({
+ // listenIps: [{ ip: "10.22.64.56" }],
+ // enableUdp: true,
+ // });
+7
socket.send(JSON.stringify({
op: VoiceOPCodes.READY,
d: {
- streams: [...data.d.streams.map(x => ({ ...x, rtx_ssrc: Math.floor(Math.random() * 10000), ssrc: Math.floor(Math.random() * 10000), active: false, }))],
+ streams: data.d.streams ? [...data.d.streams.map(x => ({ ...x, rtx_ssrc: Math.floor(Math.random() * 10000), ssrc: Math.floor(Math.random() * 10000), active: false, }))] : undefined,
ssrc: Math.floor(Math.random() * 10000),
- ip: transport.iceCandidates[0].ip,
- port: transport.iceCandidates[0].port,
+ ip: "127.0.0.1",//transport.iceCandidates[0].ip,
+ port: 50001,//transport.iceCandidates[0].port,
modes: [
"aead_aes256_gcm_rtpsize",
"aead_aes256_gcm",
diff --git a/webrtc/src/opcodes/SelectProtocol.ts b/webrtc/src/opcodes/SelectProtocol.ts
index 98899caf..29b9c1f9 100644
--- a/webrtc/src/opcodes/SelectProtocol.ts
+++ b/webrtc/src/opcodes/SelectProtocol.ts
@@ -5,6 +5,7 @@ import { Server } from "../Server";
import * as mediasoup from "mediasoup";
import { RtpCodecCapability } from "mediasoup/node/lib/RtpParameters";
import * as sdpTransform from 'sdp-transform';
+import sodium from "libsodium-wrappers";
/*
@@ -70,42 +71,66 @@ import * as sdpTransform from 'sdp-transform';
*/
export async function onSelectProtocol(this: Server, socket: WebSocket, data: Payload) {
- const rtpCapabilities = this.mediasoupRouters[0].rtpCapabilities;
- const codecs = rtpCapabilities.codecs as RtpCodecCapability[];
+ // const rtpCapabilities = this.mediasoupRouters[0].rtpCapabilities;
+ // const codecs = rtpCapabilities.codecs as RtpCodecCapability[];
- const transport = this.mediasoupTransports[0]; //whatever
+ if (data.d.sdp) {
+ // const transport = this.mediasoupTransports[0]; //whatever
- const res = sdpTransform.parse(data.d.sdp);
+ // const res = sdpTransform.parse(data.d.sdp);
- const videoCodec = this.mediasoupRouters[0].rtpCapabilities.codecs!.find((x: any) => x.kind === "video");
- const audioCodec = this.mediasoupRouters[0].rtpCapabilities.codecs!.find((x: any) => x.kind === "audio");
+ // const videoCodec = this.mediasoupRouters[0].rtpCapabilities.codecs!.find((x: any) => x.kind === "video");
+ // const audioCodec = this.mediasoupRouters[0].rtpCapabilities.codecs!.find((x: any) => x.kind === "audio");
- const producer = this.mediasoupProducers[0] || await transport.produce({
- kind: "audio",
- rtpParameters: {
- mid: "audio",
- codecs: [{
- clockRate: audioCodec!.clockRate,
- payloadType: audioCodec!.preferredPayloadType as number,
- mimeType: audioCodec!.mimeType,
- channels: audioCodec?.channels,
- }],
- headerExtensions: res.ext?.map(x => ({
- id: x.value,
- uri: x.uri,
- })),
- },
- paused: false,
- });
+ // const producer = this.mediasoupProducers[0] || await transport.produce({
+ // kind: "audio",
+ // rtpParameters: {
+ // mid: "audio",
+ // codecs: [{
+ // clockRate: audioCodec!.clockRate,
+ // payloadType: audioCodec!.preferredPayloadType as number,
+ // mimeType: audioCodec!.mimeType,
+ // channels: audioCodec?.channels,
+ // }],
+ // headerExtensions: res.ext?.map(x => ({
+ // id: x.value,
+ // uri: x.uri,
+ // })),
+ // },
+ // paused: false,
+ // });
- console.log("can consume: " + this.mediasoupRouters[0].canConsume({ producerId: producer.id, rtpCapabilities: rtpCapabilities }));
+ // console.log("can consume: " + this.mediasoupRouters[0].canConsume({ producerId: producer.id, rtpCapabilities: rtpCapabilities }));
- // const consumer = this.mediasoupConsumers[0] || await transport.consume({
- // producerId: producer.id,
- // paused: false,
- // rtpCapabilities,
- // });
+ // // const consumer = this.mediasoupConsumers[0] || await transport.consume({
+ // // producerId: producer.id,
+ // // paused: false,
+ // // rtpCapabilities,
+ // // });
+ // socket.send(JSON.stringify({
+ // op: VoiceOPCodes.SESSION_DESCRIPTION,
+ // d: {
+ // video_codec: videoCodec?.mimeType?.substring(6) || undefined,
+ // // mode: "xsalsa20_poly1305_lite",
+ // media_session_id: transport.id,
+ // audio_codec: audioCodec?.mimeType.substring(6),
+ // secret_key: sodium.from_hex("724b092810ec86d7e35c9d067702b31ef90bc43a7b598626749914d6a3e033ed").buffer,
+ // sdp: `m=audio ${50001} ICE/SDP\n`
+ // + `a=fingerprint:sha-256 ${transport.dtlsParameters.fingerprints.find(x => x.algorithm === "sha-256")?.value}\n`
+ // + `c=IN IP4 ${transport.iceCandidates[0].ip}\n`
+ // + `t=0 0\n`
+ // + `a=ice-lite\n`
+ // + `a=rtcp-mux\n`
+ // + `a=rtcp:${50001}\n`
+ // + `a=ice-ufrag:${transport.iceParameters.usernameFragment}\n`
+ // + `a=ice-pwd:${transport.iceParameters.password}\n`
+ // + `a=fingerprint:sha-256 ${transport.dtlsParameters.fingerprints.find(x => x.algorithm === "sha-256")?.value}\n`
+ // + `a=candidate:1 1 ${transport.iceCandidates[0].protocol.toUpperCase()} ${transport.iceCandidates[0].priority} ${transport.iceCandidates[0].ip} ${50001} typ ${transport.iceCandidates[0].type}`
+ // }
+ // }));
+ return;
+ }
/*
{
"video_codec":"H264",
@@ -125,24 +150,25 @@ export async function onSelectProtocol(this: Server, socket: WebSocket, data: Pa
}
*/
+
+ /*
+ {
+ "video_codec": "H264",
+ "secret_key": [36, 80, 96, 53, 95, 149, 253, 16, 137, 186, 238, 222, 251, 180, 94, 150, 112, 137, 192, 109, 69, 79, 218, 111, 217, 197, 56, 74, 18, 41, 51, 140],
+ "mode": "aead_aes256_gcm_rtpsize",
+ "media_session_id": "797575a97a87b63e81e2399348b97ad1",
+ "audio_codec": "opus"
+ };
+ */
+
socket.send(JSON.stringify({
- op: VoiceOPCodes.SESSION_DESCRIPTION,
+ op:VoiceOPCodes.SESSION_DESCRIPTION,
d: {
- video_codec: videoCodec?.mimeType?.substring(6) || undefined,
- // mode: "xsalsa20_poly1305_lite",
- media_session_id: transport.id,
- audio_codec: audioCodec?.mimeType.substring(6),
- sdp: `m=audio ${transport.iceCandidates[0].port} ICE/SDP\n`
- + `a=fingerprint:sha-256 ${transport.dtlsParameters.fingerprints.find(x => x.algorithm === "sha-256")?.value}\n`
- + `c=IN IP4 ${transport.iceCandidates[0].ip}\n`
- + `t=0 0\n`
- + `a=ice-lite\n`
- + `a=rtcp-mux\n`
- + `a=rtcp:${transport.iceCandidates[0].port}\n`
- + `a=ice-ufrag:${transport.iceParameters.usernameFragment}\n`
- + `a=ice-pwd:${transport.iceParameters.password}\n`
- + `a=fingerprint:sha-256 ${transport.dtlsParameters.fingerprints.find(x => x.algorithm === "sha-256")?.value}\n`
- + `a=candidate:1 1 ${transport.iceCandidates[0].protocol.toUpperCase()} ${transport.iceCandidates[0].priority} ${transport.iceCandidates[0].ip} ${transport.iceCandidates[0].port} typ ${transport.iceCandidates[0].type}`
+ video_codec: "H264",
+ secret_key: [...sodium.from_hex("724b092810ec86d7e35c9d067702b31ef90bc43a7b598626749914d6a3e033ed")],
+ mode: "aead_aes256_gcm_rtpsize",
+ media_session_id: "blah blah blah",
+ audio_codec: "opus",
}
}));
}
\ No newline at end of file
From e2e4c5715ed89ef945f6b1adfb5b8b79ae158ef5 Mon Sep 17 00:00:00 2001
From: Madeline <46743919+MaddyUnderStars@users.noreply.github.com>
Date: Fri, 22 Apr 2022 15:02:40 +1000
Subject: [PATCH 3/4] Added README, added more UDP decryption stuff
---
README.md | 38 ++++++++++++++++++----------
webrtc/src/Server.ts | 28 +++++++++++++-------
webrtc/src/opcodes/SelectProtocol.ts | 5 +++-
3 files changed, 48 insertions(+), 23 deletions(-)
diff --git a/README.md b/README.md
index f2743ed1..fe03e88e 100644
--- a/README.md
+++ b/README.md
@@ -14,22 +14,34 @@
-## [About](https://fosscord.com)
+# Install
+Setup fosscord-server as normal ( existing installations are fine, if you run voice on the same server on port `3004` you don't need to edit the `regions_available_0_endpoint` record of `config` )
-This repository contains:
+Note: currently everything about webrtc is commented out ( because I was lazy )
+If you want to test that, you're gonna have to do some fiddling, shouldn't be toooo difficult ( check `SelectProtocols.ts`, `Identify.ts` and theres probably smth in `Server.ts` I forgot about ). Also also make sure you set the `listenIps` in `Identify.ts` properly because otherwise the transport won't start
-- [Fosscord HTTP API Server](/api)
-- [WebSocket Gateway Server](/gateway)
-- [HTTP CDN Server](/cdn)
-- [Utility and Database Models](/util)
-- [RTC Server](/rtc)
-- [WebRTC Server](/webrtc)
-- [Admin Dashboard](/dashboard)
+```sh
+cd webrtc
+ts-node src/start.ts # don't think the build script works lol
+```
-## [Resources](https://docs.fosscord.com/resources/)
+# Current problems / setup / etc:
+* Webrtc DTLS fails to properly connect with browser voice. The handshake completes and is labeled completed by chrome://webrtc-internals, however mediasoup drops all RTP packets as the 'handshake is not completed' yet.
-- [Contributing](https://docs.fosscord.com/contributing/server/)
+* After the desktop client updates it's VoiceState to join a voice channel, upon leaving the VoiceState will not update to match, and the client is prevented from joining any new voice channels. The client also continuously plays the voice disconnected notification sound. [Video demo](https://who-the-fuck-pinged.me/6dlya82Z)
+* Desktop client cannot properly connect to voice/media servers due to the above, but also because somewhere in my signalling there is a problem. I haven't looked much into it.
+* When the client does magically decide to try to connect, it connects to signalling but then [throws an error client-side about `this.conn.setSelfMute` not being a function](https://media.discordapp.net/attachments/903790443052036117/951099310370615306/unknown.png)
-## [Setup](https://docs.fosscord.com/server/setup/)
+* I have instead been testing voice using [a fork](https://github.com/tenable/DiscordClient) of the reverse engineered client from [this article](https://medium.com/tenable-techblog/lets-reverse-engineer-discord-1976773f4626), with some slight modifications ( I think it was just changing the email field the client uses to login from `email` -> `login`. Todo: these could be aliases in `fosscord-server`? )
+* This client can join a channel, connect to signalling, and does send packets to the UDP server. However, I can't seem to get decrpytion to work. As far as I know, I'm using the same key I'm sending. It turns out the client converts the `secret_key: Number[]` received into a string, but doing the same on the server-side before passing to the decrpyt method still just complains about a key mismatch.
-- [Download](https://github.com/fosscord/fosscord-server/releases)
+# Resources:
+* [Mediasoup docs](https://mediasoup.org/documentation/v3/), or more specifically the [API docs](https://mediasoup.org/documentation/v3/mediasoup/api/)
+* * [Mediasoup SFU video demo](https://github.com/Dirvann/mediasoup-sfu-webrtc-video-rooms)
+* [The fork of the reverse engineered voice client](https://github.com/edisionnano/DiscordClient)
+* * [discord_voice.node stubs for logging client actions](https://github.com/edisionnano/discord_voice-stub/blob/main/discord_voice.js)
+* [Discord.com docs: connecting to voice](https://discord.com/developers/docs/topics/voice-connections#connecting-to-voice)
+* [Anatomy of a WebRTC SDP](https://webrtchacks.com/sdp-anatomy/)
+* [WebRTC Glossary](https://webrtcglossary.com/)
+* * [What is an SFU/MCU](https://webrtcglossary.com/sfu/)
+* * [How SDP, how to send DTLS fingerprints](https://blog.actorsfit.com/a?ID=00001-8ebd39ca-2d57-41bc-9743-635373e77167)
\ No newline at end of file
diff --git a/webrtc/src/Server.ts b/webrtc/src/Server.ts
index 67f60f9f..a43768ac 100644
--- a/webrtc/src/Server.ts
+++ b/webrtc/src/Server.ts
@@ -19,6 +19,7 @@ export class Server {
public mediasoupProducers: MediasoupTypes.Producer[] = [];
public mediasoupConsumers: MediasoupTypes.Consumer[] = [];
+ public decryptKey: number[] = [];
public testUdp = udp.createSocket("udp6");
constructor() {
@@ -50,7 +51,6 @@ export class Server {
this.testUdp.bind(50001);
this.testUdp.on("message", (msg, rinfo) => {
//random key from like, the libsodium examples on npm lol
- const decryptKey = sodium.from_hex("724b092810ec86d7e35c9d067702b31ef90bc43a7b598626749914d6a3e033ed");
//give me my remote port?
if (sodium.to_hex(msg) == "0001004600000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000") {
@@ -66,17 +66,27 @@ export class Server {
}
const nonce = Buffer.concat([msg.slice(-4), Buffer.from("\x00".repeat(20))]);
- console.log(`[UDP] nonce for this message: ${nonce}`);
+ console.log(`[UDP] nonce for this message: ${nonce.toString("hex")}`);
+
+ console.log(`[UDP] message: ${sodium.to_hex(msg)}`);
+
+ let encrypted;
+ if (msg.slice(0, 2).indexOf("\x81\xc9") == 0) {
+ encrypted = msg.slice(0x18, -4);
+ }
+ else if (msg.slice(0, 2).indexOf("\x90\x78") == 0) {
+ encrypted = msg.slice(0x1C, -4);
+ }
+ else {
+ encrypted = msg.slice(0x18, -4);
+ console.log(`wtf header received: ${encrypted.toString("hex")}`);
+ }
- console.log(sodium.to_hex(msg));
if (sodium.to_hex(msg).indexOf("80c8000600000001") == 0) {
//call status
- const encrypted = msg.slice(8, -4);
- const currentPacket = msg.slice(-4);
- console.log(`[UDP] Current packet: ${currentPacket}`);
+
try {
- console.log(`[UDP] Encrypted bytes: ${encrypted.toString("base64")}`);
- const decrypted = sodium.crypto_secretbox_open_easy(encrypted, nonce, decryptKey);
+ const decrypted = sodium.crypto_secretbox_open_easy(encrypted, nonce, Uint8Array.from(this.decryptKey));
console.log("[UDP] [ call status ]" + decrypted);
}
catch (e) {
@@ -86,7 +96,7 @@ export class Server {
}
try {
- const decrypted = sodium.crypto_secretbox_open_easy(msg, nonce, decryptKey);
+ const decrypted = sodium.crypto_secretbox_open_easy(encrypted, nonce, Uint8Array.from(this.decryptKey));
console.log("[UDP] " + decrypted);
}
catch (e) {
diff --git a/webrtc/src/opcodes/SelectProtocol.ts b/webrtc/src/opcodes/SelectProtocol.ts
index 29b9c1f9..75ab4495 100644
--- a/webrtc/src/opcodes/SelectProtocol.ts
+++ b/webrtc/src/opcodes/SelectProtocol.ts
@@ -161,11 +161,14 @@ export async function onSelectProtocol(this: Server, socket: WebSocket, data: Pa
};
*/
+ this.decryptKey = [...sodium.randombytes_buf(sodium.crypto_secretbox_KEYBYTES)];
+ console.log(this.decryptKey.map(x => String.fromCharCode(x)).join(""));
+
socket.send(JSON.stringify({
op:VoiceOPCodes.SESSION_DESCRIPTION,
d: {
video_codec: "H264",
- secret_key: [...sodium.from_hex("724b092810ec86d7e35c9d067702b31ef90bc43a7b598626749914d6a3e033ed")],
+ secret_key: this.decryptKey,
mode: "aead_aes256_gcm_rtpsize",
media_session_id: "blah blah blah",
audio_codec: "opus",
From 77b31d79a38447a4a68e5afa8c28345b38d73fef Mon Sep 17 00:00:00 2001
From: Madeline <46743919+MaddyUnderStars@users.noreply.github.com>
Date: Sun, 5 Jun 2022 22:02:21 +1000
Subject: [PATCH 4/4] More random bullshit
---
webrtc/src/Server.ts | 61 +++++---
webrtc/src/opcodes/Identify.ts | 16 +-
webrtc/src/opcodes/SelectProtocol.ts | 211 +++++++++++++++------------
3 files changed, 167 insertions(+), 121 deletions(-)
diff --git a/webrtc/src/Server.ts b/webrtc/src/Server.ts
index a43768ac..7a1070b9 100644
--- a/webrtc/src/Server.ts
+++ b/webrtc/src/Server.ts
@@ -7,6 +7,7 @@ import * as mediasoup from "mediasoup";
import { types as MediasoupTypes } from "mediasoup";
import udp from "dgram";
import sodium from "libsodium-wrappers";
+import { assert } from "console";
var port = Number(process.env.PORT);
if (isNaN(port)) port = 3004;
@@ -19,7 +20,7 @@ export class Server {
public mediasoupProducers: MediasoupTypes.Producer[] = [];
public mediasoupConsumers: MediasoupTypes.Consumer[] = [];
- public decryptKey: number[] = [];
+ public decryptKey: Uint8Array;
public testUdp = udp.createSocket("udp6");
constructor() {
@@ -46,9 +47,20 @@ export class Server {
socket.close(CLOSECODES.Unknown_opcode);
}
});
+
+ socket.on("close", (code: number, reason: string) => {
+ console.log(`client closed ${code} ${reason}`);
+ for (var consumer of this.mediasoupConsumers) consumer.close();
+ for (var producer of this.mediasoupProducers) producer.close();
+ for (var transport of this.mediasoupTransports) transport.close();
+
+ this.mediasoupConsumers = [];
+ this.mediasoupProducers = [];
+ this.mediasoupTransports = [];
+ })
});
- this.testUdp.bind(50001);
+ this.testUdp.bind(60000);
this.testUdp.on("message", (msg, rinfo) => {
//random key from like, the libsodium examples on npm lol
@@ -70,23 +82,28 @@ export class Server {
console.log(`[UDP] message: ${sodium.to_hex(msg)}`);
- let encrypted;
- if (msg.slice(0, 2).indexOf("\x81\xc9") == 0) {
- encrypted = msg.slice(0x18, -4);
- }
- else if (msg.slice(0, 2).indexOf("\x90\x78") == 0) {
- encrypted = msg.slice(0x1C, -4);
- }
- else {
- encrypted = msg.slice(0x18, -4);
- console.log(`wtf header received: ${encrypted.toString("hex")}`);
- }
+ // let encrypted;
+ // if (Buffer.from(msg).indexOf("\x81\xc9") == 0) {
+ // encrypted = msg.slice(0x18, -4);
+ // }
+ // else if (Buffer.from(msg).indexOf("\x90\x78") == 0) {
+ // encrypted = msg.slice(0x1C, -4);
+ // }
+ // else {
+ // encrypted = msg.slice(0x18, -4);
+ // console.log(`wtf header received: ${encrypted.toString("hex")}`);
+ // }
+
+ let encrypted = msg;
if (sodium.to_hex(msg).indexOf("80c8000600000001") == 0) {
//call status
+ encrypted = encrypted.slice(8, -4);
+ assert(encrypted.length == 40);
+
try {
- const decrypted = sodium.crypto_secretbox_open_easy(encrypted, nonce, Uint8Array.from(this.decryptKey));
+ const decrypted = sodium.crypto_secretbox_open_easy(encrypted, nonce, Buffer.from(this.decryptKey));
console.log("[UDP] [ call status ]" + decrypted);
}
catch (e) {
@@ -95,13 +112,13 @@ export class Server {
return;
}
- try {
- const decrypted = sodium.crypto_secretbox_open_easy(encrypted, nonce, Uint8Array.from(this.decryptKey));
- console.log("[UDP] " + decrypted);
- }
- catch (e) {
- console.error(`[UDP] decrypt failure\n${e}\n${msg.toString("base64")}`);
- }
+ // try {
+ // const decrypted = sodium.crypto_secretbox_open_easy(encrypted, nonce, Buffer.from(this.decryptKey.map(x => String.fromCharCode(x)).join("")));
+ // console.log("[UDP] " + decrypted);
+ // }
+ // catch (e) {
+ // console.error(`[UDP] decrypt failure\n${e}\n${msg.toString("base64")}`);
+ // }
});
}
@@ -109,7 +126,7 @@ export class Server {
// @ts-ignore
await initDatabase();
await Config.init();
- //await this.createWorkers();
+ await this.createWorkers();
console.log("[DB] connected");
console.log(`[WebRTC] online on 0.0.0.0:${port}`);
}
diff --git a/webrtc/src/opcodes/Identify.ts b/webrtc/src/opcodes/Identify.ts
index 68452d4f..ef0386a7 100644
--- a/webrtc/src/opcodes/Identify.ts
+++ b/webrtc/src/opcodes/Identify.ts
@@ -33,18 +33,18 @@ export async function onIdentify(this: Server, socket: WebSocket, data: Identify
if (!guild.members.find(x => x.id === user.id))
return socket.close(CLOSECODES.Invalid_intent);
- // var transport = this.mediasoupTransports[0] || await this.mediasoupRouters[0].createWebRtcTransport({
- // listenIps: [{ ip: "10.22.64.56" }],
- // enableUdp: true,
- // });
-7
+ var transport = this.mediasoupTransports[0] || await this.mediasoupRouters[0].createWebRtcTransport({
+ listenIps: [{ ip: "10.22.64.146" }],
+ enableUdp: true,
+ });
+
socket.send(JSON.stringify({
op: VoiceOPCodes.READY,
d: {
- streams: data.d.streams ? [...data.d.streams.map(x => ({ ...x, rtx_ssrc: Math.floor(Math.random() * 10000), ssrc: Math.floor(Math.random() * 10000), active: false, }))] : undefined,
+ streams: data.d.streams ? [...data.d.streams.map(x => ({ ...x, rtx_ssrc: Math.floor(Math.random() * 10000), ssrc: Math.floor(Math.random() * 10000), active: true, }))] : undefined,
ssrc: Math.floor(Math.random() * 10000),
- ip: "127.0.0.1",//transport.iceCandidates[0].ip,
- port: 50001,//transport.iceCandidates[0].port,
+ ip: transport.iceCandidates[0].ip,
+ port: transport.iceCandidates[0].port,
modes: [
"aead_aes256_gcm_rtpsize",
"aead_aes256_gcm",
diff --git a/webrtc/src/opcodes/SelectProtocol.ts b/webrtc/src/opcodes/SelectProtocol.ts
index 75ab4495..72fb9c79 100644
--- a/webrtc/src/opcodes/SelectProtocol.ts
+++ b/webrtc/src/opcodes/SelectProtocol.ts
@@ -7,6 +7,24 @@ import { RtpCodecCapability } from "mediasoup/node/lib/RtpParameters";
import * as sdpTransform from 'sdp-transform';
import sodium from "libsodium-wrappers";
+export interface CodecPayload {
+ name: string,
+ type: "audio" | "video",
+ priority: number,
+ payload_type: number,
+ rtx_payload_type: number | null,
+}
+
+export interface SelectProtocolPayload extends Payload {
+ d: {
+ codecs: Array,
+ data: string, // SDP if webrtc
+ protocol: string,
+ rtc_connection_id: string,
+ sdp?: string, // same as data
+ };
+}
+
/*
Sent by client:
@@ -70,108 +88,119 @@ import sodium from "libsodium-wrappers";
}
*/
-export async function onSelectProtocol(this: Server, socket: WebSocket, data: Payload) {
- // const rtpCapabilities = this.mediasoupRouters[0].rtpCapabilities;
- // const codecs = rtpCapabilities.codecs as RtpCodecCapability[];
-
+export async function onSelectProtocol(this: Server, socket: WebSocket, data: SelectProtocolPayload) {
if (data.d.sdp) {
- // const transport = this.mediasoupTransports[0]; //whatever
+ const rtpCapabilities = this.mediasoupRouters[0].rtpCapabilities;
+ const codecs = rtpCapabilities.codecs as RtpCodecCapability[];
- // const res = sdpTransform.parse(data.d.sdp);
+ const transport = this.mediasoupTransports[0]; //whatever
- // const videoCodec = this.mediasoupRouters[0].rtpCapabilities.codecs!.find((x: any) => x.kind === "video");
- // const audioCodec = this.mediasoupRouters[0].rtpCapabilities.codecs!.find((x: any) => x.kind === "audio");
+ const res = sdpTransform.parse(data.d.sdp);
- // const producer = this.mediasoupProducers[0] || await transport.produce({
- // kind: "audio",
- // rtpParameters: {
- // mid: "audio",
- // codecs: [{
- // clockRate: audioCodec!.clockRate,
- // payloadType: audioCodec!.preferredPayloadType as number,
- // mimeType: audioCodec!.mimeType,
- // channels: audioCodec?.channels,
- // }],
- // headerExtensions: res.ext?.map(x => ({
- // id: x.value,
- // uri: x.uri,
- // })),
- // },
- // paused: false,
- // });
+ const videoCodec = this.mediasoupRouters[0].rtpCapabilities.codecs!.find((x: any) => x.kind === "video");
+ const audioCodec = this.mediasoupRouters[0].rtpCapabilities.codecs!.find((x: any) => x.kind === "audio");
- // console.log("can consume: " + this.mediasoupRouters[0].canConsume({ producerId: producer.id, rtpCapabilities: rtpCapabilities }));
+ const producer = this.mediasoupProducers[0] || await transport.produce({
+ kind: "audio",
+ rtpParameters: {
+ mid: "audio",
+ codecs: [{
+ clockRate: audioCodec!.clockRate,
+ payloadType: audioCodec!.preferredPayloadType as number,
+ mimeType: audioCodec!.mimeType,
+ channels: audioCodec?.channels,
+ }],
+ headerExtensions: res.ext?.map(x => ({
+ id: x.value,
+ uri: x.uri,
+ })),
+ },
+ paused: false,
+ });
- // // const consumer = this.mediasoupConsumers[0] || await transport.consume({
- // // producerId: producer.id,
- // // paused: false,
- // // rtpCapabilities,
- // // });
+ console.log("can consume: " + this.mediasoupRouters[0].canConsume({ producerId: producer.id, rtpCapabilities: rtpCapabilities }));
- // socket.send(JSON.stringify({
- // op: VoiceOPCodes.SESSION_DESCRIPTION,
- // d: {
- // video_codec: videoCodec?.mimeType?.substring(6) || undefined,
- // // mode: "xsalsa20_poly1305_lite",
- // media_session_id: transport.id,
- // audio_codec: audioCodec?.mimeType.substring(6),
- // secret_key: sodium.from_hex("724b092810ec86d7e35c9d067702b31ef90bc43a7b598626749914d6a3e033ed").buffer,
- // sdp: `m=audio ${50001} ICE/SDP\n`
- // + `a=fingerprint:sha-256 ${transport.dtlsParameters.fingerprints.find(x => x.algorithm === "sha-256")?.value}\n`
- // + `c=IN IP4 ${transport.iceCandidates[0].ip}\n`
- // + `t=0 0\n`
- // + `a=ice-lite\n`
- // + `a=rtcp-mux\n`
- // + `a=rtcp:${50001}\n`
- // + `a=ice-ufrag:${transport.iceParameters.usernameFragment}\n`
- // + `a=ice-pwd:${transport.iceParameters.password}\n`
- // + `a=fingerprint:sha-256 ${transport.dtlsParameters.fingerprints.find(x => x.algorithm === "sha-256")?.value}\n`
- // + `a=candidate:1 1 ${transport.iceCandidates[0].protocol.toUpperCase()} ${transport.iceCandidates[0].priority} ${transport.iceCandidates[0].ip} ${50001} typ ${transport.iceCandidates[0].type}`
- // }
- // }));
+ const consumer = this.mediasoupConsumers[0] || await transport.consume({
+ producerId: producer.id,
+ paused: false,
+ rtpCapabilities,
+ });
+
+ transport.connect({
+ dtlsParameters: {
+ fingerprints: transport.dtlsParameters.fingerprints,
+ role: "server",
+ }
+ });
+
+ socket.send(JSON.stringify({
+ op: VoiceOPCodes.SESSION_DESCRIPTION,
+ d: {
+ video_codec: videoCodec?.mimeType?.substring(6) || undefined,
+ // mode: "xsalsa20_poly1305_lite",
+ media_session_id: transport.id,
+ audio_codec: audioCodec?.mimeType.substring(6),
+ secret_key: sodium.from_hex("724b092810ec86d7e35c9d067702b31ef90bc43a7b598626749914d6a3e033ed").buffer,
+ sdp: `m=audio ${50001} ICE/SDP\n`
+ + `a=fingerprint:sha-256 ${transport.dtlsParameters.fingerprints.find(x => x.algorithm === "sha-256")?.value}\n`
+ + `c=IN IP4 ${transport.iceCandidates[0].ip}\n`
+ + `t=0 0\n`
+ + `a=ice-lite\n`
+ + `a=rtcp-mux\n`
+ + `a=rtcp:${50001}\n`
+ + `a=ice-ufrag:${transport.iceParameters.usernameFragment}\n`
+ + `a=ice-pwd:${transport.iceParameters.password}\n`
+ + `a=fingerprint:sha-256 ${transport.dtlsParameters.fingerprints.find(x => x.algorithm === "sha-256")?.value}\n`
+ + `a=candidate:1 1 ${transport.iceCandidates[0].protocol.toUpperCase()} ${transport.iceCandidates[0].priority} ${transport.iceCandidates[0].ip} ${50001} typ ${transport.iceCandidates[0].type}`
+ }
+ }));
return;
}
- /*
- {
- "video_codec":"H264",
- "sdp":
- "
- m=audio 50010 ICE/SDP
- a=fingerprint:sha-256 4A:79:94:16:44:3F:BD:05:41:5A:C7:20:F3:12:54:70:00:73:5D:33:00:2D:2C:80:9B:39:E1:9F:2D:A7:49:87
- c=IN IP4 109.200.214.158
- a=rtcp:50010
- a=ice-ufrag:+npq
- a=ice-pwd:+jf7jAesMeHHby43FRqWTy
- a=fingerprint:sha-256 4A:79:94:16:44:3F:BD:05:41:5A:C7:20:F3:12:54:70:00:73:5D:33:00:2D:2C:80:9B:39:E1:9F:2D:A7:49:87
- a=candidate:1 1 UDP 4261412862 109.200.214.158 50010 typ host",
- "media_session_id":"59265c94fa13e313492c372c4c8da801
- ",
- "audio_codec":"opus"
- }
- */
+ else {
+ /*
+ {
+ "video_codec":"H264",
+ "sdp":
+ "
+ m=audio 50010 ICE/SDP
+ a=fingerprint:sha-256 4A:79:94:16:44:3F:BD:05:41:5A:C7:20:F3:12:54:70:00:73:5D:33:00:2D:2C:80:9B:39:E1:9F:2D:A7:49:87
+ c=IN IP4 109.200.214.158
+ a=rtcp:50010
+ a=ice-ufrag:+npq
+ a=ice-pwd:+jf7jAesMeHHby43FRqWTy
+ a=fingerprint:sha-256 4A:79:94:16:44:3F:BD:05:41:5A:C7:20:F3:12:54:70:00:73:5D:33:00:2D:2C:80:9B:39:E1:9F:2D:A7:49:87
+ a=candidate:1 1 UDP 4261412862 109.200.214.158 50010 typ host",
+ "media_session_id":"59265c94fa13e313492c372c4c8da801
+ ",
+ "audio_codec":"opus"
+ }
+ */
- /*
- {
- "video_codec": "H264",
- "secret_key": [36, 80, 96, 53, 95, 149, 253, 16, 137, 186, 238, 222, 251, 180, 94, 150, 112, 137, 192, 109, 69, 79, 218, 111, 217, 197, 56, 74, 18, 41, 51, 140],
- "mode": "aead_aes256_gcm_rtpsize",
- "media_session_id": "797575a97a87b63e81e2399348b97ad1",
- "audio_codec": "opus"
- };
- */
+ /*
+ {
+ "video_codec": "H264",
+ "secret_key": [36, 80, 96, 53, 95, 149, 253, 16, 137, 186, 238, 222, 251, 180, 94, 150, 112, 137, 192, 109, 69, 79, 218, 111, 217, 197, 56, 74, 18, 41, 51, 140],
+ "mode": "aead_aes256_gcm_rtpsize",
+ "media_session_id": "797575a97a87b63e81e2399348b97ad1",
+ "audio_codec": "opus"
+ };
+ */
- this.decryptKey = [...sodium.randombytes_buf(sodium.crypto_secretbox_KEYBYTES)];
- console.log(this.decryptKey.map(x => String.fromCharCode(x)).join(""));
+ this.decryptKey = sodium.randombytes_buf(sodium.crypto_secretbox_KEYBYTES);
- socket.send(JSON.stringify({
- op:VoiceOPCodes.SESSION_DESCRIPTION,
- d: {
- video_codec: "H264",
- secret_key: this.decryptKey,
- mode: "aead_aes256_gcm_rtpsize",
- media_session_id: "blah blah blah",
- audio_codec: "opus",
- }
- }));
+ // this.decryptKey = new Array(sodium.crypto_secretbox_KEYBYTES).fill(null).map((x, i) => i + 1);
+ console.log(this.decryptKey);
+
+ socket.send(JSON.stringify({
+ op: VoiceOPCodes.SESSION_DESCRIPTION,
+ d: {
+ video_codec: "H264",
+ secret_key: [...this.decryptKey.values()],
+ mode: "aead_aes256_gcm_rtpsize",
+ media_session_id: "blah blah blah",
+ audio_codec: "opus",
+ }
+ }));
+ }
}
\ No newline at end of file