Skip to content

Commit 3b848d4

Browse files
committed
some VC updates
1 parent ac724bd commit 3b848d4

File tree

5 files changed

+128
-22
lines changed

5 files changed

+128
-22
lines changed

src/webpage/channel.ts

Lines changed: 57 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1124,31 +1124,54 @@ class Channel extends SnowFlake {
11241124
console.log("vid", elm);
11251125
box.append(elm);
11261126
}
1127+
makeBig(box: HTMLElement) {
1128+
const par = box.parentElement;
1129+
if (!par) return;
1130+
if (par.children[0] !== box || !box.classList.contains("bigBox")) {
1131+
box.classList.add("bigBox");
1132+
if (par.children[0] !== box) {
1133+
par.children[0].classList.remove("bigBox");
1134+
}
1135+
} else {
1136+
par.children[0].classList.remove("bigBox");
1137+
}
1138+
par.prepend(box);
1139+
}
11271140
decorateLive(id: string) {
11281141
if (!this.voice) return;
11291142
const box = this.liveMap.get(id);
11301143
if (!box) return;
11311144
box.innerHTML = "";
11321145
const live = this.voice.getLive(id);
1146+
const self = id === this.localuser.user.id;
11331147
if (!this.voice.open) {
11341148
const span = document.createElement("span");
11351149
span.textContent = I18n.vc.joinForStream();
11361150
box.append(span);
11371151
} else if (live) {
11381152
const leave = document.createElement("button");
11391153
leave.classList.add("leave");
1140-
leave.textContent = I18n.vc.leavestream();
1141-
leave.onclick = () => {
1142-
this.voice?.leaveLive(id);
1154+
leave.textContent = self ? I18n.vc.stopstream() : I18n.vc.leavestream();
1155+
leave.onclick = (e) => {
1156+
e.stopImmediatePropagation();
1157+
if (self) {
1158+
this.voice?.stopStream();
1159+
} else {
1160+
this.voice?.leaveLive(id);
1161+
}
11431162
};
11441163
box.append(live, leave);
1145-
} else {
1164+
} else if (!self) {
11461165
const joinB = document.createElement("button");
11471166
joinB.textContent = I18n.vc.joinstream();
11481167
joinB.classList.add("joinb");
11491168
box.append(joinB);
11501169
joinB.onclick = () => {
11511170
if (!this.voice) return;
1171+
box.innerHTML = "";
1172+
const span = document.createElement("span");
1173+
span.textContent = I18n.vc.joiningStream();
1174+
box.append(span);
11521175
this.voice.joinLive(id);
11531176
};
11541177
}
@@ -1194,6 +1217,9 @@ class Channel extends SnowFlake {
11941217
} else if (!live && change.live && box) {
11951218
const livediv = document.createElement("div");
11961219
this.liveMap.set(id, livediv);
1220+
livediv.onclick = () => {
1221+
this.makeBig(livediv);
1222+
};
11971223
box.parentElement?.prepend(livediv);
11981224
this.decorateLive(id);
11991225
}
@@ -1217,6 +1243,9 @@ class Channel extends SnowFlake {
12171243
async makeUserBox(user: User, users: HTMLElement) {
12181244
const memb = Member.resolveMember(user, this.guild);
12191245
const box = document.createElement("div");
1246+
box.onclick = () => {
1247+
this.makeBig(box);
1248+
};
12201249
this.boxMap.set(user.id, box);
12211250
if (user.accent_color != undefined) {
12221251
box.style.setProperty(
@@ -1297,6 +1326,7 @@ class Channel extends SnowFlake {
12971326
updateVideoIcon();
12981327
video.onclick = async () => {
12991328
if (!this.voice) return;
1329+
if (!this.voice.open) return;
13001330
if (this.localuser.voiceFactory?.video) {
13011331
this.voice.stopVideo();
13021332
} else {
@@ -1317,23 +1347,39 @@ class Channel extends SnowFlake {
13171347
video.classList.add("callVoiceIcon");
13181348

13191349
const updateLiveIcon = () => {
1320-
lspan.classList.remove("svg-video", "svg-novideo");
1321-
lspan.classList.add(true ? "svg-stream" : "svg-stopstream");
1350+
lspan.classList.remove("svg-stream", "svg-stopstream");
1351+
lspan.classList.add(this.voice?.isLive() ? "svg-stopstream" : "svg-stream");
13221352
};
13231353
const live = document.createElement("div");
13241354
const lspan = document.createElement("span");
13251355
live.append(lspan);
13261356
updateLiveIcon();
13271357
live.onclick = async () => {
1328-
const stream = await navigator.mediaDevices.getDisplayMedia();
1329-
this.voice?.createLive(this.localuser.user.id, stream);
1358+
if (!this.voice?.open) return;
1359+
if (this.voice?.isLive()) {
1360+
this.voice?.stopStream();
1361+
} else {
1362+
const stream = await navigator.mediaDevices.getDisplayMedia();
1363+
const v = await this.voice?.createLive(stream);
1364+
console.log(v);
1365+
}
13301366
updateLiveIcon();
13311367
};
13321368
live.classList.add("callVoiceIcon");
13331369

1334-
buttonRow.append(mute, call, video, live);
1370+
buttonRow.append(mute, video, live, call);
13351371

13361372
const users = document.createElement("div");
1373+
const mut = new MutationObserver(() => {
1374+
const arr = Array.from(users.children);
1375+
const box = arr.find((_) => _.classList.contains("bigBox"));
1376+
if (box && arr[0] !== box) {
1377+
users.prepend(box);
1378+
}
1379+
});
1380+
mut.observe(users, {
1381+
childList: true,
1382+
});
13371383
users.classList.add("voiceUsers");
13381384

13391385
this.voice.userids.forEach(async (_, id) => {
@@ -1351,6 +1397,7 @@ class Channel extends SnowFlake {
13511397
this.boxVid(id, vid);
13521398
};
13531399
this.voice.onGotStream = (_vid, id) => {
1400+
updateLiveIcon();
13541401
this.decorateLive(id);
13551402
};
13561403
this.voice.onconnect = () => {
@@ -1365,6 +1412,7 @@ class Channel extends SnowFlake {
13651412

13661413
this.voice.onLeave = () => {
13671414
updateCallIcon();
1415+
updateVideoIcon();
13681416
for (const [id] of this.boxMap) {
13691417
this.purgeVid(id);
13701418
}

src/webpage/icons/stopstream.svg

Lines changed: 1 addition & 0 deletions
Loading

src/webpage/style.css

Lines changed: 21 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -218,31 +218,40 @@ body {
218218
.leave:hover {
219219
background: color-mix(in srgb, var(--red) 85%, white);
220220
}
221+
221222
.voiceUsers > * {
222223
background: var(--accent_color, var(--primary-bg));
223224
border-radius: 8px;
224225
position: relative;
225226
box-sizing: border-box;
226227
margin: 8px;
227228
width: 340px;
228-
height: 220px;
229+
aspect-ratio: 3/2;
229230
display: flex;
230-
justify-content: center;
231231
align-items: center;
232-
232+
justify-content: center;
233+
cursor: pointer;
233234
img {
234235
width: 60px;
235236
height: 60px;
236237
cursor: unset;
237238
}
238239
video {
239240
position: absolute;
240-
top: 0px;
241-
left: 0px;
242-
width: 100%;
243-
height: 100%;
241+
flex-grow: 1;
244242
}
245243
}
244+
.voiceUsers:has(.bigBox) > * {
245+
width: 220px;
246+
flex-grow: 0;
247+
flex-shrink: 0;
248+
}
249+
.bigBox {
250+
width: min(80%, 600px) !important;
251+
height: unset;
252+
margin: 0 calc((100% - min(80%, 600px)) / 2);
253+
}
254+
246255
.buttonRow > * {
247256
margin-right: 6px;
248257
width: 54px;
@@ -529,6 +538,11 @@ textarea {
529538
mask: url(/icons/stream.svg);
530539
mask-size: contain !important;
531540
}
541+
.svg-stopstream {
542+
mask: url(/icons/stopstream.svg);
543+
mask-size: contain !important;
544+
background-color: var(--red);
545+
}
532546
.svg-video {
533547
mask: url(/icons/video.svg);
534548
mask-size: contain !important;

src/webpage/voice.ts

Lines changed: 46 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,7 @@ class VoiceFactory {
7070
},
7171
});
7272
}
73+
7374
updateSelf() {
7475
if (this.currentVoice && this.currentVoice.open) {
7576
this.handleGateway({
@@ -111,6 +112,16 @@ class VoiceFactory {
111112
op: 4,
112113
};
113114
}
115+
leaveLive() {
116+
const userid = this.settings.id;
117+
const stream_key = `${this.curGuild === "@me" ? "call" : `guild:${this.curGuild}`}:${this.curChan}:${userid}`;
118+
this.handleGateway({
119+
op: 19,
120+
d: {
121+
stream_key,
122+
},
123+
});
124+
}
114125
live = new Map<string, (res: Voice) => void>();
115126
steamTokens = new Map<string, Promise<[string, string]>>();
116127
steamTokensRes = new Map<string, (res: [string, string]) => void>();
@@ -134,7 +145,8 @@ class VoiceFactory {
134145
}
135146
islive = false;
136147
liveStream?: MediaStream;
137-
async createLive(userid: string, stream: MediaStream) {
148+
async createLive(stream: MediaStream) {
149+
const userid = this.settings.id;
138150
this.islive = true;
139151
this.liveStream = stream;
140152
const stream_key = `${this.curGuild === "@me" ? "call" : `guild:${this.curGuild}`}:${this.curChan}:${userid}`;
@@ -207,6 +219,9 @@ class VoiceFactory {
207219
};
208220

209221
voice2.gotStream(voice, user);
222+
console.warn(voice2);
223+
const res = this.live.get(create.d.stream_key);
224+
if (res) res(voice);
210225
}
211226
}
212227
streamServerUpdate(update: streamServerUpdate) {
@@ -410,6 +425,7 @@ class Voice {
410425
if (!ld) throw new Error("localDescription isn't defined");
411426
const parsed = Voice.parsesdp(ld.sdp);
412427
const group = parsed.atr.get("group");
428+
console.warn(parsed);
413429
if (!group) throw new Error("group isn't in sdp");
414430
const [_, ...bundles] = (group.entries().next().value as [string, string])[0].split(" ");
415431
bundles[bundles.length - 1] = bundles[bundles.length - 1].replace("\r", "");
@@ -508,13 +524,19 @@ a=rtcp-mux\r`;
508524
const sendOffer = async () => {
509525
console.trace("neg need");
510526
await pc.setLocalDescription();
527+
console.log("set local");
511528

512529
const senders = this.senders.difference(this.ssrcMap);
530+
console.log(senders, this.ssrcMap);
513531
for (const sender of senders) {
514-
for (const thing of (await sender.getStats()) as Map<string, any>) {
532+
console.log(sender);
533+
const d = (await sender.getStats()) as Map<string, any>;
534+
console.log([...d]);
535+
for (const thing of d) {
515536
if (thing[1].ssrc) {
516537
this.ssrcMap.set(sender, thing[1].ssrc);
517538
this.makeOp12(sender);
539+
console.warn("ssrc");
518540
}
519541
}
520542
}
@@ -532,14 +554,20 @@ a=rtcp-mux\r`;
532554
this.status = "Done";
533555
}
534556
};
557+
function logState(thing: string, message = "") {
558+
console.log(thing + (message ? ":" + message : ""));
559+
}
535560
pc.addEventListener("negotiationneeded", async () => {
561+
logState("negotiationneeded");
536562
await sendOffer();
537563
console.log(this.ssrcMap);
538564
});
539565
pc.addEventListener("signalingstatechange", async () => {
566+
logState("signalingstatechange", pc.signalingState);
540567
detectDone();
541568
while (!this.counter) await new Promise((res) => setTimeout(res, 100));
542569
if (this.pc && this.counter) {
570+
console.warn("in here :3");
543571
if (pc.signalingState === "have-local-offer") {
544572
const counter = this.counter;
545573
const remote: {sdp: string; type: RTCSdpType} = {
@@ -549,24 +577,28 @@ a=rtcp-mux\r`;
549577
console.log(remote);
550578
await pc.setRemoteDescription(remote);
551579
}
580+
} else {
581+
console.warn("uh oh!");
552582
}
553583
});
554584
pc.addEventListener("connectionstatechange", async () => {
585+
logState("connectionstatechange", pc.connectionState);
555586
detectDone();
556587
if (pc.connectionState === "connecting") {
557588
await pc.setLocalDescription();
558589
}
559590
});
560591
pc.addEventListener("icegatheringstatechange", async () => {
592+
logState("icegatheringstatechange", pc.iceGatheringState);
561593
detectDone();
562-
console.log("icegatheringstatechange", pc.iceGatheringState, this.pc, this.counter);
563594
if (this.pc && this.counter) {
564595
if (pc.iceGatheringState === "complete") {
565596
pc.setLocalDescription();
566597
}
567598
}
568599
});
569600
pc.addEventListener("iceconnectionstatechange", async () => {
601+
logState("iceconnectionstatechange", pc.iceConnectionState);
570602
detectDone();
571603
if (pc.iceConnectionState === "checking") {
572604
sendOffer();
@@ -754,14 +786,17 @@ a=rtcp-mux\r`;
754786
}
755787
liveMap = new Map<string, HTMLVideoElement>();
756788
voiceMap = new Map<string, Voice>();
789+
isLive() {
790+
return !!this.voiceMap.get(this.userid);
791+
}
757792
getLive(id: string) {
758793
return this.liveMap.get(id);
759794
}
760795
joinLive(id: string) {
761796
return this.owner.joinLive(id);
762797
}
763-
createLive(id: string, stream: MediaStream) {
764-
return this.owner.createLive(id, stream);
798+
createLive(stream: MediaStream) {
799+
return this.owner.createLive(stream);
765800
}
766801
leaveLive(id: string) {
767802
const v = this.voiceMap.get(id);
@@ -771,6 +806,10 @@ a=rtcp-mux\r`;
771806
this.liveMap.delete(id);
772807
this.onLeaveStream(id);
773808
}
809+
stopStream() {
810+
this.leaveLive(this.userid);
811+
this.owner.leaveLive();
812+
}
774813
onLeaveStream = (_user: string) => {};
775814
onGotStream = (_v: HTMLVideoElement, _user: string) => {};
776815
gotStream(voice: Voice, user: string) {
@@ -1168,7 +1207,9 @@ a=rtcp-mux\r`;
11681207
console.warn("leave");
11691208
this.open = false;
11701209
this.status = "Left voice chat";
1210+
if (!this.settings.stream) this.owner.video = false;
11711211
this.onLeave();
1212+
11721213
for (const thing of this.liveMap) {
11731214
this.leaveLive(thing[0]);
11741215
}

translations/en.json

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,9 @@
88
"vc": {
99
"joinstream": "Watch stream",
1010
"leavestream": "Leave stream",
11-
"joinForStream": "Join the VC to watch"
11+
"joinForStream": "Join the VC to watch",
12+
"stopstream": "Stop stream",
13+
"joiningStream": "Joining stream..."
1214
},
1315
"readableName": "English",
1416
"pinMessage": "Pin Message",

0 commit comments

Comments
 (0)