lavalink-devs / Lavalink

Standalone audio sending node based on Lavaplayer.
https://lavalink.dev/
MIT License
1.58k stars 669 forks source link

Lavalink Server Not Outputting Audio On Windows #455

Closed Lunas12 closed 3 years ago

Lunas12 commented 3 years ago

Description

<I have made a discord.py music bot that uses wavelink to interact with the server and was working perfectly up until about a 4 hours ago when unprompted it no longer streams music to discord despite it searching for and loading the song>

Version info

Wavelink:

Output of java -version:

(Open jdk 13.0.2)
freyacodes commented 3 years ago

Post logs.

Searching and loading songs is not enough. You also have to play them and send a voice server update.

Lunas12 commented 3 years ago

2021-03-16 22:11:53.633 INFO 16800 --- [ main] lavalink.server.Launcher :

←[32m . ←[31m ←[32m ←[32m /\ ←[31m| | ____ | () | | ←[32m\ \ \ \ ←[32m ( ( )←[31m| |/ ` \ \ / / ` | | | ' | |/ /←[32m \ \ \ \ ←[32m \/ ←[31m| | (| |\ V / (| | | | | | | < ←[32m ) ) ) ) ←[32m ' ←[31m||_,| _/ \,|||| |||_\←[32m / / / / ←[0m =========================================←[32m///_/←[0m

    Version:        8be3fec7084caa2659e92c28f1f43070fcb84dcd-SNAPSHOT
    Build:          1209
    Build time:     17.02.2021 23:24:14 UTC
    Branch          master
    Commit:         8be3fec
    Commit time:    17.02.2021 23:18:16 UTC
    JVM:            13.0.2
    Lavaplayer      1.3.65

2021-03-16 22:11:53.737 INFO 16800 --- [ main] lavalink.server.Launcher : Starting Launcher on DESKTOP-50QVGAL with PID 16800 (C:\Users\olive\OneDrive\Desktop\Music Bot\openjdk-13.0.2_windows-x64_bin\jdk-13.0.2\bin\Lavalink.jar started by olive in C:\Users\olive\OneDrive\Desktop\Music Bot\openjdk-13.0.2_windows-x64_bin\jdk-13.0.2\bin) 2021-03-16 22:11:53.738 INFO 16800 --- [ main] lavalink.server.Launcher : No active profile set, falling back to default profiles: default 2021-03-16 22:11:53.857 WARN 16800 --- [kground-preinit] o.s.h.c.j.Jackson2ObjectMapperBuilder : For Jackson Kotlin classes support please add "com.fasterxml.jackson.module:jackson-module-kotlin" to the classpath 2021-03-16 22:11:55.079 WARN 16800 --- [ main] io.undertow.websockets.jsr : UT026010: Buffer pool was not set on WebSocketDeploymentInfo, the default pool will be used 2021-03-16 22:11:55.107 INFO 16800 --- [ main] io.undertow.servlet : Initializing Spring embedded WebApplicationContext 2021-03-16 22:11:55.107 INFO 16800 --- [ main] o.s.web.context.ContextLoader : Root WebApplicationContext: initialization completed in 1319 ms 2021-03-16 22:11:55.465 WARN 16800 --- [ main] l.server.config.SentryConfiguration : Turning off sentry 2021-03-16 22:11:55.726 INFO 16800 --- [ main] c.s.d.l.tools.GarbageCollectionMonitor : GC monitoring enabled, reporting results every 2 minutes. 2021-03-16 22:11:56.126 INFO 16800 --- [ main] lavalink.server.config.KoeConfiguration : OS: Windows 10, Arch: amd64 2021-03-16 22:11:56.127 WARN 16800 --- [ main] lavalink.server.config.KoeConfiguration : This system and architecture appears to not support native audio sending! GC pauses may cause your bot to stutter during playback. 2021-03-16 22:11:56.378 INFO 16800 --- [ main] o.s.s.concurrent.ThreadPoolTaskExecutor : Initializing ExecutorService 'applicationTaskExecutor' 2021-03-16 22:11:56.643 INFO 16800 --- [ main] org.xnio : XNIO version 3.3.8.Final 2021-03-16 22:11:56.654 INFO 16800 --- [ main] org.xnio.nio : XNIO NIO Implementation Version 3.3.8.Final 2021-03-16 22:11:56.719 INFO 16800 --- [ main] o.s.b.w.e.u.UndertowServletWebServer : Undertow started on port(s) 2333 (http) with context path '' 2021-03-16 22:11:56.723 INFO 16800 --- [ main] lavalink.server.Launcher : Started Launcher in 3.527 seconds (JVM running for 3.963) 2021-03-16 22:11:56.725 INFO 16800 --- [ main] lavalink.server.Launcher : You can safely ignore the big red warning about illegal reflection. See https://github.com/Frederikam/Lavalink/issues/295 2021-03-16 22:12:00.553 INFO 16800 --- [ XNIO-1 task-1] io.undertow.servlet : Initializing Spring DispatcherServlet 'dispatcherServlet' 2021-03-16 22:12:00.554 INFO 16800 --- [ XNIO-1 task-1] o.s.web.servlet.DispatcherServlet : Initializing Servlet 'dispatcherServlet' 2021-03-16 22:12:00.562 INFO 16800 --- [ XNIO-1 task-1] o.s.web.servlet.DispatcherServlet : Completed initialization in 7 ms 2021-03-16 22:12:00.583 INFO 16800 --- [ XNIO-1 task-1] l.server.io.HandshakeInterceptorImpl : Incoming connection from /127.0.0.1:50908 2021-03-16 22:12:00.647 INFO 16800 --- [ XNIO-1 task-1] lavalink.server.io.SocketServer : Connection successfully established from /127.0.0.1:50908 2021-03-16 22:12:12.533 INFO 16800 --- [ XNIO-1 task-2] l.server.player.AudioLoaderRestHandler : Got request to load for identifier "ytsearch:heat waves" 2021-03-16 22:12:13.450 INFO 16800 --- [ader-2-thread-1] lavalink.server.player.AudioLoader : Loaded playlist Search results for: heat waves 2021-03-16 22:12:17.442 INFO 16800 --- [ XNIO-1 I/O-4] lavalink.server.io.SocketServer : {"op": "play", "guildId": "732912297823043615", "track": "QAAAjwIAKEdsYXNzIEFuaW1hbHMgLSBIZWF0IFdhdmVzIChMeXJpYyB2aWRlbykADUdsYXNzIEFuaW1hbHMAAAAAAAOlmAALS1Q3RjE1VDlWQkkAAQAraHR0cHM6Ly93d3cueW91dHViZS5jb20vd2F0Y2g/dj1LVDdGMTVUOVZCSQAHeW91dHViZQAAAAAAAAAA", "noReplace": false, "startTime": "0"}

it does this then never outputs any audio to the vc it was working perfectly for over a week straight and just stopped about 4hrs ago with out a single line of code being touched

devoxin commented 3 years ago

There's no voiceUpdate payload in your logs so that would probably be why.

Lunas12 commented 3 years ago

There's no voiceUpdate payload in your logs so that would probably be why.

Thanks for the reply, how would i impliment it into my code i looked at my repositary for the code which was working but is an a outdated version of the current bot and there is no mention of it any where other than the code the disconnects the bot if the vc is empty...

Lunas12 commented 3 years ago

import asyncio import datetime as dt import random import re import typing as t from enum import Enum

import discord import wavelink from discord.ext import commands

URL_REGEX = r"(?i)\b((?:https?://|www\d{0,3}[.]|[a-z0-9.-]+[.][a-z]{2,4}/)(?:[^\s()<>]+|(([^\s()<>]+|(([^\s()<>]+)))))+(?:(([^\s()<>]+|(([^\s()<>]+))))|[^\s`!()[]{};:'\".,<>?«»“”‘’]))" OPTIONS = { "1️⃣": 0, "2⃣": 1, "3⃣": 2, "4⃣": 3, "5⃣": 4, }

class AlreadyConnectedToChannel(commands.CommandError): pass

class NoVoiceChannel(commands.CommandError): pass

class QueueIsEmpty(commands.CommandError): pass

class NoTracksFound(commands.CommandError): pass

class PlayerIsAlreadyPaused(commands.CommandError): pass

class NoMoreTracks(commands.CommandError): pass

class NoPreviousTracks(commands.CommandError): pass

class InvalidRepeatMode(commands.CommandError): pass

class RepeatMode(Enum): NONE = 0 ONE = 1 ALL = 2

class Queue: def init(self): self._queue = [] self.position = 0 self.repeat_mode = RepeatMode.NONE

@property
def is_empty(self):
    return not self._queue

@property
def current_track(self):
    if not self._queue:
        raise QueueIsEmpty

    if self.position <= len(self._queue) - 1:
        return self._queue[self.position]

@property
def upcoming(self):
    if not self._queue:
        raise QueueIsEmpty

    return self._queue[self.position + 1:]

@property
def history(self):
    if not self._queue:
        raise QueueIsEmpty

    return self._queue[:self.position]

@property
def length(self):
    return len(self._queue)

def add(self, *args):
    self._queue.extend(args)

def get_next_track(self):
    if not self._queue:
        raise QueueIsEmpty

    self.position += 1

    if self.position < 0:
        return None
    elif self.position > len(self._queue) - 1:
        if self.repeat_mode == RepeatMode.ALL:
            self.position = 0
        else:
            return None

    return self._queue[self.position]

def shuffle(self):
    if not self._queue:
        raise QueueIsEmpty

    upcoming = self.upcoming
    random.shuffle(upcoming)
    self._queue = self._queue[:self.position + 1]
    self._queue.extend(upcoming)

def set_repeat_mode(self, mode):
    if mode == "none":
        self.repeat_mode = RepeatMode.NONE
    elif mode == "1":
        self.repeat_mode = RepeatMode.ONE
    elif mode == "all":
        self.repeat_mode = RepeatMode.ALL

def empty(self):
    self._queue.clear()
    self.position = 0

class Player(wavelink.Player): def init(self, *args, *kwargs): super().init(args, **kwargs) self.queue = Queue()

async def connect(self, ctx, channel=None):
    if self.is_connected:
        raise AlreadyConnectedToChannel

    if (channel := getattr(ctx.author.voice, "channel", channel)) is None:
        raise NoVoiceChannel

    await super().connect(channel.id)
    return channel

async def teardown(self):
    try:
        await self.destroy()
    except KeyError:
        pass

async def add_tracks(self, ctx, tracks):
    if not tracks:
        raise NoTracksFound

    if isinstance(tracks, wavelink.TrackPlaylist):
        self.queue.add(*tracks.tracks)
    elif len(tracks) == 1:
        self.queue.add(tracks[0])
        await ctx.send(f"Added {tracks[0].title} to the queue.")
    else:
        if (track := await self.choose_track(ctx, tracks)) is not None:
            self.queue.add(track)
            await ctx.send(f"Added {track.title} to the queue.")

    if not self.is_playing and not self.queue.is_empty:
        await self.start_playback()

async def choose_track(self, ctx, tracks):
    def _check(r, u):
        return (
            r.emoji in OPTIONS.keys()
            and u == ctx.author
            and r.message.id == msg.id
        )

    embed = discord.Embed(
        title="Choose a song",
        description=(
            "\n".join(
                f"**{i+1}.** {t.title} ({t.length//60000}:{str(t.length%60).zfill(2)})"
                for i, t in enumerate(tracks[:5])
            )
        ),
        colour=ctx.author.colour,
        timestamp=dt.datetime.utcnow()
    )
    embed.set_author(name="Query Results")
    embed.set_footer(text=f"Invoked by {ctx.author.display_name}", icon_url=ctx.author.avatar_url)

    msg = await ctx.send(embed=embed)
    for emoji in list(OPTIONS.keys())[:min(len(tracks), len(OPTIONS))]:
        await msg.add_reaction(emoji)

    try:
        reaction, _ = await self.bot.wait_for("reaction_add", timeout=60.0, check=_check)
    except asyncio.TimeoutError:
        await msg.delete()
        await ctx.message.delete()
    else:
        await msg.delete()
        return tracks[OPTIONS[reaction.emoji]]

async def start_playback(self):
    await self.play(self.queue.current_track)

async def advance(self):
    try:
        if (track := self.queue.get_next_track()) is not None:
            await self.play(track)
    except QueueIsEmpty:
        pass

async def repeat_track(self):
    await self.play(self.queue.current_track)

class Music(commands.Cog, wavelink.WavelinkMixin): def init(self, bot): self.bot = bot self.wavelink = wavelink.Client(bot=bot) self.bot.loop.create_task(self.start_nodes())

@commands.Cog.listener()
async def on_voice_state_update(self, member, before, after):
    if not member.bot and after.channel is None:
        if not [m for m in before.channel.members if not m.bot]:
            await self.get_player(member.guild).teardown()

@wavelink.WavelinkMixin.listener()
async def on_node_ready(self, node):
    print(f" Wavelink node `{node.identifier}` ready.")

@wavelink.WavelinkMixin.listener("on_track_stuck")
@wavelink.WavelinkMixin.listener("on_track_end")
@wavelink.WavelinkMixin.listener("on_track_exception")
async def on_player_stop(self, node, payload):
    if payload.player.queue.repeat_mode == RepeatMode.ONE:
        await payload.player.repeat_track()
    else:
        await payload.player.advance()

async def cog_check(self, ctx):
    if isinstance(ctx.channel, discord.DMChannel):
        await ctx.send("Music commands are not available in DMs.")
        return False

    return True

async def start_nodes(self):
    await self.bot.wait_until_ready()

    nodes = {
        "MAIN": {
            "host": "127.0.0.1",
            "port": 2333,
            "rest_uri": "http://127.0.0.1:2333",
            "password": "youshallnotpass",
            "identifier": "MAIN",
            "region": "europe",
        }
    }

    for node in nodes.values():
        await self.wavelink.initiate_node(**node)

def get_player(self, obj):
    if isinstance(obj, commands.Context):
        return self.wavelink.get_player(obj.guild.id, cls=Player, context=obj)
    elif isinstance(obj, discord.Guild):
        return self.wavelink.get_player(obj.id, cls=Player)
@commands.command(name="connect", aliases=["join"])
async def connect_command(self, ctx, *, channel: t.Optional[discord.VoiceChannel]):
    player = self.get_player(ctx)
    channel = await player.connect(ctx, channel)
    await ctx.send(f"Connected to {channel.name}.")

@connect_command.error
async def connect_command_error(self, ctx, exc):
    if isinstance(exc, AlreadyConnectedToChannel):
        await ctx.send("Already connected to a voice channel.")
    elif isinstance(exc, NoVoiceChannel):
        await ctx.send("No suitable voice channel was provided.")

@commands.command(name="disconnect", aliases=["leave"])
async def disconnect_command(self, ctx):
    player = self.get_player(ctx)
    await player.teardown()
    await ctx.send("Disconnected.")

@commands.command(name="play", aliases=["p"])
async def play_command(self, ctx, *, query: t.Optional[str]):
    player = self.get_player(ctx)

    if not player.is_connected:
        await player.connect(ctx)

    if query is None:
        if player.queue.is_empty:
            raise QueueIsEmpty

        await player.set_pause(False)
        await ctx.send("Playback resumed.")

    else:
        query = query.strip("<>")
        if not re.match(URL_REGEX, query):
            query = f"ytsearch:{query}"

        await player.add_tracks(ctx, await self.wavelink.get_tracks(query))

@play_command.error
async def play_command_error(self, ctx, exc):
    if isinstance(exc, QueueIsEmpty):
        await ctx.send("No songs to play as the queue is empty.")
    elif isinstance(exc, NoVoiceChannel):
        await ctx.send("No suitable voice channel was provided.")

@commands.command(name="pause")
async def pause_command(self, ctx):
    player = self.get_player(ctx)

    if player.is_paused:
        raise PlayerIsAlreadyPaused

    await player.set_pause(True)
    await ctx.send("Playback paused.")

@pause_command.error
async def pause_command_error(self, ctx, exc):
    if isinstance(exc, PlayerIsAlreadyPaused):
        await ctx.send("Already paused.")

@commands.command(name="stop")
async def stop_command(self, ctx):
    player = self.get_player(ctx)
    player.queue.empty()
    await player.stop()
    await ctx.send("Playback stopped.")

@commands.command(name="previous")
async def previous_command(self, ctx):
    player = self.get_player(ctx)

    if not player.queue.history:
        raise NoPreviousTracks

    player.queue.position -= 2
    await player.stop()
    await ctx.send("Playing previous track in queue.")

@previous_command.error
async def previous_command_error(self, ctx, exc):
    if isinstance(exc, QueueIsEmpty):
        await ctx.send("This could not be executed as the queue is currently empty.")
    elif isinstance(exc, NoPreviousTracks):
        await ctx.send("There are no previous tracks in the queue.")

@commands.command(name="volume", aliases=["vol"])
async def volume_command(self, ctx, volume: t.Optional[t.Union[int, str]]):
    player = self.get_player(ctx)

    if volume is None:
        return await ctx.send(f"The volume is currently set at {player.volume // 10}%.")

    if isinstance(volume, int):
        if not 0 <= volume <= 150:
            raise VolumeOutOfBounds

        await player.set_volume(volume)
        return await ctx.send(f"The volume has been set to {volume}%.")

    if isinstance(volume, str):
        if volume.lower() in ("up", "+"):
            await player.set_volume(min(player.volume + 10, 150))
            return await ctx.send(f"The volume has been set to {volume}%.")
        elif volume.lower() in ("down", "-"):
            await player.set_volume(min(player.volume - 10))
            return await ctx.send(f"The volume has been set to {volume}%.") 
        else:
            raise InvalidVolumeInstruction

@volume_command.error
async def volume_command_error(self, ctx, exc):
    if isinstance(exc, VolumeOutOfBounds):
        await ctx.send("Sorry the volume can only be set between 0 and 150 percent")
    elif isinstance(exc, InvalidVolumeInstruction):
        await ctx.send("You must specify a volume or use 'up', 'down', '+', '-',")

@commands.command(name="shuffle")
async def shuffle_command(self, ctx):
    player = self.get_player(ctx)
    player.queue.shuffle()
    await ctx.send("Queue shuffled.")

@shuffle_command.error
async def shuffle_command_error(self, ctx, exc):
    if isinstance(exc, QueueIsEmpty):
        await ctx.send("The queue could not be shuffled as it is currently empty.")

@commands.command(name="repeat")
async def repeat_command(self, ctx, mode: str):
    if mode not in ("none", "1", "all"):
        raise InvalidRepeatMode

    player = self.get_player(ctx)
    player.queue.set_repeat_mode(mode)
    await ctx.send(f"The repeat mode has been set to {mode}.")

@commands.command(name="queue", aliases=["q"])
async def queue_command(self, ctx, show: t.Optional[int] = 10):
    player = self.get_player(ctx)

    if player.queue.is_empty:
        raise QueueIsEmpty

    embed = discord.Embed(
        title="Queue",
        description=f"Showing up to next {show} tracks",
        colour=ctx.author.colour,
        timestamp=dt.datetime.utcnow()
    )
    embed.set_author(name="Query Results")
    embed.set_footer(text=f"Requested by {ctx.author.display_name}", icon_url=ctx.author.avatar_url)
    embed.add_field(
        name="Currently playing",
        value=getattr(player.queue.current_track, "title", "No tracks currently playing."),
        inline=False
    )
    if upcoming := player.queue.upcoming:
        embed.add_field(
            name="Next up",
            value="\n".join(t.title for t in upcoming[:show]),
            inline=False
        )

    msg = await ctx.send(embed=embed)
    print(msg)

@commands.command(name="website", aliases=["web"])
async def website(self, ctx):
    await ctx.send("Find my website at http://86.176.239.70:8000/index.html for a list of commands and a invite link :)")

@commands.command(name="clear")
async def clear_command(self,ctx):
    player = self.get_player(ctx)
    player.queue.empty()
    await player.stop()
    await ctx.send("Queue has been cleared.")

@queue_command.error
async def queue_command_error(self, ctx, exc):
    if isinstance(exc, QueueIsEmpty):
        await ctx.send("The queue is currently empty.")

@commands.command(name="next", aliases=["skip"])
async def next_command(self, ctx):
    player = self.get_player(ctx)

    if not player.queue.upcoming:
        raise NoMoreTracks

    await player.stop()
    await ctx.send("Playing next track in queue.")

@next_command.error
async def next_command_error(self, ctx, exc):
    if isinstance(exc, QueueIsEmpty):
        await ctx.send("This could not be executed as the queue is currently empty.")
    elif isinstance(exc, NoMoreTracks):
        await ctx.send("There are no more tracks in the queue.")

def setup(bot): bot.add_cog(Music(bot))

This is the code in its current form, sorry im new to github so am unaware on how to format this correctly for the website haha

freyacodes commented 3 years ago

You're having problems with Wavelink not Lavalink. Reach out to the maintainers instead of us.

Also, this issue tracker is not for general troubleshooting.