2 Commits

Author SHA1 Message Date
Logan Cusano
95c99971a2 Revert to Naudiodon and Update Config
- Changed to .env file
2023-04-30 03:52:20 -04:00
Logan Cusano
b248e7f40e Update debugging
- Uniform client name
2023-04-30 03:29:38 -04:00
14 changed files with 2624 additions and 64 deletions

View File

@@ -1 +1,8 @@
DEBUG="client:*";
DEBUG="client:*"
TOKEN=""
# Bot Config
APPLICATION_ID=""
GUILD_ID=""
# Audio Config
AUDIO_DEVICE_ID="1"
AUDIO_DEVICE_NAME="VoiceMeeter VAIO3 Output (VB-Au"

View File

@@ -1,6 +1,6 @@
// Debug
const { DebugBuilder } = require("../utilities/debugBuilder.js");
const log = new DebugBuilder("client-bot", "leave");
const log = new DebugBuilder("client", "leave");
// Modules
const { SlashCommandBuilder } = require('discord.js');
const { leave } = require("../controllers/commandController")

View File

@@ -1,6 +1,6 @@
// Debug
const { DebugBuilder } = require("../utilities/debugBuilder.js");
const log = new DebugBuilder("client-bot", "status");
const log = new DebugBuilder("client", "status");
// Modules
const { status } = require('../controllers/commandController');
// Utilities

View File

@@ -1,6 +0,0 @@
{
"ApplicationID": "943742040255115304",
"GuildID": "367396189529833472",
"DeviceID": "5",
"DeviceName": "VoiceMeeter Aux Output (VB-Audi"
}

View File

@@ -4,7 +4,7 @@ exports.clientConfig = {
"id": 13,
"name": "boilin balls in the hall",
"ip": "172.16.100.150",
"port": 3001,
"port": 3010,
"location": "the house",
"nearbySystems": ["Westchester Cty. Simulcast"],
"online": true

View File

@@ -1,12 +1,12 @@
// Config
const { getDeviceID } = require('../utilities/configHandler.js');
// Modules
const alsaInstance = require('alsa-capture');
const portAudio = require('naudiodon');
const { returnAlsaDeviceObject } = require("../utilities/executeConsoleCommands.js");
// Debug
const { DebugBuilder } = require("../utilities/debugBuilder.js");
// Global Vars
const log = new DebugBuilder("client-bot", "audioController");
const log = new DebugBuilder("client", "audioController");
/**
* Checks to make sure the selected audio device is available and returns the device object (PortAudio Device Info)
@@ -19,8 +19,13 @@ const log = new DebugBuilder("client-bot", "audioController");
async function confirmAudioDevice({deviceName = undefined, deviceId = undefined}){
const deviceList = await getAudioDevices();
if (!deviceName && !deviceId) throw new Error("No device given");
if (deviceId) return deviceList.find(device => device.id === deviceId);
if (deviceName) return deviceList.find(device => device.name === deviceName);
let confirmedDevice;
if (deviceId) confirmedDevice = deviceList.find(device => device.id === deviceId);
if (deviceName) confirmedDevice = deviceList.find(device => device.name === deviceName);
log.DEBUG("Confirmed Audio Device: ", confirmedDevice);
return confirmedDevice;
}
exports.confirmAudioDevice = confirmAudioDevice;
@@ -31,9 +36,16 @@ exports.confirmAudioDevice = confirmAudioDevice;
*/
async function getAudioDevices(){
// Exec output contains both stderr and stdout outputs
const deviceList = await returnAlsaDeviceObject();
log.DEBUG("Device list: ", deviceList);
//const deviceList = await returnAlsaDeviceObject();
const deviceList = portAudio.getDevices().map((device) => {
if (device.maxInputChannels > 2) {
return device;
}
else {
return null;
}
}).filter(Boolean);
log.VERBOSE("Device List: ", deviceList);
return deviceList;
}
exports.getAudioDevices = getAudioDevices;
@@ -48,6 +60,19 @@ async function createAudioInstance() {
const selectedDevice = await confirmAudioDevice({deviceId: getDeviceID()});//{deviceName: "VoiceMeeter VAIO3 Output (VB-Au"});
log.DEBUG("Device selected from config: ", selectedDevice);
// Create an instance of AudioIO with outOptions (defaults are as below), which will return a WritableStream
return new portAudio.AudioIO({
inOptions: {
channelCount: 2,
sampleFormat: portAudio.SampleFormat16Bit,
sampleRate: 48000,
deviceId: selectedDevice.id, // Use -1 or omit the deviceId to select the default device
closeOnError: true, // Close the stream if an audio error is detected, if set false then just log the error
framesPerBuffer: 20, //(48000 / 1000) * 20, //(48000 * 16 * 2) / 1000 * 20 // (48000 * (16 / 8) * 2) / 60 / 1000 * 20 //0.025 * 48000 / 2
highwaterMark: 3840,
},
});
/*
return new alsaInstance({
channels: 2,
format: "U8",
@@ -57,5 +82,7 @@ async function createAudioInstance() {
periodTime: undefined,
// highwaterMark: 3840
});
*/
}
exports.createAudioInstance = createAudioInstance;

View File

@@ -1,6 +1,6 @@
// Debug
const { DebugBuilder } = require("../utilities/debugBuilder.js");
const log = new DebugBuilder("client-bot", "commandController");
const log = new DebugBuilder("client", "commandController");
// Modules
const { joinVoiceChannel, VoiceConnectionStatus, getVoiceConnection } = require("@discordjs/voice");
const { OpusEncoder } = require("@discordjs/opus");
@@ -31,7 +31,7 @@ exports.join = async function join({interaction= undefined, guildID= undefined,
log.DEBUG("Channel ID: ", channelID)
log.DEBUG("Guild ID: ", guildID)
const voiceConnection = joinVoiceChannel({
const voiceConnection = await joinVoiceChannel({
channelId: channelID,
guildId: guildID,
adapterCreator: guildObj.voiceAdapterCreator,
@@ -41,21 +41,24 @@ exports.join = async function join({interaction= undefined, guildID= undefined,
const audioInstance = await createAudioInstance();
audioInstance.on('audio', (buffer) => {
buffer = Buffer.from(buffer);
log.DEBUG("Audio buffer: ", buffer);
log.VERBOSE("Audio Instance: ", audioInstance);
audioInstance.on('data', buffer => {
//buffer = Buffer.from(buffer);
log.VERBOSE("Audio buffer: ", buffer);
const encodedBuffer = encoder.encode(buffer);
log.DEBUG("Encoded packet: ", encodedBuffer);
// TODO Add a function here to check the volume of either buffer and only play audio to discord when there is audio to be played
voiceConnection.playOpusPacket(encodedBuffer);
})
// Exit the audio handler when the bot disconnects
voiceConnection.on(VoiceConnectionStatus.Destroyed, () => {
audioInstance.close();
audioInstance.quit();
})
if (guildID && callback) callback();
audioInstance.start();
if (guildID && callback) return callback();
else return;
}

2533
Client/package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -3,6 +3,11 @@
"version": "0.0.0",
"private": true,
"main": "app.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"preinstall": "echo preinstall",
"postinstall": "echo postinstall"
},
"dependencies": {
"convert-units": "^2.3.4",
"cookie-parser": "~1.4.4",
@@ -21,6 +26,6 @@
"discord.js": "^14.7.1",
"node-gyp": "^9.3.0",
"libsodium-wrappers": "^0.7.10",
"alsa-capture": "0.3.0"
"naudiodon": "^2.3.6"
}
}

View File

@@ -1,10 +1,26 @@
#!/bin/bash
# Check if the user is root
if [ "$EUID" -ne 0 ]
then echo "Please run as root"
exit
fi
# Check for updates
apt-get update
# Install Node Repo
curl -fsSL https://deb.nodesource.com/setup_current.x | sudo -E bash -
# Update the system
apt-get update
apt-get upgrade -y
# Install the necessary packages
apt-get install -y nodejs npm libopus-dev gcc make alsa-utils libasound2 libasound2-dev libpulse-dev pulseaudio apulse
# Ensure pulse audio is running
pulseaudio
# Install the node packages from the project
npm i

View File

@@ -1,48 +1,36 @@
// Debug
const { DebugBuilder } = require("../utilities/debugBuilder.js");
const log = new DebugBuilder("client-bot", "configController");
const log = new DebugBuilder("client", "configController");
// Modules
const { readFileSync } = require('fs');
const path = require("path");
require('dotenv').config();
function getConfig() {
const botConfigObj = JSON.parse(readFileSync(path.resolve("./config/botConfig.json")))
return botConfigObj;
}
exports.getConfig = getConfig;
const GuildID = process.env.GUILD_ID;
const ApplicationID = process.env.APPLICATION_ID;
const DeviceID = parseInt(process.env.AUDIO_DEVICE_ID);
const DeviceName = process.env.AUDIO_DEVICE_NAME;
function getGuildID() {
const parsedJSON = getConfig();
const guildID = parsedJSON.GuildID;
log.DEBUG("Guild ID: ", guildID);
return guildID;
log.DEBUG("Guild ID: ", GuildID);
return GuildID;
}
exports.getGuildID = getGuildID;
function getApplicationID() {
const parsedJSON = getConfig();
const appID = parsedJSON.ApplicationID;
log.DEBUG("Application ID: ", appID);
return appID;
log.DEBUG("Application ID: ", ApplicationID);
return ApplicationID;
}
exports.getApplicationID = getApplicationID;
function getDeviceID(){
const parsedJSON = getConfig();
const deviceID = parseInt(parsedJSON.DeviceID);
log.DEBUG("Device ID: ", deviceID);
return deviceID;
log.DEBUG("Device ID: ", DeviceID);
return DeviceID;
}
exports.getDeviceID = getDeviceID;
function getDeviceName(){
const parsedJSON = getConfig();
const deviceName = parsedJSON.DeviceName;
log.DEBUG("Device Name: ", deviceName);
return deviceName;
log.DEBUG("Device Name: ", DeviceName);
return DeviceName;
}
exports.getDeviceName = getDeviceID;

View File

@@ -12,6 +12,11 @@ exports.DebugBuilder = class DebugBuilder {
this.INFO = debug(`${appName}:${fileName}:INFO`);
this.DEBUG = debug(`${appName}:${fileName}:DEBUG`);
this.WARN = debug(`${appName}:${fileName}:WARNING`);
this.ERROR = debug(`${appName}:${fileName}:ERROR`);
this.VERBOSE = debug(`${appName}:${fileName}:VERBOSE`);
this.ERROR = (...messageParts) => {
const error = debug(`${appName}:${fileName}:ERROR`);
error(messageParts);
if (process.env.EXIT_ON_ERROR && process.env.EXIT_ON_ERROR > 0) setTimeout(process.exit, process.env.EXIT_ON_ERROR_DELAY ?? 0);
}
}
}

View File

@@ -4,7 +4,7 @@ const { exec } = require("child_process");
// Debug
const { DebugBuilder } = require("../utilities/debugBuilder.js");
// Global Vars
const log = new DebugBuilder("client-bot", "executeConsoleCommands");
const log = new DebugBuilder("client", "executeConsoleCommands");
const execCommand = promisify(exec);

View File

@@ -1,6 +1,6 @@
// Debug
const { DebugBuilder } = require("../utilities/debugBuilder.js");
const log = new DebugBuilder("client-bot", "messageHandler");
const log = new DebugBuilder("client", "messageHandler");
exports.replyToInteraction = async function replyToInteraction(interaction, message){
interaction.reply({ content: message, fetchReply: true })