discords.js voice speaking event not triggering - javascript

I am using discordjs/voice in order to sum up for how long users have talked in the voice channel. So far it never logged an data and I noticed that it is because the client.on('speaking' event is not triggered. I have tried looking for solutions to why that happens but couldn`t find any.
Here is the related piece from my code:
if (msg.content === '!scw start') {
if (!msg.guild) {
msg.channel.send('You\'re currently not in a guild!');
return;
};
msg.channel.send('Please wait a moment while I connect to the VC.')
.catch(error => {
console.log(error);
});
const channel = msg.member.voice.channel
if (channel === undefined) {
msg.channel.send('It seems like you\'re not in a VC.');
return
};
const connection = joinVoiceChannel({
channelId: channel.id,
guildId: channel.guild.id,
adapterCreator: channel.guild.voiceAdapterCreator,
selfDeaf: false
});
msg.channel.send('Success! I\'m now connected and ready to listen.');
var speakers = [];
connection.on('speaking', (user, speaking) => {
// when a user starts speaking:
if (speaking) {
console.log(`${user} started talking`)
// add them to the list of speakers
// start a timer recording how long they're speaking
speakers.push({ user: new Date().getTime() });
// when a user stops speaking:
} else {
console.log(`${user} stopped talking`)
// stop the timer and add it to their total time
var talkTime = (new Date().getTime()) - (stats[user]['timeSpeaking']);
var talkTime = talkTime / 1000;
var talkTime = Math.abs(talkTime);
if (user in stats) {
stats[user]['timeSpeaking'] = stats[user]['timeSpeaking'] + talkTime;
} else {
stats[user] = {
'timeSpeaking': talkTime,
};
};
// remove them from the list of speakers
if (speakers.includes(user)) {
arrayRemove(speakers, user)
};
};
});
connection.on('disconnect', () => {
msg.channel.send('I was disconnected ⁉️.')
.catch(error => {
console.log(error);
});
})
};

Related

Supabase realtime slow and skipping some broadcasts

I'm using supabase realtime channels to build a collaborative editor. I'm using slatejs and I'm broadcasting operations on the channel but the broadcasts appear really slow on other clients and also some of the broadcasts are lost.
This is the main code:
const blockUpdateChannel = supabaseClient.channel(
"block-updates" + DOCUMENT_ID
);
// Applying the received broadcasts to current editor
blockUpdateChannel
.on("broadcast", { event: "blockupdate" }, (event: any) => {
Editor.withoutNormalizing(editor as any, () => {
const operations = event.payload.ops;
operations.forEach((operation: any) => {
console.log(operation);
if (operation.source !== userId) {
editor?.apply(operation);
}
});
});
})
.subscribe();
// sending broadcasts
const ops: any = [];
editor?.operations.forEach((operation: any) => {
var shouldAdd = false;
if (!operation.source) {
if (operation.type !== "set_selection") {
shouldAdd = true;
if (operation.type === "set_node") {
if (operation.newProperties.modifiedByUserId !== undefined) {
shouldAdd = false;
}
}
}
}
if (shouldAdd) {
operation.source = userId;
ops.push(operation);
}
});
if (ops.length) {
console.log("Sending ops", ops);
blockUpdateChannel.send({
type: "broadcast",
event: "blockupdate",
payload: { ops },
});
}
You can debug Supabase Realtime by looking at the (new) Realtime logs at:
https://app.supabase.com/project/YOUR_PROJECT/database/realtime-logs
You can also inspect the websocket frames with Chrome Inspector. There may be some odd messages there. Or you might find that it's disconnecting / reconnecting frequently for some reason.

keep playing the song even if someone else joined the channel

Hello I'm trying to make the bot play specific songs then I want the bot to leave the channel and I made it, but the problem is when someone else joins the channel while the bot is playing it restart playing the songs
client.on('voiceStateUpdate', async (oldState, newState) => {
const channel = client.channels.cache.get('921118985876017217')
if (oldState.channel == null && newState.channel == channel) {
await new Promise(function (resolve , reject) {
resolve(
joinVoiceChannel({
channelId: channel.id,
guildId: newState.guild.id,
adapterCreator: newState.guild.voiceAdapterCreator
}))
let stream = ytdl('https://www.youtube.com/watch?v=TU1i6I1ms6s', {
filter: "audioonly",
fmt: "mp3",
encoderArgs: ['-af', 'bass=g=10'],
})
let secStream = ytdl('https://www.youtube.com/watch?v=wHqKkiHlvJc&list=RDwHqKkiHlvJc&start_radio=1', {
filter: "audioonly",
fmt: "mp3",
encoderArgs: ['-af', 'bass=g=10'],
})
const resource = createAudioResource(stream, {
inputType: StreamType.Arbitrary,
inlineVolume: true,
});
// resource.volume.setVolume(0.5);
const secReasorce = createAudioResource(secStream, {
inputType: StreamType.Arbitrary, /* StreamType.Arbitrary type of the song like mpe */
inlineVolume: true,
});
const player = createAudioPlayer();
player.play(resource)
const connection = getVoiceConnection(oldState.guild.id)
connection.subscribe(player)
player.on(AudioPlayerStatus.Idle, () =>setTimeout(() => {
try{
{player.play(secReasorce)}
}catch{
connection.destroy()
}
}, 3000))
player.on( AudioPlayerStatus.Playing , ()=>{
//I think there will be the solution but I don't know any functions does what I want
} )
})
You have to keep track of whether it's already playing audio or not. Since you're getting the channel based off of an ID; I'm assuming you're only using it in one voice channel. So you could just have a boolean outside of the lambda expression's scope that keeps track of whether it's playing.
If you implement that you'd have something like this:
let isPlaying = false; // Create a variable to keep track of whether it's playing or not.
client.on('voiceStateUpdate', async (oldState, newState) => {
// If it's already playing, return and do nothing.
if (isPlaying) return;
const channel = client.channels.cache.get('921118985876017217')
if (oldState.channel == null && newState.channel == channel) {
await new Promise(function (resolve , reject) {
resolve(
joinVoiceChannel({
channelId: channel.id,
guildId: newState.guild.id,
adapterCreator: newState.guild.voiceAdapterCreator
}))
isPlaying = true; // Bot successfully joined vc, it now begins to play audio.
// Removed code unrelated to the answer so you can more easily see the changes.
player.on(AudioPlayerStatus.Idle, () =>setTimeout(() => {
try{
{player.play(secReasorce)}
}catch{
// I assume this is where you make it disconnect?
// If so, retain the integrity of `isPlaying` by setting it back to false.
isPlaying = false;
connection.destroy()
}
}, 3000))
})```

WebRTC connectionState stuck at "new" - Safari only, works in Chrome and FF

I'm having trouble connecting to my local peer as remote with WebRTC video and audio. This issue is only happening in Safari on desktop and iOS. On Chrome and Firefox the issue is non-existant.
I'm assuming it has something to do with the fact that in Safari, it always asks if you want to allow audio/video but I'm not sure. That's just the only difference I can make out between the browsers. Even after selecting 'allow', the issue persists.
Reproduction steps:
In Chrome, open the initial local connection with audio/video
In Safari, open the remote connection and choose to enable audio/video
Result:
Local connection never makes an offer and the connectionState of the remote (Safari) gets stuck as new. See the following RTCPeerConnection object:
Here is the exact same object via the exact same steps, but in Chrome or Firefox:
Edit:
After more testing, I've found the following:
Below format: (First Connection) > (Second Connection)
Chrome > Chrome: Works
Chrome > Firefox: Works
Chrome > Safari: Doesn't work
Safari > Chrome: Works
Safari > Safari: Works
The issue doesn't seem to exist when using Safari for both sides of the connection...only when Safari is used as the secondary connection.
Here is my code:
import h from './helpers.js';
document.getElementById('close-chat').addEventListener('click', (e) => {
document.querySelector('#right').style.display = "none";
});
document.getElementById('open-chat').addEventListener('click', (e) => {
document.querySelector('#right').style.display = "flex";
});
window.addEventListener('load', () => {
sessionStorage.setItem('connected', 'false');
const room = h.getParam('room');
const user = h.getParam('user');
sessionStorage.setItem('username', user);
const username = sessionStorage.getItem('username');
if (!room) {
document.querySelector('#room-create').attributes.removeNamedItem('hidden');
}
else if (!username) {
document.querySelector('#username-set').attributes.removeNamedItem('hidden');
}
else {
let commElem = document.getElementsByClassName('room-comm');
for (let i = 0; i < commElem.length; i++) {
commElem[i].attributes.removeNamedItem('hidden');
}
var pc = [];
let socket = io('/stream');
var socketId = '';
var myStream = '';
var screen = '';
// Get user video by default
getAndSetUserStream();
socket.on('connect', () => {
console.log('Connected');
sessionStorage.setItem('remoteConnected', 'false');
h.connectedChat();
setTimeout(h.establishingChat, 3000);
setTimeout(h.oneMinChat, 60000);
setTimeout(h.twoMinChat, 120000);
setTimeout(h.threeMinChat, 180000);
setTimeout(h.fourMinChat, 240000);
setTimeout(h.fiveMinChat, 300000);
// Set socketId
socketId = socket.io.engine.id;
socket.emit('subscribe', {
room: room,
socketId: socketId
});
socket.on('new user', (data) => {
// OG user gets log when new user joins here.
console.log('New User');
console.log(data);
socket.emit('newUserStart', { to: data.socketId, sender: socketId });
pc.push(data.socketId);
init(true, data.socketId);
});
socket.on('newUserStart', (data) => {
console.log('New User Start');
console.log(data);
pc.push(data.sender);
init(false, data.sender);
});
socket.on('ice candidates', async (data) => {
console.log('Ice Candidates:');
console.log(data);
data.candidate ? await pc[data.sender].addIceCandidate(new RTCIceCandidate(data.candidate)) : '';
});
socket.on('sdp', async (data) => {
console.log('SDP:');
console.log(data);
if (data.description.type === 'offer') {
data.description ? await pc[data.sender].setRemoteDescription(new RTCSessionDescription(data.description)) : '';
h.getUserFullMedia().then(async (stream) => {
if (!document.getElementById('local').srcObject) {
h.setLocalStream(stream);
}
// Save my stream
myStream = stream;
stream.getTracks().forEach((track) => {
pc[data.sender].addTrack(track, stream);
});
let answer = await pc[data.sender].createAnswer();
await pc[data.sender].setLocalDescription(answer);
socket.emit('sdp', { description: pc[data.sender].localDescription, to: data.sender, sender: socketId });
}).catch((e) => {
console.error(e);
});
}
else if (data.description.type === 'answer') {
await pc[data.sender].setRemoteDescription(new RTCSessionDescription(data.description));
}
});
socket.on('chat', (data) => {
h.addChat(data, 'remote');
});
});
function getAndSetUserStream() {
console.log('Get and set user stream.');
h.getUserFullMedia({ audio: true, video: true }).then((stream) => {
// Save my stream
myStream = stream;
h.setLocalStream(stream);
}).catch((e) => {
console.error(`stream error: ${e}`);
});
}
function sendMsg(msg) {
let data = {
room: room,
msg: msg,
sender: username
};
// Emit chat message
socket.emit('chat', data);
// Add localchat
h.addChat(data, 'local');
}
function init(createOffer, partnerName) {
console.log('P1:');
console.log(partnerName);
pc[partnerName] = new RTCPeerConnection(h.getIceServer());
console.log('P2:');
console.log(pc[partnerName]);
if (screen && screen.getTracks().length) {
console.log('Screen:');
console.log(screen);
screen.getTracks().forEach((track) => {
pc[partnerName].addTrack(track, screen); // Should trigger negotiationneeded event
});
}
else if (myStream) {
console.log('myStream:');
console.log(myStream);
myStream.getTracks().forEach((track) => {
pc[partnerName].addTrack(track, myStream); // Should trigger negotiationneeded event
});
}
else {
h.getUserFullMedia().then((stream) => {
console.log('Stream:');
console.log(stream);
// Save my stream
myStream = stream;
stream.getTracks().forEach((track) => {
console.log('Tracks:');
console.log(track);
pc[partnerName].addTrack(track, stream); // Should trigger negotiationneeded event
});
h.setLocalStream(stream);
}).catch((e) => {
console.error(`stream error: ${e}`);
});
}
// Create offer
if (createOffer) {
console.log('Create Offer');
pc[partnerName].onnegotiationneeded = async () => {
let offer = await pc[partnerName].createOffer();
console.log('Offer:');
console.log(offer);
await pc[partnerName].setLocalDescription(offer);
console.log('Partner Details:');
console.log(pc[partnerName]);
socket.emit('sdp', { description: pc[partnerName].localDescription, to: partnerName, sender: socketId });
};
}
// Send ice candidate to partnerNames
pc[partnerName].onicecandidate = ({ candidate }) => {
console.log('Send ICE Candidates:');
console.log(candidate);
socket.emit('ice candidates', { candidate: candidate, to: partnerName, sender: socketId });
};
// Add
pc[partnerName].ontrack = (e) => {
console.log('Adding partner video...');
let str = e.streams[0];
if (document.getElementById(`${partnerName}-video`)) {
document.getElementById(`${partnerName}-video`).srcObject = str;
}
else {
// Video elem
let newVid = document.createElement('video');
newVid.id = `${partnerName}-video`;
newVid.srcObject = str;
newVid.autoplay = true;
newVid.className = 'remote-video';
newVid.playsInline = true;
newVid.controls = true;
// Put div in main-section elem
document.getElementById('left').appendChild(newVid);
const video = document.getElementsByClassName('remote-video');
}
};
pc[partnerName].onconnectionstatechange = (d) => {
console.log('Connection State:');
console.log(pc[partnerName].iceConnectionState);
switch (pc[partnerName].iceConnectionState) {
case 'new':
console.log('New connection...!');
break;
case 'checking':
console.log('Checking connection...!');
break;
case 'connected':
console.log('Connected with dispensary!');
sessionStorage.setItem('remoteConnected', 'true');
h.establishedChat();
break;
case 'disconnected':
console.log('Disconnected');
sessionStorage.setItem('connected', 'false');
sessionStorage.setItem('remoteConnected', 'false');
h.disconnectedChat();
h.closeVideo(partnerName);
break;
case 'failed':
console.log('Failed');
sessionStorage.setItem('connected', 'false');
sessionStorage.setItem('remoteConnected', 'false');
h.disconnectedChat();
h.closeVideo(partnerName);
break;
case 'closed':
console.log('Closed');
sessionStorage.setItem('connected', 'false');
sessionStorage.setItem('remoteConnected', 'false');
h.disconnectedChat();
h.closeVideo(partnerName);
break;
}
};
pc[partnerName].onsignalingstatechange = (d) => {
switch (pc[partnerName].signalingState) {
case 'closed':
console.log("Signalling state is 'closed'");
h.closeVideo(partnerName);
break;
}
};
}
// Chat textarea
document.getElementById('chat-input').addEventListener('keypress', (e) => {
if (e.which === 13 && (e.target.value.trim())) {
e.preventDefault();
sendMsg(e.target.value);
setTimeout(() => {
e.target.value = '';
}, 50);
}
});
}
});
It would be helpful to see the console logs from a failed (stuck in the "new" state) Safari run.
One possibility is that Safari isn't doing the full ice candidate gathering. As Phillip Hancke noted, seeing the SDP would help figure out if that's happening. As would seeing the console logs. In the past, Safari has had various quirks and bugs related to candidate gathering.
One way to force Safari to gather candidates is to explicitly set offerToReceiveAudio and offerToReceiveVideo:
await pc[partnerName].createOffer({ offerToReceiveAudio: true, offerToReceiveVideo: true })

UnhandledPromiseRejectionWarning: MongoError: Cannot use a session that has ended

I am creating a node.js bot to track how long users have been on a game for. When I run this code sometimes the bot throws an error UnhandledPromiseRejectionWarning: MongoError: Cannot use a session that has ended
I can't see unreachable code or a session that is disconnected before everything has a chance to run. Here is my entire code for the function on a discord presence update:
const mongo = require('./mongo');
const exposeSchema = require('./schemas/expose-schema');
const { general } = require('./config.json');
module.exports = async client => {
client.on('presenceUpdate', async (oldPresence, newPresence) => {
const username = newPresence.user.username;
const guild = newPresence.guild.id;
console.log('Presence update detected:');
console.log(`Guild ID: ${guild} \nUser ID: ${newPresence.user.id} \nUsername: ${username}`);
await mongo().then(async mongoose => {
try {
await exposeSchema.where({ guildid: guild, username: username }).findOne(async function(err, sent) {
if (err) {
console.log(err);
}
if (sent == null) {
console.log('Writing to database');
await exposeSchema({
guildid: guild,
username: username,
sent: false,
}).save();
}
else if (sent.sent == false) {
const act = await newPresence.activities.find(activity => activity.timestamps != null);
if (act) {
const n = new Date();
const g = act.timestamps.start;
const hours = Math.abs(n - g) / 36e5;
if (hours >= 4) {
await exposeSchema.findOneAndUpdate({
guildid: guild,
username: username,
}, {
guildid: guild,
username: username,
sent: true,
}, {
upsert: true,
});
console.log(`${newPresence.user.username} has been playing ${act.name} for ${Math.round(hours)} hours, time to wrap it the fuck up and go outside or get some sleep.`);
if (newPresence.member.nickname == null) {
await client.channels.cache.get(general).send(`${newPresence.user.username} has been playing ${act.name} for ${Math.round((hours) * 100) / 100} hours, time to wrap it the fuck up and go outside or get some sleep.`);
}
else {
await client.channels.cache.get(general).send(`${newPresence.user.nickname} has been playing ${act.name} for ${Math.round((hours) * 100) / 100} hours, time to wrap it the fuck up and go outside or get some sleep.`);
}
}
}
}
});
}
finally {
mongoose.connection.close();
}
});
});
};

Remote video not display using webrtc scaledrone

Hi can someone check is there something wrong with my code cause it not displayig the remote video. The log always return 'Start web RTC as 'offerer'' for both local and remote video. And I think mostly the sample code almost similar with my code so I dont know. Much love appreciate if you guys can help me. Thanks!
if (!location.hash) {
location.hash = Math.floor(Math.random() * 0xFFFFFF).toString(16);
}
const roomHash = location.hash.substring(1);
//const roomHash = '5dfd9b';
console.log("ROOM ID: >> " +roomHash);
// TODO: Replace with your own channel ID
const drone = new ScaleDrone('AUpfMxm16E9bfdgA');
// Room name needs to be prefixed with 'observable-'
//const roomName = 'observable-' + roomHash;
const roomName = 'observable-testPHR';
const configuration = {
iceServers: [{
urls: 'stun:stun.l.google.com:19302'
}]
};
let room;
let pc;
function onSuccess() {
console.log("Connection sucess");
};
function onError(error) {
console.log("Connection failed!");
//console.error(error);
};
drone.on('open', error => {
if (error) {
console.log( " Error open drone >>");
return console.error(error);
}
console.log(" Drone open >>")
room = drone.subscribe(roomName);
room.on('open', error => {
if (error) {
onError(error);
}
});
// We're connected to the room and received an array of 'members'
// connected to the room (including us). Signaling server is ready.
room.on('members', members => {
console.log('MEMBERS', members);
// If we are the second user to connect to the room we will be creating the offer
const isOfferer = members.length === 2;
startWebRTC(isOfferer);
});
});
// Send signaling data via Scaledrone
function sendMessage(message) {
console.log("Sending signal via scaledrone >>");
drone.publish({
room: roomName,
message
});
}
function startWebRTC(isOfferer) {
console.log('Starting WebRTC in as', isOfferer ? 'offerer' : 'waiter');
pc = new RTCPeerConnection(configuration);
console.log(" Test A ");
// 'onicecandidate' notifies us whenever an ICE agent needs to deliver a
// message to the other peer through the signaling server
pc.onicecandidate = event => {
console.log("Send Message to Candidate");
if (event.candidate) {
sendMessage({'candidate': event.candidate});
}
};
console.log(" Test B ");
// If user is offerer let the 'negotiationneeded' event create the offer
if (isOfferer) {
console.log(" Create Offer ");
pc.onnegotiationneeded = () => {
pc.createOffer().then(localDescCreated).catch(onError);
}
}
console.log(" Test C ");
// When a remote stream arrives display it in the #remoteVideo element
pc.ontrack = event => {
console.log("Display remote video >>>")
const stream = event.streams[0];
console.log(" Stream : >>" +stream);
if (!remoteVideo.srcObject || remoteVideo.srcObject.id !== stream.id) {
remoteVideo.srcObject = stream;
}
};
console.log(" Test D ");
navigator.mediaDevices.getUserMedia({
audio: true,
video: true,
}).then(stream => {
console.log(" Display Local Video >> ");
// Display your local video in #localVideo element
localVideo.srcObject = stream;
// Add your stream to be sent to the conneting peer
stream.getTracks().forEach(track => pc.addTrack(track, stream));
}, onError);
console.log(" Test E ");
// Listen to signaling data from Scaledrone
room.on('data', (message, client) => {
// Message was sent by us
if (client.id === drone.clientId) {
return;
}
console.log(" Test F ");
if (message.sdp) {
// This is called after receiving an offer or answer from another peer
pc.setRemoteDescription(new RTCSessionDescription(message.sdp), () => {
// When receiving an offer lets answer it
if (pc.remoteDescription.type === 'offer') {
console.log(" Answer call ");
pc.createAnswer().then(localDescCreated).catch(onError);
}
}, onError);
} else if (message.candidate) {
// Add the new ICE candidate to our connections remote description
pc.addIceCandidate(
new RTCIceCandidate(message.candidate), onSuccess, onError
);
}
});
}
function localDescCreated(desc) {
pc.setLocalDescription(
desc,
() => sendMessage({'sdp': pc.localDescription}),
onError
);
}

Categories