Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow usage of non-allocating frame buffers #1095

Merged
merged 2 commits into from
Aug 20, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions LavalinkServer/application.yml.example
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ lavalink:
rotation: true
channelMix: true
lowPass: true
nonAllocatingFrameBuffer: false # Setting to true reduces the number of allocations made by each player at the expense of frame rebuilding (e.g. non-instantaneous volume changes)
bufferDurationMs: 400 # The duration of the NAS buffer. Higher values fare better against longer GC pauses. Duration <= 0 to disable JDA-NAS. Minimum of 40ms, lower values may introduce pauses.
frameBufferDurationMs: 5000 # How many milliseconds of audio to keep buffered
opusEncodingQuality: 10 # Opus encoder quality. Valid values range from 0 to 10, where 10 is best quality but is the most expensive on the CPU.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import com.sedmelluq.discord.lavaplayer.source.soundcloud.*
import com.sedmelluq.discord.lavaplayer.source.twitch.TwitchStreamAudioSourceManager
import com.sedmelluq.discord.lavaplayer.source.vimeo.VimeoAudioSourceManager
import com.sedmelluq.discord.lavaplayer.source.youtube.YoutubeAudioSourceManager
import com.sedmelluq.discord.lavaplayer.track.playback.NonAllocatingAudioFrameBuffer
import com.sedmelluq.lava.extensions.youtuberotator.YoutubeIpRotatorSetup
import com.sedmelluq.lava.extensions.youtuberotator.planner.*
import com.sedmelluq.lava.extensions.youtuberotator.tools.ip.Ipv4Block
Expand Down Expand Up @@ -55,6 +56,11 @@ class AudioPlayerConfiguration {
audioPlayerManager.enableGcMonitoring()
}

if (serverConfig.isNonAllocatingFrameBuffer) {
log.info("Using a non-allocating frame buffer")
audioPlayerManager.configuration.setFrameBufferFactory(::NonAllocatingAudioFrameBuffer)
}

val defaultFrameBufferDuration = audioPlayerManager.frameBufferDuration
serverConfig.frameBufferDurationMs?.let {
if (it < 200) { // At the time of writing, LP enforces a minimum of 200ms.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ import org.springframework.stereotype.Component
@Component
class ServerConfig {
var password: String? = null
var isNonAllocatingFrameBuffer = false
var bufferDurationMs: Int? = null
var frameBufferDurationMs: Int? = null
var opusEncodingQuality: Int? = null
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,12 +21,14 @@
*/
package lavalink.server.player

import com.sedmelluq.discord.lavaplayer.format.StandardAudioDataFormats
import com.sedmelluq.discord.lavaplayer.player.AudioPlayer
import com.sedmelluq.discord.lavaplayer.player.AudioPlayerManager
import com.sedmelluq.discord.lavaplayer.player.event.AudioEventAdapter
import com.sedmelluq.discord.lavaplayer.track.AudioTrack
import com.sedmelluq.discord.lavaplayer.track.AudioTrackEndReason
import com.sedmelluq.discord.lavaplayer.track.playback.AudioFrame
import com.sedmelluq.discord.lavaplayer.track.playback.MutableAudioFrame
import dev.arbjerg.lavalink.api.AudioPluginInfoModifier
import dev.arbjerg.lavalink.api.IPlayer
import io.netty.buffer.ByteBuf
Expand All @@ -36,6 +38,7 @@ import lavalink.server.io.SocketServer.Companion.sendPlayerUpdate
import lavalink.server.player.filters.FilterChain
import moe.kyokobot.koe.MediaConnection
import moe.kyokobot.koe.media.OpusAudioFrameProvider
import java.nio.ByteBuffer
import java.util.concurrent.ScheduledFuture
import java.util.concurrent.TimeUnit

Expand All @@ -46,6 +49,9 @@ class LavalinkPlayer(
audioPlayerManager: AudioPlayerManager,
pluginInfoModifiers: List<AudioPluginInfoModifier>
) : AudioEventAdapter(), IPlayer {
private val buffer = ByteBuffer.allocate(StandardAudioDataFormats.DISCORD_OPUS.maximumChunkSize())
private val mutableFrame = MutableAudioFrame().apply { setBuffer(buffer) }

val audioLossCounter = AudioLossCounter()
var endMarkerHit = false
var filters: FilterChain = FilterChain()
Expand Down Expand Up @@ -117,21 +123,15 @@ class LavalinkPlayer(
}

private inner class Provider(connection: MediaConnection?) : OpusAudioFrameProvider(connection) {
private var lastFrame: AudioFrame? = null

override fun canProvide(): Boolean {
lastFrame = audioPlayer.provide()
return if (lastFrame == null) {
override fun canProvide() = audioPlayer.provide(mutableFrame).also { provided ->
if (!provided) {
audioLossCounter.onLoss()
false
} else {
true
}
}

override fun retrieveOpusFrame(buf: ByteBuf) {
audioLossCounter.onSuccess()
buf.writeBytes(lastFrame!!.data)
buf.writeBytes(buffer.flip())
}
}
}
Loading