Skip to content

Commit

Permalink
Merge remote-tracking branch 'origin/dev' into feature/resume
Browse files Browse the repository at this point in the history
# Conflicts:
#	IMPLEMENTATION.md
#	LavalinkServer/src/main/java/lavalink/server/io/SocketContext.kt
#	LavalinkServer/src/main/java/lavalink/server/io/SocketServer.kt
#	LavalinkServer/src/main/java/lavalink/server/io/StatsTask.java
#	LavalinkServer/src/main/java/lavalink/server/io/WebSocketHandlers.kt
#	LavalinkServer/src/main/java/lavalink/server/player/EventEmitter.java
#	LavalinkServer/src/main/java/lavalink/server/player/Player.java
  • Loading branch information
freyacodes committed Dec 20, 2018
2 parents 7e96b02 + 64bd27e commit 57db2bc
Show file tree
Hide file tree
Showing 13 changed files with 147 additions and 20 deletions.
23 changes: 23 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,29 @@
Each release usually includes various fixes and improvements.
The most noteworthy of these, as well as any features and breaking changes, are listed here.

## v3.1.2
* Add API version header to all responses

Contributor:
[@Devoxin](https://github.com/Devoxin)

## v3.1.1
* Add equalizer support
* Update lavaplayer to 1.3.10
* Fixed automatic versioning
* Added build config to upload binaries to GitHub releases from CI

Contributors:
[@Devoxin](https://github.com/Devoxin),
[@Frederikam](https://github.com/Frederikam/),
[@calebj](https://github.com/calebj)

## v3.1
* Replaced JDAA with Magma
* Added an event for when the Discord voice WebSocket is closed
* Replaced Tomcat and Java_Websocket with Undertow. WS and REST is now handled by the same
server and port. Port is specified by `server.port`.

## v3.0
* **Breaking:** The minimum required Java version to run the server is now Java 10.
**Please note**: Java 10 will be obsolete
Expand Down
20 changes: 20 additions & 0 deletions IMPLEMENTATION.md
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,24 @@ Set player volume. Volume may range from 0 to 1000. 100 is default.
}
```

Using the player equalizer
```json
{
"op": "equalizer",
"guildId": "...",
"bands": [
{
"band": 0,
"gain": 0.2
}
]
}
```
There are 15 bands (0-14) that can be changed.
`gain` is the multiplier for the given band. The default value is 0. Valid values range from -0.25 to 1.0,
where -0.25 means the given band is completely muted, and 0.25 means it is doubled. Modifying the gain could
also change the volume of the output.

Tell the server to potentially disconnect from the voice server and potentially remove the player with all its data.
This is useful if you want to move to a new node for a voice connection. Calling this op does not affect voice state,
and you can send the same VOICE_SERVER_UPDATE to a new node.
Expand Down Expand Up @@ -289,6 +307,8 @@ Additionally, in every `/loadtracks` response, a `loadType` property is returned
* `NO_MATCHES` - Returned if no matches/sources could be found for a given identifier.
* `LOAD_FAILED` - Returned if Lavaplayer failed to load something for some reason.

All REST responses from Lavalink include a `Lavalink-Api-Version` header.

### Resuming Lavalink sessions

What happens after your client disconnects is dependent on whether or not the session has been configured for resuming.
Expand Down
2 changes: 1 addition & 1 deletion LavalinkServer/application.yml.example
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ lavalink:
http: true
local: false
bufferDurationMs: 400
youtubePlaylistLoadLimit: 600
youtubePlaylistLoadLimit: 6 # Number of pages at 100 each
gc-warnings: true

metrics:
Expand Down
12 changes: 9 additions & 3 deletions LavalinkServer/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ sourceCompatibility = 10
targetCompatibility = 10

bootRun {
//compiling tests during bootRun increases the likelyhood of catching broken tests locally instead of on the CI
//compiling tests during bootRun increases the likelihood of catching broken tests locally instead of on the CI
dependsOn compileTestJava

//pass in custom jvm args
Expand Down Expand Up @@ -97,10 +97,16 @@ compileTestKotlin {
String versionFromTag() {

def headTag = grgit.tag.list().find {
it.commit == grgit.head()
it.commit.getId() == grgit.head().getId()
}

def clean = grgit.status().clean //uncommitted changes? -> should be SNAPSHOT
// Uncommitted changes? -> should be SNAPSHOT
// Also watch out for false positives in the CI build
def clean = grgit.status().clean || System.getenv('CI') != null

if (!clean) {
println("Git state is dirty, setting version as snapshot")
}

if (headTag && clean) {
headTag.getName()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,8 @@ public Supplier<AudioPlayerManager> audioPlayerManagerSupplier(AudioSourcesConfi
if (sources.isHttp()) audioPlayerManager.registerSourceManager(new HttpAudioSourceManager());
if (sources.isLocal()) audioPlayerManager.registerSourceManager(new LocalAudioSourceManager());

audioPlayerManager.getConfiguration().setFilterHotSwapEnabled(true);

return audioPlayerManager;
};
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package lavalink.server.io;

import org.jetbrains.annotations.NotNull;
import org.springframework.stereotype.Component;
import org.springframework.web.filter.OncePerRequestFilter;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

@Component
public class ResponseHeaderFilter extends OncePerRequestFilter {

@Override
protected void doFilterInternal(@NotNull HttpServletRequest request, @NotNull HttpServletResponse response,
@NotNull FilterChain filterChain) throws IOException, ServletException {
response.addHeader("Lavalink-Api-Version", "3");
filterChain.doFilter(request, response);
}
}
16 changes: 12 additions & 4 deletions LavalinkServer/src/main/java/lavalink/server/io/SocketContext.kt
Original file line number Diff line number Diff line change
Expand Up @@ -23,21 +23,25 @@
package lavalink.server.io

import com.sedmelluq.discord.lavaplayer.player.AudioPlayerManager
import lavalink.server.player.Player
import space.npstr.magma.MagmaMember
import io.undertow.websockets.core.WebSocketCallback
import io.undertow.websockets.core.WebSocketChannel
import io.undertow.websockets.core.WebSockets
import io.undertow.websockets.jsr.UndertowSession
import lavalink.server.player.Player
import org.json.JSONObject
import org.slf4j.LoggerFactory
import org.springframework.web.socket.WebSocketSession
import org.springframework.web.socket.adapter.standard.StandardWebSocketSession
import space.npstr.magma.MagmaApi
import space.npstr.magma.MagmaMember
import space.npstr.magma.events.api.MagmaEvent
import space.npstr.magma.events.api.WebSocketClosed
import java.util.*
import java.util.concurrent.*
import java.util.concurrent.ConcurrentHashMap
import java.util.concurrent.Executors
import java.util.concurrent.ScheduledExecutorService
import java.util.concurrent.TimeUnit
import java.util.function.Supplier

class SocketContext internal constructor(
Expand All @@ -55,8 +59,6 @@ class SocketContext internal constructor(
internal val magma: MagmaApi = MagmaApi.of { socketServer.getAudioSendFactory(it) }
//guildId <-> Player
val players = ConcurrentHashMap<String, Player>()
private val executor: ScheduledExecutorService
val playerUpdateService: ScheduledExecutorService
@Volatile
var sessionPaused = false
private val resumeEventQueue = ConcurrentLinkedQueue<String>()
Expand All @@ -65,6 +67,8 @@ class SocketContext internal constructor(
var resumeKey: String? = null
var resumeTimeout = 60L // Seconds
private var sessionTimeoutFuture: ScheduledFuture<Unit>? = null
private val executor: ScheduledExecutorService
val playerUpdateService: ScheduledExecutorService

val playingPlayers: List<Player>
get() {
Expand Down Expand Up @@ -92,6 +96,10 @@ class SocketContext internal constructor(
Player(this, guildId, audioPlayerManager)
}

internal fun getPlayers(): Map<String, Player> {
return players
}

private fun handleMagmaEvent(magmaEvent: MagmaEvent) {
if (magmaEvent is WebSocketClosed) {
val out = JSONObject()
Expand Down
13 changes: 9 additions & 4 deletions LavalinkServer/src/main/java/lavalink/server/io/SocketServer.kt
Original file line number Diff line number Diff line change
Expand Up @@ -25,9 +25,11 @@ package lavalink.server.io
import com.github.shredder121.asyncaudio.jda.AsyncPacketProviderFactory
import com.sedmelluq.discord.lavaplayer.jdaudp.NativeAudioSendFactory
import com.sedmelluq.discord.lavaplayer.player.AudioPlayerManager
import com.sedmelluq.discord.lavaplayer.track.TrackMarker
import lavalink.server.config.AudioSendFactoryConfiguration
import lavalink.server.config.ServerConfig
import lavalink.server.player.Player
import lavalink.server.player.TrackEndMarkerHandler
import lavalink.server.util.Util
import net.dv8tion.jda.core.audio.factory.IAudioSendFactory
import org.json.JSONObject
Expand All @@ -38,7 +40,7 @@ import org.springframework.web.socket.TextMessage
import org.springframework.web.socket.WebSocketSession
import org.springframework.web.socket.handler.TextWebSocketHandler
import space.npstr.magma.Member
import java.util.*
import java.util.HashMap
import java.util.concurrent.ConcurrentHashMap
import java.util.function.Supplier

Expand All @@ -54,7 +56,7 @@ class SocketServer(
val contextMap = HashMap<String, SocketContext>()
private val sendFactories = ConcurrentHashMap<Int, IAudioSendFactory>()
@Suppress("LeakingThis")
private val handlers = WebSocketHandlers(this)
private val handlers = WebSocketHandlers(contextMap)
private val resumableSessions = mutableMapOf<String, SocketContext>()

companion object {
Expand Down Expand Up @@ -90,6 +92,8 @@ class SocketServer(
return
}

shardCounts[userId] = shardCount

contextMap[session.id] = SocketContext(audioPlayerManagerSupplier, session, this, userId)
log.info("Connection successfully established from " + session.remoteAddress!!)
}
Expand Down Expand Up @@ -149,6 +153,7 @@ class SocketServer(
"volume" -> handlers.volume(session, json)
"destroy" -> handlers.destroy(session, json)
"configureResuming" -> handlers.configureResuming(session, json)
"equalizer" -> handlers.equalizer(session, json)
else -> log.warn("Unexpected operation: " + json.getString("op"))
// @formatter:on
}
Expand All @@ -158,8 +163,8 @@ class SocketServer(
val shardCount = shardCounts.getOrDefault(member.userId, 1)
val shardId = Util.getShardFromSnowflake(member.guildId, shardCount)

return sendFactories.computeIfAbsent(shardId % audioSendFactoryConfiguration.audioSendFactoryCount)
{
return sendFactories.computeIfAbsent(shardId % audioSendFactoryConfiguration.audioSendFactoryCount
) {
val customBuffer = serverConfig.bufferDurationMs
val nativeAudioSendFactory: NativeAudioSendFactory
nativeAudioSendFactory = if (customBuffer != null) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,9 @@ private void sendStats() {
JSONObject cpu = new JSONObject();
cpu.put("cores", Runtime.getRuntime().availableProcessors());
cpu.put("systemLoad", hal.getProcessor().getSystemCpuLoad());
cpu.put("lavalinkLoad", getProcessRecentCpuUsage());
double load = getProcessRecentCpuUsage();
if (!Double.isFinite(load)) load = 0;
cpu.put("lavalinkLoad", load);

out.put("cpu", cpu);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,7 @@ import org.springframework.web.socket.WebSocketSession
import space.npstr.magma.MagmaMember
import space.npstr.magma.MagmaServerUpdate

class WebSocketHandlers(socketServer: SocketServer) {

private val contextMap = socketServer.contextMap
class WebSocketHandlers(private val contextMap: Map<String, SocketContext>) {

fun voiceUpdate(session: WebSocketSession, json: JSONObject) {
val sessionId = json.getString("sessionId")
Expand Down Expand Up @@ -91,6 +89,16 @@ class WebSocketHandlers(socketServer: SocketServer) {
player.setVolume(json.getInt("volume"))
}

fun equalizer(session: WebSocketSession, json: JSONObject) {
val player = contextMap[session.id]!!.getPlayer(json.getString("guildId"))
val bands = json.getJSONArray("bands")

for (i in 0 until bands.length()) {
val band = bands.getJSONObject(i)
player.setBandGain(band.getInt("band"), band.getFloat("gain"))
}
}

fun destroy(session: WebSocketSession, json: JSONObject) {
val socketContext = contextMap[session.id]!!
val player = socketContext.players.remove(json.getString("guildId"))
Expand All @@ -108,5 +116,4 @@ class WebSocketHandlers(socketServer: SocketServer) {
socketContext.resumeKey = json.optString("key")
if (json.has("timeout")) socketContext.resumeTimeout = json.getLong("timeout")
}

}
31 changes: 31 additions & 0 deletions LavalinkServer/src/main/java/lavalink/server/player/Player.java
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@

package lavalink.server.player;

import com.sedmelluq.discord.lavaplayer.filter.equalizer.Equalizer;
import com.sedmelluq.discord.lavaplayer.filter.equalizer.EqualizerFactory;
import com.sedmelluq.discord.lavaplayer.player.AudioPlayer;
import com.sedmelluq.discord.lavaplayer.player.AudioPlayerManager;
import com.sedmelluq.discord.lavaplayer.player.event.AudioEventAdapter;
Expand Down Expand Up @@ -49,6 +51,8 @@ public class Player extends AudioEventAdapter implements AudioSendHandler {
private AudioLossCounter audioLossCounter = new AudioLossCounter();
private AudioFrame lastFrame = null;
private ScheduledFuture myFuture = null;
private EqualizerFactory equalizerFactory = new EqualizerFactory();
private boolean isEqualizerApplied = false;

public Player(SocketContext socketContext, String guildId, AudioPlayerManager audioPlayerManager) {
this.socketContext = socketContext;
Expand Down Expand Up @@ -87,6 +91,33 @@ public void setVolume(int volume) {
player.setVolume(volume);
}

public void setBandGain(int band, float gain) {
log.debug("Setting band {}'s gain to {}", band, gain);
equalizerFactory.setGain(band, gain);

if (gain == 0.0f) {
if (!isEqualizerApplied) {
return;
}

boolean shouldDisable = true;

for (int i = 0; i < Equalizer.BAND_COUNT; i++) {
if (equalizerFactory.getGain(i) != 0.0f) {
shouldDisable = false;
}
}

if (shouldDisable) {
this.player.setFilterFactory(null);
this.isEqualizerApplied = false;
}
} else if (!this.isEqualizerApplied) {
this.player.setFilterFactory(equalizerFactory);
this.isEqualizerApplied = true;
}
}

public JSONObject getState() {
JSONObject json = new JSONObject();

Expand Down
5 changes: 3 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,8 @@ users about the compatibility of their clients to the Lavalink server.
* [SandySounds](https://github.com/MrJohnCoder/SandySounds) (JavaScript)
* [eris-lavalink](https://github.com/briantanner/eris-lavalink) ([eris](https://github.com/abalabahaha/eris), JavaScript)
* [discord.js-lavalink](https://github.com/MrJacz/discord.js-lavalink/) ([discord.js](https://github.com/discordjs/discord.js), JavaScript)
* [Victoria](https://github.com/Yucked/Bot.NET/tree/master/Victoria) ([Discord.NET](https://github.com/RogueException/Discord.Net), .NET)
* [SharpLink](https://github.com/Devoxin/SharpLink) ([Discord.Net](https://github.com/RogueException/Discord.Net), .NET)
* [Victoria](https://github.com/Yucked/Victoria) ([Discord.NET](https://github.com/RogueException/Discord.Net), .NET)
* [Lavalink.NET](https://github.com/Dev-Yukine/Lavalink.NET) (.NET)
* [DSharpPlus.Lavalink](https://github.com/DSharpPlus/DSharpPlus/tree/master/DSharpPlus.Lavalink) ([DSharpPlus](https://github.com/DSharpPlus/DSharpPlus/), .NET)
* [Luna](https://github.com/CharlotteDunois/Luna) ([Yasmin](https://github.com/CharlotteDunois/Yasmin) or generic, PHP)
Expand All @@ -79,7 +80,7 @@ users about the compatibility of their clients to the Lavalink server.
* Or [create your own](https://github.com/Frederikam/Lavalink/blob/master/IMPLEMENTATION.md)

## Server configuration
Download from [the CI server](https://ci.fredboat.com/viewLog.html?buildId=lastSuccessful&buildTypeId=Lavalink_Build&tab=artifacts&guest=1)
Download binaries from [the CI server](https://ci.fredboat.com/viewLog.html?buildId=lastSuccessful&buildTypeId=Lavalink_Build&tab=artifacts&guest=1) or [the GitHub releases](https://github.com/Frederikam/Lavalink/releases).

Put an `application.yml` file in your working directory. [Example](https://github.com/Frederikam/Lavalink/blob/master/LavalinkServer/application.yml.example)

Expand Down
2 changes: 1 addition & 1 deletion build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ subprojects {
ext {
//@formatter:off

lavaplayerVersion = '1.3.7'
lavaplayerVersion = '1.3.10'
magmaVersion = '0.6.1'
jdaNasVersion = '1.0.6'
jappVersion = '1.3'
Expand Down

0 comments on commit 57db2bc

Please sign in to comment.