You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Discord机器人on_voice_state_update事件语音连接状态检测故障排查

Fixing Voice Connection Detection & Preventing Duplicate Actions in Your Discord Bot

Let's break down what's going wrong with your current code and how to fix it, step by step:

Key Issues in Your Original Code

  1. Incorrect ID Comparison: You're comparing member.id (an integer) to a string like 'id of member'—this will never evaluate to true, so the core logic inside that condition never runs.
  2. Misplaced Sleep & Condition Check: You're sleeping before verifying if the event is relevant to your target member, leading to unnecessary delays and timing mismatches.
  3. No Concurrency Control: Without a lock, rapid-fire events (like multiple users entering AFK quickly) can trigger duplicate voice connections.
  4. Redundant Channel Lookup: You convert before.channel.id to an integer just to fetch the channel again—you can use before.channel directly.

Corrected Code with Explanations

First, add an async lock to your cog's initialization to prevent concurrent voice operations:

import asyncio
import discord
from discord.ext import commands

class YourCog(commands.Cog):
    def __init__(self, bot):
        self.bot = bot
        self.voice_lock = asyncio.Lock()  # Prevents overlapping voice actions

    async def on_voice_state_update(self, member, before, after):
        # Configuration - replace these with your actual values (use integers for IDs!)
        TARGET_MEMBER_ID = 123456789012345678  # ID of the member you want to monitor
        MP3_FILE_PATH = '/full/path/to/your/audio.mp3'

        # Early exit if this isn't the event we care about
        if (
            member.id != TARGET_MEMBER_ID
            or not after.afk
            or before.afk
        ):
            return

        # Ensure only one voice operation runs at a time
        async with self.voice_lock:
            # Reliably check if the bot is connected to any voice channel in this guild
            bot_member = member.guild.get_member(self.bot.user.id)
            if bot_member.voice and bot_member.voice.channel:
                # Bot is currently busy - skip this event (wait for lock to release if needed)
                return

            # Get the previous channel the member was in
            prev_channel = before.channel
            if not prev_channel:
                return  # Member wasn't in a channel before, nothing to do

            # Execute the voice action with proper cleanup
            voice_client = None
            try:
                voice_client = await prev_channel.connect()
                # Play the audio file
                audio_source = discord.FFmpegPCMAudio(MP3_FILE_PATH)
                voice_client.play(audio_source)

                # Wait until the audio finishes playing (instead of fixed sleep)
                while voice_client.is_playing():
                    await asyncio.sleep(0.5)
            except Exception as e:
                print(f"Error during voice action: {str(e)}")
            finally:
                # Always disconnect, even if an error occurs
                if voice_client and voice_client.is_connected():
                    await voice_client.disconnect()

What Changed & Why

  1. Async Lock: The self.voice_lock ensures that only one instance of the voice playback logic runs at a time. If multiple events trigger quickly, they'll wait until the lock is released (after the bot disconnects).
  2. Early Event Filtering: We first check if the event is relevant to our target member before doing any heavy lifting, avoiding unnecessary processing.
  3. Reliable Connection Check: Using bot_member.voice directly checks if the bot is present in any voice channel in the guild—this is more reliable than checking voice_clients alone.
  4. Audio Completion Wait: Instead of a fixed 5-second sleep, we wait until the audio stops playing, ensuring the full track is heard before disconnecting.
  5. Proper Error Handling: The try/finally block guarantees the bot disconnects even if an error occurs during playback.
  6. Fixed ID Comparison: Using integer IDs for the target member matches Discord's internal ID format.

Why Your Original is_connected Function Failed

Your nested is_connected function was technically correct, but it was being called before checking if the event was relevant. This meant you were sleeping 9 seconds for every voice state change (even unrelated ones), leading to confusion about whether it was working. Additionally, the string ID comparison meant the core logic inside the condition never executed, making it seem like the connection check was broken.

内容的提问来源于stack exchange,提问作者nxfi777

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.07 19:33:09