discordjs / discord.js

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

AudioPlayer does not emit 'playing' when AudioResource is a Readable/Stream #8905

Open dzlandis opened 1 year ago

dzlandis commented 1 year ago

Which package is this bug report for?

voice

Issue description

  1. Connect bot to voice channel like normal and create an audio player.
  2. Get an audio stream which is of type Readable.
  3. Create an audio resource by doing createAudioResource(<readable stream here>)
  4. Listen to player.on('playing') or player.on('stateChange')
  5. Observe that the 'playing' event is never emitted despite the audio being played.

Other packages: "@discordjs/opus": "^0.9.0" "sodium-native": "^3.4.1"

Code sample

/******minimal******/
const connection = joinVoiceChannel({
      channelId: voiceChannelId,
      guildId: interaction.guild.id,
      adapterCreator: interaction.guild.voiceAdapterCreator,
      selfDeaf: false
    });
const player = createAudioPlayer();
connection.subscribe(player)
const url = 'audio url'
const res = await fetch(url);
if (!res) return;
const audio = Readable.fromWeb(res.body);
const resource = createAudioResource(audio);
player.play(resource);

player.on(AudioPlayerStatus.Playing, () => {
      console.log('playing event has been emitted') // this will never log
});
/******minimal******/

/******full example******/
const client = new Client({
  intents: [
    Intents.FLAGS.GUILDS,
    Intents.FLAGS.GUILD_VOICE_STATES,
    Intents.FLAGS.GUILD_MEMBERS,
    Intents.FLAGS.GUILD_INTEGRATIONS,
    Intents.FLAGS.GUILD_MESSAGES,
  ],
});

let playAsStream = true;
client.on('messageCreate', (message: Message) => {
  if (message.member?.voice?.channel) {
    const connection = joinVoiceChannel({
      channelId: message.member.voice.channel.id,
      guildId: message.member.voice.guild.id,
      adapterCreator: message.member.voice.guild.voiceAdapterCreator,
      selfDeaf: false,
    });
    const player = createAudioPlayer();
    connection.subscribe(player);
    let resource: AudioResource;
    if (playAsStream) {
      resource = createAudioResource(createReadStream('myPath/to/my/file.mp3'));
      playAsStream = false;
    } else {
      resource = createAudioResource('myPath/to/my/file.mp3');
    }
    player.play(resource);
    player.on('playing', () => {
         console.log('playing event emitted') // this will never log when player is a stream
    })
  }
});

client.login('token');
/******full example******/
// this last full example was taken from a similar issue and modified to showcase this problem

Package version

0.14.0

Node.js version

v18.12.1

Operating system

Windows 10

Priority this issue should have

Medium (should be fixed soon)

Which partials do you have configured?

Not applicable (subpackage bug)

Which gateway intents are you subscribing to?

Guilds, GuildVoiceStates

I have tested this issue on a development release

No response

nyapat commented 1 year ago

is the issue only after playing something else before? your code sample is confusing and doesn't reproduce the bug

dzlandis commented 1 year ago

@nyapat the 'playing' event should be emitted when the bot starts playing something in a voice channel. The issue here is that the event is not being emitted when the stream type is a Readable. In this case, the event is never emitted when the stream type is a Readable. Let me know if there is anything else I can clarify.

MagicPotato21 commented 1 year ago

@dzlandis It looks like the player.on event handler is not being called because it is not attached to the correct object. In the first code snippet, player is defined and assigned to the result of calling createAudioPlayer(). However, in the second code snippet, player is defined and assigned within the messageCreate event handler, so it is not the same object as the one in the first code snippet.

To fix this, you can move the player.on event handler inside the messageCreate event handler so that it is attached to the correct player object. Here is an example of how the code could be modified:

client.on('messageCreate', (message: Message) => { if (message.member?.voice?.channel) { const connection = joinVoiceChannel({ channelId: message.member.voice.channel.id, guildId: message.member.voice.guild.id, adapterCreator: message.member.voice.guild.voiceAdapterCreator, selfDeaf: false, }); const player = createAudioPlayer(); connection.subscribe(player); let resource: AudioResource; if (playAsStream) { resource = createAudioResource(createReadStream('myPath/to/my/file.mp3')); playAsStream = false; } else { resource = createAudioResource('myPath/to/my/file.mp3'); } player.play(resource);

player.on('playing', () => {
  console.log('playing event emitted');
});

} });

This way, the player.on event handler is attached to the player object that is created and used within the messageCreate event handler. This should ensure that the playing event is handled correctly.

dzlandis commented 1 year ago

Hi there @VirginGingerKid

Sorry for the confusion around the examples. The first code snippet I took from my actual code. It is in a command handler environment, and so it should be under, in this case, the interactionCreate event. I shortened it so it would be easier to see what's happening. The second example I took from a similar issue relating to Readable audio streams.

I don't believe the information you have provided will fix my problem.

nyapat commented 1 year ago

I can't repro with the first minimal sample and the second one just never gets to playing, it's closer to the linked issue though imo

dzlandis commented 1 year ago

@nyapat I updated the code slightly, please try again. If you are still unable to reproduce, if you could describe the behavior you see, that would be great.