discord.js icon indicating copy to clipboard operation
discord.js copied to clipboard

Output Stream for AudioPlayer

Open DanielBUBU opened this issue 5 months ago • 8 comments

Which application or package is this feature request for?

voice

Feature

I am trying to build a site that can play same music on discord.

  • when AudioPlayer pause, the music on the site pause (site got long keep alive setting so it should be fine)
  • the site can take multiple request at once
  • the stream on the site should able to play on VLC

here's the part of the code I wrote: BufferTransformStream

const { Transform } = require('stream');

const DEFAULT_CAPACITY = 10;

class BufferingTransform extends Transform {
    constructor(options = {}) {
        super(options);

        this.capacity = options.capacity || DEFAULT_CAPACITY;
        this.delay = options.delay || 25
        this.pending = [];

        return;
    }

    get atCapacity() {
        return this.pending.length >= this.capacity;
    }

    _transform(chunk, encoding, cb) {

        if (this.atCapacity) {
            this.push(...this.pending.shift());
        }

        this.pending.push([chunk, encoding]);

        if (cb != undefined) {
            cb();
        }
    }

    _flush(cb) {

        while (this.pending.length > 0) {
            this.push(...this.pending.shift());
        }

        if (cb != undefined) {
            cb();
        }
    }

    _write(chunk, encoding, callback) {
        this.push(chunk);
        setTimeout(callback, this.delay);
    }
    _final() {
        this.push(null)
    }
}

in my class for music processing:

this.port = process.env.PORT + processIndex + 1 || 4000 + processIndex + 1;

        this.expressApp.get('/', (req, res) => {
            console.log("A new connection was made by a client.");
            var bufferStr = new BufferingTransform();
            res.writeHead(200, {
                //'Content-Type': 'video/mp4',
                //"Content-Length": "*",
            });
            bufferStr.on("data", async (data) => {
                //console.log("BufData")
            })
            bufferStr.on("end", async (data) => {
                //console.log("BufEnd")
            })
            res.on('close', () => {
                console.log("Des")
                try {
                    bufferStr.destroy();
                } catch (error) {

                }
            });
            bufferStr.pipe(res);
            this.webAudioStream.pipe(bufferStr);
        })
        while (!this.webListenerSuccessFlag && this.port <= 65535) {
            try {
                this.expressApp.listen(this.port, () => {
                    this.port--;
                    console.log(`ChildProcess ${processIndex} listening on port ${this.port}`)
                }).on('connection', function (socket) {
                        socket.setTimeout(3000 * 1000);
                        // 30 second timeout. Change this as you see fit.
                });
                this.webListenerSuccessFlag = true;
            } catch (error) {
                console.log(error);
            }
            this.port++;
        }

this.webAudioStream is a BufferingTransform object I want data pass from a AudioPlayer object to this.webAudioStream (so music sync with discord)

Ideal solution or implementation

  • Output silence when player is not in AudioPlayerPlayingState instead of close/end the output stream

Method1-Add pipe function

Pipe to another stream and AudioPlayerObject doesn't close when the stream that pipe into is closed

AudioPlayerObject.pipe(BufferingTransformStreamETC1)
BufferingTransformStream.Close();
AudioPlayerObject.pipe(BufferingTransformStreamETC2)

Method2-Pretend it's a connection

Init a VoiceConnection object using a stream, so it can be sub/unsub just like a VoiceConnection

VoiceConnectionObject=joinVoiceChannel({
            stream :BufferingTransform
        })

or

VoiceConnectionObject=createFromStream({
            stream :BufferingTransform
        })

Alternative solutions or implementations

No response

Other context

My target is create a web radio that sync with discord. It can be done if I pipe them like this:

sources=>web radio=>discord audio resource

But the annoying part is that I have to maintain more stuff. And discord audio might be unstable due to the web radio part, in a discord bot project, so it become a tradeoff between reliability and new web radio function for my bot

DanielBUBU avatar Sep 06 '24 07:09 DanielBUBU