discordjs / discord.js

A powerful JavaScript library for interacting with the Discord API
https://discord.js.org
Apache License 2.0
25.36k stars 3.97k forks source link

Long delay after playing audio files with playFile() #2461

Closed ggresillion closed 6 years ago

ggresillion commented 6 years ago

Please describe the problem you are having in as much detail as possible: After playing some little files (~10), long delays occurs using the method playFile(). This delay is getting bigger and bigger as I keep playing files. My songs are located in $songsDir/category/ Notice that the callback on('end') is triggered close to immediately after the function call, and even before the songs starts to play. I am testing this code with only one connection, so the connection number is not the issue. I am running on a raspberry pi but I'm getting the same issue on my local machine.

Include a reproducible code sample here, if possible:

play(category, song) {
        if (this.connections.length === 0) {
            throw new Error('No connection !');
        }
        const dir = songsDir + category;
        fs.readdir(dir, (err, items) => {
            const filepath = dir + '/' + items.find((el) => {
                return el.toString().startsWith(song);
            });
            fs.stat(filepath, (err, stats) => {
                if (stats) {
                    this.connections.forEach((con) => {
                        let dispatcher = con.playFile(filepath);
                        dispatcher.on('end', () => {
                            console.log('Song ' + song + ' played !');
                        });
                    });
                }
                else {
                    throw new Error('No such song !');
                }

            });
        });
    }

Further details:

amishshah commented 6 years ago

Hi,

I know it's not exactly ideal but could you update your discord.js to the master version and test again? There has been a pretty major voice rewrite and hopefully that fixes your issue.

I also noticed that you're running on a Pi, to ensure best performance I'd recommend converting your audio files to .ogg files containing Opus (free tools online to do this) and then specifying, in the latest master version, connection.play('audio.ogg', { type: 'ogg/opus' }). This should really improve your performance because FFmpeg will no longer be required!

Thanks for reporting this issue, hopefully this can fix it for you.

ggresillion commented 6 years ago

Alright, I will use the master branch and convert my files to .ogg. Thanks for your help, I keep you informed.

jmcountryman commented 6 years ago

I'm experiencing both of these issues as well (first the end event being fired instantly after calling play, and now it not firing at all, both with no audio actually being played), initially using a .mp3 with v11.3.0 and v11.3.2, then with both a .mp3 and .ogg on master.

I did some rudimentary debugging (I'm not super familiar with Node, so this just amounts to placing some console.log calls in various places with a local clone of discord.js); as best as I can tell, StreamDispatcher._write is never being called, despite both BasePlayer.createDispatcher and streams.opus.pipe(dispatcher) succeeding.

Interestingly, this was working yesterday, and I even went back a few commits in my project to make sure. The code that was working yesterday in both my development and "production" environments is now only working in "production". My package.json and yarn.lock have not changed since last month, except for when I tried different versions of discord.js today while "debugging".

fatchan commented 6 years ago

I faced this issue at one point and remembered this workaround from https://github.com/discordjs/discord.js/issues/1693#issuecomment-317301023

dispatcher.on('start', () => {
    connection.player.streamingData.pausedTime = 0;
});

If you log the pausedtime on each end event, you will notce it gets larger and larger. before any song plays, it waits for this delay before starting. sounds exactly like the issue you're facing. I think it only happens if you are pausing/resuming, which you didnt show in the code sample, but if its a music bot chances are you have pause/resume commands. Might be worth a shot.

...Or try master

CorySanin commented 6 years ago

I just tried the new connection.play method from the latest master version, and I get the following: caught: Error [VOICE_PRISM_DEMUXERS_NEED_STREAM]: To play a webm/ogg stream, you need to pass a ReadableStream.

If connection.play requires a stream, what's the difference between connection.play and connection.playOpusStream? Am I thinking about this the right way?

Also, after getting it all set up, starting the playback of an audio stream takes way longer. I would think it would have less processing to do and would therefore start up faster, but that doesn't seem to be the case. Is this a predictable tradeoff or did I set it up wrong?

amishshah commented 6 years ago

@CorySanin what system are you running on and what Node.js version do you have?

CorySanin commented 6 years ago

Windows 10, and the latest master branch as of 21 hours ago.

amishshah commented 6 years ago

I meant Node.js version, not Discord.js version, I doubt it would make much of a difference but it's nice to know when debugging :+1:

CorySanin commented 6 years ago

oh oops. 8.9.3. And it looks like it's the 64-bit binary.

amishshah commented 6 years ago

Ok cool, could you try playing with: connection.play(stream, { highWaterMark: 1 })?

CorySanin commented 6 years ago

That works a lot better! Sometimes my bot is a bit slow to connect, but when it connects it plays the stream right away. And no more depending on ffmpeg, which is nice.

actually, after having success with { highWaterMark: 1 }, I switched back to { type: 'ogg/opus' } and that seems to be working better now too. Maybe it was just a fluke yesterday.

amishshah commented 6 years ago

Awesome! :smile: the highWaterMark option means that Discord.js will create fewer packets ahead of time, maybe it was just taking too long to make the initial 12 packets or something. Either way, that's great to hear!

amishshah commented 6 years ago

@jmcountryman not sure if it would help your particular issue, but does connection.play(stream, { highWaterMark: 1 }) help?

jmcountryman commented 6 years ago

Unfortunately highWaterMark doesn't help; with or without, it "finishes" playing the audio right away.

(Pictured: The first two log calls happen just before calling play, and the second two happen in player.on('end', ...). No time passes between the two events, despite the audio file being 5 seconds long.) image

jmcountryman commented 6 years ago

It looks like my issue is related to ffmpeg-binaries—that package works fine on my EC2 instance, but on OS X it causes this issue. If I replace ffmpeg-binaries with the ffmpeg from Homebrew, it works just fine. Sorry for the trouble!

amishshah commented 6 years ago

No problem! Glad this is sorted out. Is this issue ok to be closed?

jmcountryman commented 6 years ago

I can't speak for @ggresillion, but I'm all set.

amishshah commented 6 years ago

Seems to be inactive, I'm going to assume this issue has been fixed and close it. If it's still occurring after the above advice, please reopen.