basic VC gui
This commit is contained in:
parent
49632b3bab
commit
ce6dc3ba5e
9 changed files with 308 additions and 31 deletions
|
@ -89,7 +89,8 @@
|
||||||
<input type="checkbox" id="memberlisttoggle" checked />
|
<input type="checkbox" id="memberlisttoggle" checked />
|
||||||
</div>
|
</div>
|
||||||
<div class="flexltr flexgrow">
|
<div class="flexltr flexgrow">
|
||||||
<div class="flexttb flexgrow">
|
<div class="flexttb flexgrow" id="voiceArea"></div>
|
||||||
|
<div class="flexttb flexgrow" id="chatArea">
|
||||||
<div id="channelw" class="flexltr">
|
<div id="channelw" class="flexltr">
|
||||||
<div id="loadingdiv"></div>
|
<div id="loadingdiv"></div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -729,6 +729,17 @@ class Channel extends SnowFlake {
|
||||||
if (typeof memb !== "string") {
|
if (typeof memb !== "string") {
|
||||||
await Member.new(memb, this.guild);
|
await Member.new(memb, this.guild);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const users = this.usersDiv.deref();
|
||||||
|
if (users) {
|
||||||
|
const user = await this.localuser.getUser(typeof memb === "string" ? memb : memb.id);
|
||||||
|
if (joined) {
|
||||||
|
this.makeUserBox(user, users);
|
||||||
|
} else {
|
||||||
|
this.destUserBox(user);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
this.updateVoiceUsers();
|
this.updateVoiceUsers();
|
||||||
if (this.voice === this.localuser.currentVoice) {
|
if (this.voice === this.localuser.currentVoice) {
|
||||||
AVoice.noises("join");
|
AVoice.noises("join");
|
||||||
|
@ -1060,7 +1071,124 @@ class Channel extends SnowFlake {
|
||||||
if (!this.last_pin_timestamp && !this.lastpin) return false;
|
if (!this.last_pin_timestamp && !this.lastpin) return false;
|
||||||
return this.last_pin_timestamp !== this.lastpin;
|
return this.last_pin_timestamp !== this.lastpin;
|
||||||
}
|
}
|
||||||
async getHTML(addstate = true, getMessages = true) {
|
boxMap = new Map<string, HTMLElement>();
|
||||||
|
destUserBox(user: User) {
|
||||||
|
const box = this.boxMap.get(user.id);
|
||||||
|
if (!box) return;
|
||||||
|
box.remove();
|
||||||
|
this.boxMap.delete(user.id);
|
||||||
|
}
|
||||||
|
async makeUserBox(user: User, users: HTMLElement) {
|
||||||
|
const memb = Member.resolveMember(user, this.guild);
|
||||||
|
const box = document.createElement("div");
|
||||||
|
this.boxMap.set(user.id, box);
|
||||||
|
if (user.accent_color != undefined) {
|
||||||
|
box.style.setProperty(
|
||||||
|
"--accent_color",
|
||||||
|
`#${user.accent_color.toString(16).padStart(6, "0")}`,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
memb.then((_) => {
|
||||||
|
if (!_) return;
|
||||||
|
if (_.accent_color !== undefined) {
|
||||||
|
box.style.setProperty("--accent_color", `#${_.accent_color.toString(16).padStart(6, "0")}`);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
box.append(user.buildpfp(this.guild));
|
||||||
|
|
||||||
|
const span = document.createElement("span");
|
||||||
|
span.textContent = user.name;
|
||||||
|
memb.then((_) => {
|
||||||
|
if (!_) return;
|
||||||
|
span.textContent = _.name;
|
||||||
|
});
|
||||||
|
span.classList.add("voiceUsername");
|
||||||
|
box.append(span);
|
||||||
|
users.append(box);
|
||||||
|
}
|
||||||
|
usersDiv = new WeakRef(document.createElement("div"));
|
||||||
|
async setUpVoiceArea() {
|
||||||
|
if (!this.voice) throw new Error("voice not found?");
|
||||||
|
const voiceArea = document.getElementById("voiceArea") as HTMLElement;
|
||||||
|
const buttonRow = document.createElement("div");
|
||||||
|
buttonRow.classList.add("flexltr", "buttonRow");
|
||||||
|
const updateMicIcon = () => {
|
||||||
|
mspan.classList.remove("svg-micmute", "svg-mic");
|
||||||
|
mspan.classList.add(this.localuser.mute ? "svg-micmute" : "svg-mic");
|
||||||
|
};
|
||||||
|
|
||||||
|
const mute = document.createElement("div");
|
||||||
|
const mspan = document.createElement("span");
|
||||||
|
mute.append(mspan);
|
||||||
|
updateMicIcon();
|
||||||
|
this.localuser.updateOtherMic = updateMicIcon;
|
||||||
|
mute.onclick = () => {
|
||||||
|
this.localuser.mute = !this.localuser.mute;
|
||||||
|
this.localuser.updateMic();
|
||||||
|
};
|
||||||
|
mute.classList.add("muteVoiceIcon");
|
||||||
|
|
||||||
|
const updateCallIcon = () => {
|
||||||
|
cspan.classList.remove("svg-call", "svg-hangup");
|
||||||
|
cspan.classList.add(this.voice?.open ? "svg-hangup" : "svg-call");
|
||||||
|
};
|
||||||
|
const call = document.createElement("div");
|
||||||
|
const cspan = document.createElement("span");
|
||||||
|
call.append(cspan);
|
||||||
|
updateCallIcon();
|
||||||
|
call.onclick = async () => {
|
||||||
|
if (this.voice?.userids.has(this.localuser.user.id)) {
|
||||||
|
this.voice.leave();
|
||||||
|
} else if (this.voice) {
|
||||||
|
await this.localuser.joinVoice(this);
|
||||||
|
}
|
||||||
|
updateCallIcon();
|
||||||
|
};
|
||||||
|
call.classList.add("callVoiceIcon");
|
||||||
|
|
||||||
|
buttonRow.append(mute, call);
|
||||||
|
|
||||||
|
const users = document.createElement("div");
|
||||||
|
users.classList.add("voiceUsers");
|
||||||
|
this.voice.userids.forEach(async (_, id) => {
|
||||||
|
const user = await this.localuser.getUser(id);
|
||||||
|
this.makeUserBox(user, users);
|
||||||
|
});
|
||||||
|
this.usersDiv = new WeakRef(users);
|
||||||
|
this.voice.onSpeakingChange = (id, speaking) => {
|
||||||
|
const box = this.boxMap.get(id);
|
||||||
|
if (!box) return;
|
||||||
|
if (speaking) {
|
||||||
|
box.classList.add("speaking");
|
||||||
|
} else {
|
||||||
|
box.classList.remove("speaking");
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
voiceArea.append(users, buttonRow);
|
||||||
|
}
|
||||||
|
async getHTML(addstate = true, getMessages: boolean | void = undefined) {
|
||||||
|
if (getMessages === undefined) {
|
||||||
|
getMessages = this.type !== 2 || !this.localuser.voiceAllowed;
|
||||||
|
}
|
||||||
|
|
||||||
|
const messages = document.getElementById("channelw") as HTMLDivElement;
|
||||||
|
const messageContainers = Array.from(messages.getElementsByClassName("messagecontainer"));
|
||||||
|
for (const thing of messageContainers) {
|
||||||
|
thing.remove();
|
||||||
|
}
|
||||||
|
const chatArea = document.getElementById("chatArea") as HTMLElement;
|
||||||
|
|
||||||
|
const voiceArea = document.getElementById("voiceArea") as HTMLElement;
|
||||||
|
voiceArea.innerHTML = "";
|
||||||
|
if (getMessages) {
|
||||||
|
chatArea.style.removeProperty("display");
|
||||||
|
} else {
|
||||||
|
chatArea.style.setProperty("display", "none");
|
||||||
|
this.setUpVoiceArea();
|
||||||
|
}
|
||||||
|
|
||||||
const pinnedM = document.getElementById("pinnedMDiv");
|
const pinnedM = document.getElementById("pinnedMDiv");
|
||||||
if (pinnedM) {
|
if (pinnedM) {
|
||||||
if (this.unreadPins()) {
|
if (this.unreadPins()) {
|
||||||
|
@ -1069,11 +1197,6 @@ class Channel extends SnowFlake {
|
||||||
pinnedM.classList.remove("unreadPin");
|
pinnedM.classList.remove("unreadPin");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
const ghostMessages = document.getElementById("ghostMessages") as HTMLElement;
|
|
||||||
ghostMessages.innerHTML = "";
|
|
||||||
for (const thing of this.fakeMessages) {
|
|
||||||
ghostMessages.append(thing[1]);
|
|
||||||
}
|
|
||||||
if (addstate) {
|
if (addstate) {
|
||||||
history.pushState([this.guild_id, this.id], "", "/channels/" + this.guild_id + "/" + this.id);
|
history.pushState([this.guild_id, this.id], "", "/channels/" + this.guild_id + "/" + this.id);
|
||||||
}
|
}
|
||||||
|
@ -1095,6 +1218,7 @@ class Channel extends SnowFlake {
|
||||||
if (this.guild !== this.localuser.lookingguild) {
|
if (this.guild !== this.localuser.lookingguild) {
|
||||||
this.guild.loadGuild();
|
this.guild.loadGuild();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.localuser.channelfocus && this.localuser.channelfocus.myhtml) {
|
if (this.localuser.channelfocus && this.localuser.channelfocus.myhtml) {
|
||||||
this.localuser.channelfocus.myhtml.classList.remove("viewChannel");
|
this.localuser.channelfocus.myhtml.classList.remove("viewChannel");
|
||||||
}
|
}
|
||||||
|
@ -1117,15 +1241,22 @@ class Channel extends SnowFlake {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const prom = this.infinite.delete();
|
const ghostMessages = document.getElementById("ghostMessages") as HTMLElement;
|
||||||
|
ghostMessages.innerHTML = "";
|
||||||
|
for (const thing of this.fakeMessages) {
|
||||||
|
ghostMessages.append(thing[1]);
|
||||||
|
}
|
||||||
|
|
||||||
const loading = document.getElementById("loadingdiv") as HTMLDivElement;
|
const prom = this.infinite.delete();
|
||||||
Channel.regenLoadingMessages();
|
if (getMessages) {
|
||||||
loading.classList.add("loading");
|
const loading = document.getElementById("loadingdiv") as HTMLDivElement;
|
||||||
|
Channel.regenLoadingMessages();
|
||||||
|
loading.classList.add("loading");
|
||||||
|
}
|
||||||
this.rendertyping();
|
this.rendertyping();
|
||||||
this.localuser.getSidePannel();
|
this.localuser.getSidePannel();
|
||||||
if (this.voice && this.localuser.voiceAllowed) {
|
if (this.voice && this.localuser.voiceAllowed) {
|
||||||
this.localuser.joinVoice(this);
|
//this.localuser.joinVoice(this);
|
||||||
}
|
}
|
||||||
(document.getElementById("typebox") as HTMLDivElement).contentEditable = "" + this.canMessage;
|
(document.getElementById("typebox") as HTMLDivElement).contentEditable = "" + this.canMessage;
|
||||||
(document.getElementById("upload") as HTMLElement).style.visibility = this.canMessage
|
(document.getElementById("upload") as HTMLElement).style.visibility = this.canMessage
|
||||||
|
|
|
@ -54,6 +54,8 @@ class Direct extends Guild {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
getHTML() {
|
getHTML() {
|
||||||
|
const voiceArea = document.getElementById("voiceArea") as HTMLElement;
|
||||||
|
voiceArea.innerHTML = "";
|
||||||
const sideContainDiv = document.getElementById("sideContainDiv");
|
const sideContainDiv = document.getElementById("sideContainDiv");
|
||||||
if (sideContainDiv) {
|
if (sideContainDiv) {
|
||||||
sideContainDiv.classList.remove("searchDiv");
|
sideContainDiv.classList.remove("searchDiv");
|
||||||
|
|
1
src/webpage/icons/call.svg
Normal file
1
src/webpage/icons/call.svg
Normal file
|
@ -0,0 +1 @@
|
||||||
|
<svg width="48" height="48" xmlns="http://www.w3.org/2000/svg"><path style="fill:none;fill-rule:evenodd;stroke:#000;stroke-width:10;stroke-linecap:round;stroke-dasharray:none" d="M7.7 22.7a20.9 20.9 0 0 1 31.6-.6" transform="rotate(-133.7 24.2 26.6) scale(1.16048)"/><path style="fill:#1a1a1a;stroke:#000;stroke-width:6.99651;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none" transform="rotate(-133.7)" d="M-21.9-3.1h9.1v7.2h-9.1zM-52.9-3.1h9.1v7.2h-9.1z"/></svg>
|
After Width: | Height: | Size: 479 B |
1
src/webpage/icons/hangup.svg
Normal file
1
src/webpage/icons/hangup.svg
Normal file
|
@ -0,0 +1 @@
|
||||||
|
<svg width="48" height="48" xmlns="http://www.w3.org/2000/svg"><path style="fill:none;fill-rule:evenodd;stroke:#000;stroke-width:10;stroke-linecap:round;stroke-dasharray:none" d="M7.7 22.7a20.9 20.9 0 0 1 31.6-.6" transform="translate(-3.4 -2) scale(1.16048)"/><path style="fill:#1a1a1a;stroke:#000;stroke-width:6.99651;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none" d="M34.8 22.3h9.1v7.2h-9.1zM3.8 22.3h9.1v7.2H3.8z"/></svg>
|
After Width: | Height: | Size: 444 B |
|
@ -249,9 +249,12 @@ class Localuser {
|
||||||
}
|
}
|
||||||
mute = true;
|
mute = true;
|
||||||
deaf = false;
|
deaf = false;
|
||||||
updateMic() {
|
updateOtherMic = () => {};
|
||||||
|
updateMic(updateVoice: boolean = true) {
|
||||||
|
this.updateOtherMic();
|
||||||
const mic = document.getElementById("mic") as HTMLElement;
|
const mic = document.getElementById("mic") as HTMLElement;
|
||||||
mic.classList.remove("svg-mic", "svg-micmute");
|
mic.classList.remove("svg-mic", "svg-micmute");
|
||||||
|
if (this.voiceFactory && updateVoice) this.voiceFactory.mute = this.mute;
|
||||||
if (this.mute) {
|
if (this.mute) {
|
||||||
mic.classList.add("svg-micmute");
|
mic.classList.add("svg-micmute");
|
||||||
} else {
|
} else {
|
||||||
|
@ -271,7 +274,11 @@ class Localuser {
|
||||||
|
|
||||||
this.mdBox();
|
this.mdBox();
|
||||||
|
|
||||||
this.voiceFactory = new VoiceFactory({id: this.user.id});
|
this.voiceFactory = new VoiceFactory({id: this.user.id}, (g) => {
|
||||||
|
if (this.ws) {
|
||||||
|
this.ws.send(JSON.stringify(g));
|
||||||
|
}
|
||||||
|
});
|
||||||
this.handleVoice();
|
this.handleVoice();
|
||||||
this.mfa_enabled = ready.d.user.mfa_enabled as boolean;
|
this.mfa_enabled = ready.d.user.mfa_enabled as boolean;
|
||||||
this.userinfo.username = this.user.username;
|
this.userinfo.username = this.user.username;
|
||||||
|
@ -757,6 +764,10 @@ class Localuser {
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case "VOICE_STATE_UPDATE":
|
case "VOICE_STATE_UPDATE":
|
||||||
|
if (this.user.id === temp.d.user_id) {
|
||||||
|
this.mute = temp.d.self_mute;
|
||||||
|
this.updateMic(false);
|
||||||
|
}
|
||||||
if (this.voiceFactory) {
|
if (this.voiceFactory) {
|
||||||
this.voiceFactory.voiceStateUpdate(temp.d);
|
this.voiceFactory.voiceStateUpdate(temp.d);
|
||||||
}
|
}
|
||||||
|
|
|
@ -184,6 +184,69 @@ body {
|
||||||
position: relative;
|
position: relative;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
}
|
}
|
||||||
|
#voiceArea:empty {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
#voiceArea {
|
||||||
|
background: var(--black);
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
.voiceUsers {
|
||||||
|
padding: 20px;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
}
|
||||||
|
.speaking {
|
||||||
|
border: solid var(--green) 3px;
|
||||||
|
padding: 77px 137px !important;
|
||||||
|
}
|
||||||
|
.voiceUsers > * {
|
||||||
|
background: var(--accent_color, var(--primary-bg));
|
||||||
|
padding: 80px 140px;
|
||||||
|
width: fit-content;
|
||||||
|
border-radius: 8px;
|
||||||
|
position: relative;
|
||||||
|
box-sizing: border-box;
|
||||||
|
margin: 8px;
|
||||||
|
|
||||||
|
img {
|
||||||
|
width: 60px;
|
||||||
|
height: 60px;
|
||||||
|
cursor: unset;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.buttonRow > * {
|
||||||
|
margin-right: 6px;
|
||||||
|
width: 54px;
|
||||||
|
height: 54px;
|
||||||
|
background: var(--secondary-hover);
|
||||||
|
border-radius: 100%;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
cursor: pointer;
|
||||||
|
* {
|
||||||
|
width: 32px !important;
|
||||||
|
height: 32px !important;
|
||||||
|
background: var(--primary-text);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.buttonRow {
|
||||||
|
position: absolute;
|
||||||
|
bottom: 20px;
|
||||||
|
width: 100%;
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
.voiceUsername {
|
||||||
|
position: absolute;
|
||||||
|
bottom: 10px;
|
||||||
|
left: 14px;
|
||||||
|
background: var(--secondary-bg);
|
||||||
|
padding: 4px;
|
||||||
|
border-radius: 6px;
|
||||||
|
}
|
||||||
.flexgrow {
|
.flexgrow {
|
||||||
flex-grow: 1;
|
flex-grow: 1;
|
||||||
min-height: 0;
|
min-height: 0;
|
||||||
|
@ -415,6 +478,15 @@ textarea {
|
||||||
display: block;
|
display: block;
|
||||||
mask-size: cover !important;
|
mask-size: cover !important;
|
||||||
}
|
}
|
||||||
|
.svg-call {
|
||||||
|
mask: url(/icons/call.svg);
|
||||||
|
mask-size: contain !important;
|
||||||
|
}
|
||||||
|
.svg-hangup {
|
||||||
|
mask: url(/icons/hangup.svg);
|
||||||
|
mask-size: contain !important;
|
||||||
|
background: var(--red);
|
||||||
|
}
|
||||||
.svg-plainx {
|
.svg-plainx {
|
||||||
mask: url(/icons/plainx.svg);
|
mask: url(/icons/plainx.svg);
|
||||||
mask-size: contain !important;
|
mask-size: contain !important;
|
||||||
|
|
|
@ -499,14 +499,14 @@ class User extends SnowFlake {
|
||||||
this.bind(div, guild);
|
this.bind(div, guild);
|
||||||
return div;
|
return div;
|
||||||
}
|
}
|
||||||
async buildstatuspfp(guild: Guild | void | Member | null): Promise<HTMLDivElement> {
|
buildstatuspfp(guild: Guild | void | Member | null): HTMLDivElement {
|
||||||
const div = document.createElement("div");
|
const div = document.createElement("div");
|
||||||
div.classList.add("pfpDiv");
|
div.classList.add("pfpDiv");
|
||||||
const pfp = this.buildpfp(guild, div);
|
const pfp = this.buildpfp(guild, div);
|
||||||
div.append(pfp);
|
div.append(pfp);
|
||||||
const status = document.createElement("div");
|
const status = document.createElement("div");
|
||||||
status.classList.add("statusDiv");
|
status.classList.add("statusDiv");
|
||||||
switch (await this.getStatus()) {
|
switch (this.getStatus()) {
|
||||||
case "offline":
|
case "offline":
|
||||||
case "invisible":
|
case "invisible":
|
||||||
status.classList.add("offlinestatus");
|
status.classList.add("offlinestatus");
|
||||||
|
@ -785,7 +785,7 @@ class User extends SnowFlake {
|
||||||
badgediv.append(badge);
|
badgediv.append(badge);
|
||||||
}
|
}
|
||||||
})();
|
})();
|
||||||
const pfp = await this.buildstatuspfp(guild);
|
const pfp = this.buildstatuspfp(guild);
|
||||||
div.appendChild(pfp);
|
div.appendChild(pfp);
|
||||||
const userbody = document.createElement("div");
|
const userbody = document.createElement("div");
|
||||||
userbody.classList.add("flexttb", "infosection");
|
userbody.classList.add("flexttb", "infosection");
|
||||||
|
|
|
@ -1,8 +1,13 @@
|
||||||
import {memberjson, sdpback, voiceserverupdate, voiceStatus, webRTCSocket} from "./jsontypes.js";
|
import {memberjson, sdpback, voiceserverupdate, voiceStatus, webRTCSocket} from "./jsontypes.js";
|
||||||
class VoiceFactory {
|
class VoiceFactory {
|
||||||
settings: {id: string};
|
settings: {id: string};
|
||||||
constructor(usersettings: VoiceFactory["settings"]) {
|
handleGateway: (obj: Object) => void;
|
||||||
|
constructor(
|
||||||
|
usersettings: VoiceFactory["settings"],
|
||||||
|
handleGateway: VoiceFactory["handleGateway"],
|
||||||
|
) {
|
||||||
this.settings = usersettings;
|
this.settings = usersettings;
|
||||||
|
this.handleGateway = handleGateway;
|
||||||
}
|
}
|
||||||
voices = new Map<string, Map<string, Voice>>();
|
voices = new Map<string, Map<string, Voice>>();
|
||||||
voiceChannels = new Map<string, Voice>();
|
voiceChannels = new Map<string, Voice>();
|
||||||
|
@ -20,19 +25,50 @@ class VoiceFactory {
|
||||||
}
|
}
|
||||||
const urlobj = this.guildUrlMap.get(guildid);
|
const urlobj = this.guildUrlMap.get(guildid);
|
||||||
if (!urlobj) throw new Error("url Object doesn't exist (InternalError)");
|
if (!urlobj) throw new Error("url Object doesn't exist (InternalError)");
|
||||||
const voice = new Voice(this.settings.id, settings, urlobj);
|
const voice = new Voice(this.settings.id, settings, urlobj, this);
|
||||||
this.voiceChannels.set(channelId, voice);
|
this.voiceChannels.set(channelId, voice);
|
||||||
guild.set(channelId, voice);
|
guild.set(channelId, voice);
|
||||||
return voice;
|
return voice;
|
||||||
}
|
}
|
||||||
onJoin = (_voice: Voice) => {};
|
onJoin = (_voice: Voice) => {};
|
||||||
onLeave = (_voice: Voice) => {};
|
onLeave = (_voice: Voice) => {};
|
||||||
|
private imute = false;
|
||||||
|
get mute() {
|
||||||
|
return this.imute;
|
||||||
|
}
|
||||||
|
set mute(s) {
|
||||||
|
const changed = this.imute !== s;
|
||||||
|
this.imute = s;
|
||||||
|
if (this.currentVoice && changed) {
|
||||||
|
this.currentVoice.updateMute();
|
||||||
|
this.updateSelf();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
updateSelf() {
|
||||||
|
if (this.currentVoice && this.currentVoice.open) {
|
||||||
|
this.handleGateway({
|
||||||
|
op: 4,
|
||||||
|
d: {
|
||||||
|
guild_id: this.curGuild,
|
||||||
|
channel_id: this.curChan,
|
||||||
|
self_mute: this.imute,
|
||||||
|
self_deaf: false,
|
||||||
|
self_video: false,
|
||||||
|
flags: 3,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
curGuild?: string;
|
||||||
|
curChan?: string;
|
||||||
joinVoice(channelId: string, guildId: string, self_mute = false) {
|
joinVoice(channelId: string, guildId: string, self_mute = false) {
|
||||||
const voice = this.voiceChannels.get(channelId);
|
const voice = this.voiceChannels.get(channelId);
|
||||||
|
this.mute = self_mute;
|
||||||
if (this.currentVoice && this.currentVoice.ws) {
|
if (this.currentVoice && this.currentVoice.ws) {
|
||||||
this.currentVoice.leave();
|
this.currentVoice.leave();
|
||||||
}
|
}
|
||||||
|
this.curChan = channelId;
|
||||||
|
this.curGuild = guildId;
|
||||||
if (!voice) throw new Error(`Voice ${channelId} does not exist`);
|
if (!voice) throw new Error(`Voice ${channelId} does not exist`);
|
||||||
voice.join();
|
voice.join();
|
||||||
this.currentVoice = voice;
|
this.currentVoice = voice;
|
||||||
|
@ -53,7 +89,7 @@ class VoiceFactory {
|
||||||
voiceStateUpdate(update: voiceStatus) {
|
voiceStateUpdate(update: voiceStatus) {
|
||||||
const prev = this.userMap.get(update.user_id);
|
const prev = this.userMap.get(update.user_id);
|
||||||
console.log(prev, this.userMap);
|
console.log(prev, this.userMap);
|
||||||
if (prev) {
|
if (prev && update.channel_id !== this.curChan) {
|
||||||
prev.disconnect(update.user_id);
|
prev.disconnect(update.user_id);
|
||||||
this.onLeave(prev);
|
this.onLeave(prev);
|
||||||
}
|
}
|
||||||
|
@ -93,10 +129,17 @@ class Voice {
|
||||||
readonly userid: string;
|
readonly userid: string;
|
||||||
settings: {bitrate: number};
|
settings: {bitrate: number};
|
||||||
urlobj: {url?: string; token?: string; geturl: Promise<void>; gotUrl: () => void};
|
urlobj: {url?: string; token?: string; geturl: Promise<void>; gotUrl: () => void};
|
||||||
constructor(userid: string, settings: Voice["settings"], urlobj: Voice["urlobj"]) {
|
owner: VoiceFactory;
|
||||||
|
constructor(
|
||||||
|
userid: string,
|
||||||
|
settings: Voice["settings"],
|
||||||
|
urlobj: Voice["urlobj"],
|
||||||
|
owner: VoiceFactory,
|
||||||
|
) {
|
||||||
this.userid = userid;
|
this.userid = userid;
|
||||||
this.settings = settings;
|
this.settings = settings;
|
||||||
this.urlobj = urlobj;
|
this.urlobj = urlobj;
|
||||||
|
this.owner = owner;
|
||||||
}
|
}
|
||||||
pc?: RTCPeerConnection;
|
pc?: RTCPeerConnection;
|
||||||
ws?: WebSocket;
|
ws?: WebSocket;
|
||||||
|
@ -425,6 +468,7 @@ a=rtcp-mux\r`;
|
||||||
if (!this.ws) return;
|
if (!this.ws) return;
|
||||||
const pair = this.ssrcMap.entries().next().value;
|
const pair = this.ssrcMap.entries().next().value;
|
||||||
if (!pair) return;
|
if (!pair) return;
|
||||||
|
this.onSpeakingChange(this.userid, +this.speaking);
|
||||||
this.ws.send(
|
this.ws.send(
|
||||||
JSON.stringify({
|
JSON.stringify({
|
||||||
op: 5,
|
op: 5,
|
||||||
|
@ -470,6 +514,12 @@ a=rtcp-mux\r`;
|
||||||
}
|
}
|
||||||
console.log(this.reciverMap);
|
console.log(this.reciverMap);
|
||||||
}
|
}
|
||||||
|
updateMute() {
|
||||||
|
if (!this.micTrack) return;
|
||||||
|
this.micTrack.enabled = !this.owner.mute;
|
||||||
|
}
|
||||||
|
mic?: RTCRtpSender;
|
||||||
|
micTrack?: MediaStreamTrack;
|
||||||
async startWebRTC() {
|
async startWebRTC() {
|
||||||
this.status = "Making offer";
|
this.status = "Making offer";
|
||||||
const pc = new RTCPeerConnection();
|
const pc = new RTCPeerConnection();
|
||||||
|
@ -497,14 +547,17 @@ a=rtcp-mux\r`;
|
||||||
console.log(this.recivers);
|
console.log(this.recivers);
|
||||||
};
|
};
|
||||||
const audioStream = await navigator.mediaDevices.getUserMedia({video: false, audio: true});
|
const audioStream = await navigator.mediaDevices.getUserMedia({video: false, audio: true});
|
||||||
for (const track of audioStream.getAudioTracks()) {
|
const [track] = audioStream.getAudioTracks();
|
||||||
//Add track
|
//Add track
|
||||||
|
|
||||||
|
this.setupMic(audioStream);
|
||||||
|
const sender = pc.addTrack(track);
|
||||||
|
this.mic = sender;
|
||||||
|
this.micTrack = track;
|
||||||
|
track.enabled = !this.owner.mute;
|
||||||
|
this.senders.add(sender);
|
||||||
|
console.log(sender);
|
||||||
|
|
||||||
this.setupMic(audioStream);
|
|
||||||
const sender = pc.addTrack(track);
|
|
||||||
this.senders.add(sender);
|
|
||||||
console.log(sender);
|
|
||||||
}
|
|
||||||
for (let i = 0; i < 10; i++) {
|
for (let i = 0; i < 10; i++) {
|
||||||
pc.addTransceiver("audio", {
|
pc.addTransceiver("audio", {
|
||||||
direction: "inactive",
|
direction: "inactive",
|
||||||
|
@ -697,9 +750,12 @@ a=rtcp-mux\r`;
|
||||||
userids = new Map<string, {}>();
|
userids = new Map<string, {}>();
|
||||||
async voiceupdate(update: voiceStatus) {
|
async voiceupdate(update: voiceStatus) {
|
||||||
console.log("Update!");
|
console.log("Update!");
|
||||||
|
if (!this.userids.has(update.user_id)) {
|
||||||
|
this.onMemberChange(update?.member || update.user_id, true);
|
||||||
|
}
|
||||||
this.userids.set(update.user_id, {deaf: update.deaf, muted: update.mute});
|
this.userids.set(update.user_id, {deaf: update.deaf, muted: update.mute});
|
||||||
this.onMemberChange(update?.member || update.user_id, true);
|
|
||||||
if (update.user_id === this.userid && this.open) {
|
if (update.user_id === this.userid && this.open && !(this.status === "Done")) {
|
||||||
if (!update) {
|
if (!update) {
|
||||||
this.status = "bad responce from WS";
|
this.status = "bad responce from WS";
|
||||||
return;
|
return;
|
||||||
|
@ -757,6 +813,8 @@ a=rtcp-mux\r`;
|
||||||
console.warn("leave");
|
console.warn("leave");
|
||||||
this.open = false;
|
this.open = false;
|
||||||
this.status = "Left voice chat";
|
this.status = "Left voice chat";
|
||||||
|
this.onMemberChange(this.userid, false);
|
||||||
|
this.userids.delete(this.userid);
|
||||||
if (this.ws) {
|
if (this.ws) {
|
||||||
this.ws.close();
|
this.ws.close();
|
||||||
this.ws = undefined;
|
this.ws = undefined;
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue