Search code examples
python-3.xaudiodiscord.pypyaudio

How to integrate PyAudio and discord.py to play audio from my microphone


I don't know what is wrong.

when i call the voice_test command on my discord server, the bot joins a voice channel, it's outline turns green but I dont hear anything.
While running the code, i get no traceback.

here is the code:
CHUNK = 2048
FORMAT = pyaudio.paInt16
CHANNELS = 1
RATE = 44100

@client.command()
async def voice_test(ctx, *, channel: discord.VoiceChannel):
    if ctx.voice_client is not None:
        vc = await ctx.voice_client.move_to(channel)
    else:
        vc = await channel.connect()
    
    p = pyaudio.PyAudio()

    stream = p.open(
        format=FORMAT,
        channels=CHANNELS,
        rate=RATE,
        input=True,
        output=True,
        frames_per_buffer=CHUNK
    )


    while vc.is_connected():
        data = stream.read(CHUNK)
        vc.send_audio_packet(data, encode=False)
        #print(data)

    print('done playing',file=sys.stderr)
    stream.stop_stream()
    stream.close()
    p.terminate()

Solution

  • Based of my own recent experience, you have several issues, but it all boils down to discord is expecting 20ms of 48000hz dual channel opus encoded audio.

    If you encoded your audio to opus before calling send_audio_packet, you would start hearing sound. Bad sound, but sound.

    This is what worked for me, after many iterations and trial and error.

    class PyAudioPCM(discord.AudioSource):
        def __init__(self, channels=2, rate=48000, chunk=960, input_device=1) -> None:
            p = pyaudio.PyAudio()
            self.chunks = chunk
            self.input_stream = p.open(format=pyaudio.paInt16, channels=channels, rate=rate, input=True, input_device_index=input_device, frames_per_buffer=chunk)
    
        def read(self) -> bytes:
            return self.input_stream.read(self.chunks)
    
    
    async def play_audio_in_voice():
        vc.play(PyAudioPCM(), after=lambda e: print(f'Player error: {e}') if e else None)