discord.py ffmpeg song plays too quickly at the beginning

1.4k views Asked by At

I built a discord bot using discord.py and ffmpeg, it works but the song in the first 0-5 seconds plays too fast, I think it's buffering so I tried to use asyncio.sleep but didn't work, suggestions to solve the problem?

play func:

with youtube_dl.YoutubeDL(self.opts) as ydl:
    await asyncio.sleep(0.1)
    ydl.cache.remove()
    await asyncio.sleep(0.1)
    info = ydl.extract_info(url, download=False)
    raw_url_song = info['formats'][0]['url']
    await self.real_play(ctx, raw_url_song)

real_play func:

source = await discord.FFmpegOpusAudio.from_probe(processed_url_song, **self.FFMPEG_OPTIONS)
await asyncio.sleep(0.5)
self.vc.play(source, after=lambda e: asyncio.run_coroutine_threadsafe(self.real_play(ctx, processed_url_song), self.client.loop))

these are the options:

self.FFMPEG_OPTIONS = {'before_options': '-reconnect 1 -reconnect_streamed 1 -reconnect_delay_max 5', 'options': '-vn'}
self.OPTIONS = {'format': 'bestaudio'}
self.opts = {'extract_flat': True, 'skip_download': True}

the functions are separate because I do something else (such as playlists), I have reported only the essential code to understand the problem, and the cache remove is essential to reduce the occurence of HTTP 404 forbidden error, btw also without cache remove the problem persists

2

There are 2 answers

0
matteobergantin On

I think I found a hacky way to get the audio thing working.

The way the .play() function works is that it keeps calling FFmpegOpusAudio.read() to read the binary output.

I noticed that for some reason the first time FFmpegOpusAudio.read() gets called it takes a long time before sending the data (3-4 seconds), and that's what's causing the audio to play a little too fast in the beginning. So I just call FFmpegOpusAudio.read() before I actually connect to the voice channel, and then everything works fine.

This should also work for FFmpegPCMAudio.

import asyncio
from discord import FFmpegOpusAudio

source = FFmpegOpusAudio(data, pipe=True)
source.read() # This will take 3-4 seconds

player = await voice_channel.connect()
player.play(source) # This should work now
1
SegergrenDev On

I've added a pause() and resume() function with a sleep function inside it. It works but it takes a second.

import asyncio
    
voice = bot.voice_clients[0]
voice.play(discord.FFmpegPCMAudio("song.mp3"))
voice.pause()
await asyncio.sleep(1)
voice.resume()