'Discord js v13 voice recording issue

First of all excuse my horrendous code, I'm trying to make voice recording work in a way where, you type the command =record and the bot joins the channel, plays a file to signify it's there and then record voice in chunks of pcm data which it then combines into one mp3 file which it then sends back to the user.

Problem is, the pcm data comes out as garbage noise, this hasn't happened in discord v12, seems like I'm doing everything according to documentation.

Any ideas what might be wrong there?

'use strict';

import { exec } from 'child_process';
import { createAudioPlayer, createAudioResource, AudioPlayerStatus, AudioReceiveStream } from '@discordjs/voice';
import Discord from 'discord.js';
import fs from 'fs-extra';
import Relaxy from '../Relaxy.js';

const recording_stop_mp3 = createAudioResource('./additions/sounds/stoprecord.mp3');
const recording_start_mp3 = createAudioResource('./additions/sounds/startrecord.mp3');

export default class VoiceFactory {

    /**
     * Handle voice recordings.
     * @param {Relaxy} client 
     */
    constructor(client) {
        this.client = client;
        this.files_to_remove = {};
    }

    async Build(message, thing, thing2) {
        this.Combine(message).then(async() => {

            this.client.player.getQueue(message.guild.id).destroy(true);

            let count = null;

            try {
                count = fs.readdirSync(`./logs/saved_recordings/${message.guild.id}`).length;
            } catch { return this.client.build.error('Something went wrong!', message); };

            return this.client.send(message.channel, null, [{ color: '#FF69B4', description: `**${message.member}**, your recording is being processed!` }])
                .then(async(msg) => {
                    return new Promise(async() => {
                        let filePath = `./logs/saved_recordings/${message.guild.id}/${message.guild.id}_output${count}.mp3`,
                            file_too_large_flag,
                            err_flag = false;

                        exec(`ffmpeg -f s16le -ar 48000 -ac 2 -i ./logs/recordings/${message.guild.id}/${message.guild.id}.pcm ${filePath}`, (e) => {
                            if (e) {
                                err_flag = true;
                                return this.client.build.error('Something went wrong while fetching the file :/', msg);
                            }
                        });

                        if (err_flag) return;

                        let watchForFile = setInterval(() => {
                            if (fs.existsSync(filePath)) {

                                clearInterval(watchForFile);

                                watchForFile = null;
                                file_too_large_flag = true;

                                return setTimeout(async() => {
                                    return this.client.send(msg.channel, `${message.member}, here is your recording! ${thing?'(Ended due to exceeding the 8mb limit)' : ''}${thing2?'(Ended due to getting server deadfend)' : ''}`, null, [new Discord.MessageAttachment(filePath, 'recording.mp3')])
                                        .catch(() => { return this.client.build.error('FileTooLarge', message) }).then(async() => {

                                            msg.delete();

                                            fs.unlinkSync(filePath);

                                            fs.emptyDir(`./logs/recordings/${message.guild.id}`, async () => {});

                                            return;
                                        });
                                }, 500);
                            }
                        }, 100);

                        if (file_too_large_flag) return;

                        return setTimeout(() => {

                            if (file_too_large_flag) return;

                            clearInterval(watchForFile);

                            return this.client.build.error('Something went wrong!', message);
                        }, 5000);
                    });
                });
        });
    }

    Combine(message) {
        let chunks = null,
            input_stream = null,
            current_file = null,
            output_stream = null;

        try {
            chunks = fs.readdirSync(`./logs/recordings/${message.guild.id}/`);
            output_stream = fs.createWriteStream(`./logs/recordings/${message.guild.id}/${message.guild.id}.pcm`);
        } catch (error) { return this.client.build.error('Something went wrong!', message); };

        chunks.sort(async(a, b) => { return a - b });

        return this.AppendFiles(chunks, input_stream, current_file, output_stream, message);
    }

    async AppendFiles(chunks, input_stream, current_file, output_stream, message) {
        if (!chunks.length)
            return output_stream.end();

        current_file = `./logs/recordings/${message.guild.id}/` + chunks.shift(), input_stream = fs.createReadStream(current_file);

        input_stream.pipe(output_stream, { end: false });

        input_stream.on('end', async() => {
            return this.AppendFiles(chunks, input_stream, current_file, output_stream, message);
        });
    }

    async Record(message) {
        if (!message.member.voice.channel || message.member.voice.channel.type !== 'GUILD_VOICE') 
            return this.client.build.error('Invalid/no vc to connect to!', message);

        let queue = this.client.player.getQueue(message.guild.id);

        if (!queue) {
            queue = this.client.player.createQueue(message, await this.client.db.Guild(message.guild.id), { autoSelfDeaf: false });

            await queue.connect(message.member.voice.channel);

            if (message.guild.me.voice.serverDeaf)
                return this.client.build.error('Cannot record while server deafend!', message);

            queue.setState('recording');
        } else if (queue.state !== 'idle') return this.client.build.error('ActiveQueue', message);

        this.client.build.error(`description Now recording in **${message.member.voice.channel}** bound from ${message.channel}!`, message);

        this.files_to_remove[message.guild.id] = [];
        this.files_to_remove[`${message.guild.id}player`] = createAudioPlayer();

        if (!fs.existsSync(`./logs/recordings/${message.guild.id}`))
            fs.mkdirSync(`./logs/recordings/${message.guild.id}`);

        if (!fs.existsSync(`./logs/saved_recordings/${message.guild.id}`))
            fs.mkdirSync(`./logs/saved_recordings/${message.guild.id}`);

        fs.emptyDir(`./logs/recordings/${message.guild.id}/`, async () => {});

        queue.connection.voiceConnection.subscribe(this.files_to_remove[`${message.guild.id}player`]);

        this.files_to_remove[`${message.guild.id}player`].play(recording_start_mp3);

        let file_too_large_flag = false;

        try {
            if (message.guild.me.voice.serverDeaf) {
                fs.unlinkSync(`./logs/recordings/${message.guild.id}/${this.files_to_remove[message.guild.id][count]}.pcm`);
                return this.Halt(message, null, 'example');
            }
        } catch {};

        queue.connection.voiceConnection.receiver.speaking.on('start', async(userID) => {
            let count = 0;

            if (!file_too_large_flag && this.files_to_remove[`${message.guild.id}player`]) {

                /** @type {AudioReceiveStream} */
                const audioStream = queue.connection.voiceConnection.receiver.subscribe(userID);

                let current_date_ms = Date.now();

                this.files_to_remove[message.guild.id].push(current_date_ms);

                audioStream.pipe(fs.createWriteStream(`./logs/recordings/${message.guild.id}/${current_date_ms}.pcm`));

                audioStream.on("error", () => {});

                return audioStream.on('end', () => {

                    let sum = 0;

                    for (const file of fs.readdirSync(`./logs/recordings/${message.guild.id}`)) {

                        try {
                            sum += fs.statSync(`./logs/recordings/${message.guild.id}/${file}`).size / (1024 * 1024);
                        } catch {};

                        if (sum >= 7.8) {
                            file_too_large_flag = true;
                            fs.unlinkSync(`./logs/recordings/${message.guild.id}/${this.files_to_remove[message.guild.id][count]}.pcm`);
                            return this.Halt(message, 'example');
                        }

                        count++;
                    }
                })
            }
        })
    }

    async Halt(message, thing, thing2) {
        let queue = this.client.player.getQueue(message.guild.id);

        if (!(
                message &&
                message.guild &&
                message.guild.voice &&
                message.guild.voice.channel &&
                message.guild.voice.connection || !queue.state !== 'recording'
            )) return this.client.build.error('Nothing\'s being recorded!', message);

        this.files_to_remove[message.guild.id] = [];
        this.files_to_remove[`${message.guild.id}player`].play(recording_stop_mp3);

        queue.connection.voiceConnection.subscribe(this.files_to_remove[`${message.guild.id}player`]);

        try {
            guild.me.voice.disconnect();
        } catch {};

        this.files_to_remove[`${message.guild.id}player`].on(AudioPlayerStatus.Idle, () => {
            this.files_to_remove[`${message.guild.id}player`] = null;
            return this.Build(message, thing, thing2);
        });
    }
}

I might be going offline soon but I'll check all replies when I'm back.



Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source