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

Discord.py机器人已加入语音频道,调用play时触发未连接错误

问题解决方案

一、解决ClientException: Not connected to voice错误

这个问题核心是你调用的是语音频道对象的play方法,而非实际的语音连接客户端(VoiceClient)的方法,且未正确保存/获取连接实例:

  1. 确保join命令中保存VoiceClient实例
    调用channel.connect()会返回一个VoiceClient对象,这才是真正管理语音连接的实例,需要将其存储或通过bot.voice_clients列表获取。
  2. play命令必须调用VoiceClient的play方法
    不能直接用VoiceChannel对象调用play,要先获取对应服务器的活跃VoiceClient,再调用其方法。
  3. 调用前检查连接状态
    在执行播放前,先验证VoiceClient是否存在且处于连接状态。

二、解决脚本终止后机器人残留、重启join无法识别连接的问题

脚本意外终止会导致Discord服务器认为机器人仍在频道(僵尸连接),重启后的bot无法关联这个无效连接,需要主动清理:

  1. join命令先检查已有连接
    每次执行join时,先查找当前服务器是否存在活跃的VoiceClient,存在则复用或先断开再重连。
  2. 脚本退出时主动断开所有连接
    通过信号处理函数,在脚本收到终止信号时,遍历所有连接并断开,避免残留。

完整修正代码示例

from discord.ext import commands
from discord import FFmpegPCMAudio
from discord.utils import get
import signal
import asyncio

bot = commands.Bot(command_prefix="!")

@bot.command()
async def join(ctx):
    # 检查用户是否在语音频道
    if not ctx.author.voice:
        await ctx.send("你先加入一个语音频道再喊我!")
        return
    
    # 查找当前服务器的已有语音连接
    existing_vc = get(bot.voice_clients, guild=ctx.guild)
    if existing_vc:
        if existing_vc.is_connected():
            await ctx.send("我已经在语音频道里了!")
            return
        else:
            # 清理无效连接
            await existing_vc.disconnect()
    
    # 连接到用户所在频道并保存实例
    target_channel = ctx.author.voice.channel
    vc = await target_channel.connect()
    await ctx.send(f"已加入频道:{target_channel.name}")

@bot.command()
async def play(ctx, audio_path: str):
    # 获取当前服务器的活跃语音连接
    vc = get(bot.voice_clients, guild=ctx.guild)
    if not vc or not vc.is_connected():
        await ctx.send("先输入!join让我加入语音频道啊!")
        return
    
    # 加载音频源(示例用本地文件,可替换为FFmpeg拉取网络资源)
    audio_source = FFmpegPCMAudio(audio_path)
    # 调用VoiceClient的play方法
    vc.play(audio_source)
    await ctx.send("开始播放音频!")

# 处理脚本终止信号,主动断开所有语音连接
def handle_shutdown(signal_num, frame):
    asyncio.create_task(cleanup_connections())

async def cleanup_connections():
    for vc in bot.voice_clients:
        await vc.disconnect()
    await bot.close()

signal.signal(signal.SIGINT, handle_shutdown)

bot.run("你的机器人TOKEN")

关键说明

  • 始终通过bot.voice_clients列表获取对应服务器的VoiceClient,而非直接操作频道对象。
  • 脚本退出时的信号处理能避免机器人留在频道形成僵尸连接。
  • join命令的前置检查能处理重启后残留的无效连接问题。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.21 04:33:22