Skip to content

Commit 57db2bc

Browse files
committed
Merge remote-tracking branch 'origin/dev' into feature/resume
# 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
2 parents 7e96b02 + 64bd27e commit 57db2bc

File tree

13 files changed

+147
-20
lines changed

13 files changed

+147
-20
lines changed

CHANGELOG.md

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,29 @@
33
Each release usually includes various fixes and improvements.
44
The most noteworthy of these, as well as any features and breaking changes, are listed here.
55

6+
## v3.1.2
7+
* Add API version header to all responses
8+
9+
Contributor:
10+
[@Devoxin](https://github.com/Devoxin)
11+
12+
## v3.1.1
13+
* Add equalizer support
14+
* Update lavaplayer to 1.3.10
15+
* Fixed automatic versioning
16+
* Added build config to upload binaries to GitHub releases from CI
17+
18+
Contributors:
19+
[@Devoxin](https://github.com/Devoxin),
20+
[@Frederikam](https://github.com/Frederikam/),
21+
[@calebj](https://github.com/calebj)
22+
23+
## v3.1
24+
* Replaced JDAA with Magma
25+
* Added an event for when the Discord voice WebSocket is closed
26+
* Replaced Tomcat and Java_Websocket with Undertow. WS and REST is now handled by the same
27+
server and port. Port is specified by `server.port`.
28+
629
## v3.0
730
* **Breaking:** The minimum required Java version to run the server is now Java 10.
831
**Please note**: Java 10 will be obsolete

IMPLEMENTATION.md

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -110,6 +110,24 @@ Set player volume. Volume may range from 0 to 1000. 100 is default.
110110
}
111111
```
112112

113+
Using the player equalizer
114+
```json
115+
{
116+
"op": "equalizer",
117+
"guildId": "...",
118+
"bands": [
119+
{
120+
"band": 0,
121+
"gain": 0.2
122+
}
123+
]
124+
}
125+
```
126+
There are 15 bands (0-14) that can be changed.
127+
`gain` is the multiplier for the given band. The default value is 0. Valid values range from -0.25 to 1.0,
128+
where -0.25 means the given band is completely muted, and 0.25 means it is doubled. Modifying the gain could
129+
also change the volume of the output.
130+
113131
Tell the server to potentially disconnect from the voice server and potentially remove the player with all its data.
114132
This is useful if you want to move to a new node for a voice connection. Calling this op does not affect voice state,
115133
and you can send the same VOICE_SERVER_UPDATE to a new node.
@@ -289,6 +307,8 @@ Additionally, in every `/loadtracks` response, a `loadType` property is returned
289307
* `NO_MATCHES` - Returned if no matches/sources could be found for a given identifier.
290308
* `LOAD_FAILED` - Returned if Lavaplayer failed to load something for some reason.
291309

310+
All REST responses from Lavalink include a `Lavalink-Api-Version` header.
311+
292312
### Resuming Lavalink sessions
293313

294314
What happens after your client disconnects is dependent on whether or not the session has been configured for resuming.

LavalinkServer/application.yml.example

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ lavalink:
1717
http: true
1818
local: false
1919
bufferDurationMs: 400
20-
youtubePlaylistLoadLimit: 600
20+
youtubePlaylistLoadLimit: 6 # Number of pages at 100 each
2121
gc-warnings: true
2222

2323
metrics:

LavalinkServer/build.gradle

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ sourceCompatibility = 10
2222
targetCompatibility = 10
2323

2424
bootRun {
25-
//compiling tests during bootRun increases the likelyhood of catching broken tests locally instead of on the CI
25+
//compiling tests during bootRun increases the likelihood of catching broken tests locally instead of on the CI
2626
dependsOn compileTestJava
2727

2828
//pass in custom jvm args
@@ -97,10 +97,16 @@ compileTestKotlin {
9797
String versionFromTag() {
9898

9999
def headTag = grgit.tag.list().find {
100-
it.commit == grgit.head()
100+
it.commit.getId() == grgit.head().getId()
101101
}
102102

103-
def clean = grgit.status().clean //uncommitted changes? -> should be SNAPSHOT
103+
// Uncommitted changes? -> should be SNAPSHOT
104+
// Also watch out for false positives in the CI build
105+
def clean = grgit.status().clean || System.getenv('CI') != null
106+
107+
if (!clean) {
108+
println("Git state is dirty, setting version as snapshot")
109+
}
104110

105111
if (headTag && clean) {
106112
headTag.getName()

LavalinkServer/src/main/java/lavalink/server/config/AudioPlayerConfiguration.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,8 @@ public Supplier<AudioPlayerManager> audioPlayerManagerSupplier(AudioSourcesConfi
4545
if (sources.isHttp()) audioPlayerManager.registerSourceManager(new HttpAudioSourceManager());
4646
if (sources.isLocal()) audioPlayerManager.registerSourceManager(new LocalAudioSourceManager());
4747

48+
audioPlayerManager.getConfiguration().setFilterHotSwapEnabled(true);
49+
4850
return audioPlayerManager;
4951
};
5052
}
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
package lavalink.server.io;
2+
3+
import org.jetbrains.annotations.NotNull;
4+
import org.springframework.stereotype.Component;
5+
import org.springframework.web.filter.OncePerRequestFilter;
6+
7+
import javax.servlet.FilterChain;
8+
import javax.servlet.ServletException;
9+
import javax.servlet.http.HttpServletRequest;
10+
import javax.servlet.http.HttpServletResponse;
11+
import java.io.IOException;
12+
13+
@Component
14+
public class ResponseHeaderFilter extends OncePerRequestFilter {
15+
16+
@Override
17+
protected void doFilterInternal(@NotNull HttpServletRequest request, @NotNull HttpServletResponse response,
18+
@NotNull FilterChain filterChain) throws IOException, ServletException {
19+
response.addHeader("Lavalink-Api-Version", "3");
20+
filterChain.doFilter(request, response);
21+
}
22+
}

LavalinkServer/src/main/java/lavalink/server/io/SocketContext.kt

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -23,21 +23,25 @@
2323
package lavalink.server.io
2424

2525
import com.sedmelluq.discord.lavaplayer.player.AudioPlayerManager
26+
import lavalink.server.player.Player
27+
import space.npstr.magma.MagmaMember
2628
import io.undertow.websockets.core.WebSocketCallback
2729
import io.undertow.websockets.core.WebSocketChannel
2830
import io.undertow.websockets.core.WebSockets
2931
import io.undertow.websockets.jsr.UndertowSession
30-
import lavalink.server.player.Player
3132
import org.json.JSONObject
3233
import org.slf4j.LoggerFactory
3334
import org.springframework.web.socket.WebSocketSession
3435
import org.springframework.web.socket.adapter.standard.StandardWebSocketSession
3536
import space.npstr.magma.MagmaApi
36-
import space.npstr.magma.MagmaMember
3737
import space.npstr.magma.events.api.MagmaEvent
3838
import space.npstr.magma.events.api.WebSocketClosed
3939
import java.util.*
4040
import java.util.concurrent.*
41+
import java.util.concurrent.ConcurrentHashMap
42+
import java.util.concurrent.Executors
43+
import java.util.concurrent.ScheduledExecutorService
44+
import java.util.concurrent.TimeUnit
4145
import java.util.function.Supplier
4246

4347
class SocketContext internal constructor(
@@ -55,8 +59,6 @@ class SocketContext internal constructor(
5559
internal val magma: MagmaApi = MagmaApi.of { socketServer.getAudioSendFactory(it) }
5660
//guildId <-> Player
5761
val players = ConcurrentHashMap<String, Player>()
58-
private val executor: ScheduledExecutorService
59-
val playerUpdateService: ScheduledExecutorService
6062
@Volatile
6163
var sessionPaused = false
6264
private val resumeEventQueue = ConcurrentLinkedQueue<String>()
@@ -65,6 +67,8 @@ class SocketContext internal constructor(
6567
var resumeKey: String? = null
6668
var resumeTimeout = 60L // Seconds
6769
private var sessionTimeoutFuture: ScheduledFuture<Unit>? = null
70+
private val executor: ScheduledExecutorService
71+
val playerUpdateService: ScheduledExecutorService
6872

6973
val playingPlayers: List<Player>
7074
get() {
@@ -92,6 +96,10 @@ class SocketContext internal constructor(
9296
Player(this, guildId, audioPlayerManager)
9397
}
9498

99+
internal fun getPlayers(): Map<String, Player> {
100+
return players
101+
}
102+
95103
private fun handleMagmaEvent(magmaEvent: MagmaEvent) {
96104
if (magmaEvent is WebSocketClosed) {
97105
val out = JSONObject()

LavalinkServer/src/main/java/lavalink/server/io/SocketServer.kt

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -25,9 +25,11 @@ package lavalink.server.io
2525
import com.github.shredder121.asyncaudio.jda.AsyncPacketProviderFactory
2626
import com.sedmelluq.discord.lavaplayer.jdaudp.NativeAudioSendFactory
2727
import com.sedmelluq.discord.lavaplayer.player.AudioPlayerManager
28+
import com.sedmelluq.discord.lavaplayer.track.TrackMarker
2829
import lavalink.server.config.AudioSendFactoryConfiguration
2930
import lavalink.server.config.ServerConfig
3031
import lavalink.server.player.Player
32+
import lavalink.server.player.TrackEndMarkerHandler
3133
import lavalink.server.util.Util
3234
import net.dv8tion.jda.core.audio.factory.IAudioSendFactory
3335
import org.json.JSONObject
@@ -38,7 +40,7 @@ import org.springframework.web.socket.TextMessage
3840
import org.springframework.web.socket.WebSocketSession
3941
import org.springframework.web.socket.handler.TextWebSocketHandler
4042
import space.npstr.magma.Member
41-
import java.util.*
43+
import java.util.HashMap
4244
import java.util.concurrent.ConcurrentHashMap
4345
import java.util.function.Supplier
4446

@@ -54,7 +56,7 @@ class SocketServer(
5456
val contextMap = HashMap<String, SocketContext>()
5557
private val sendFactories = ConcurrentHashMap<Int, IAudioSendFactory>()
5658
@Suppress("LeakingThis")
57-
private val handlers = WebSocketHandlers(this)
59+
private val handlers = WebSocketHandlers(contextMap)
5860
private val resumableSessions = mutableMapOf<String, SocketContext>()
5961

6062
companion object {
@@ -90,6 +92,8 @@ class SocketServer(
9092
return
9193
}
9294

95+
shardCounts[userId] = shardCount
96+
9397
contextMap[session.id] = SocketContext(audioPlayerManagerSupplier, session, this, userId)
9498
log.info("Connection successfully established from " + session.remoteAddress!!)
9599
}
@@ -149,6 +153,7 @@ class SocketServer(
149153
"volume" -> handlers.volume(session, json)
150154
"destroy" -> handlers.destroy(session, json)
151155
"configureResuming" -> handlers.configureResuming(session, json)
156+
"equalizer" -> handlers.equalizer(session, json)
152157
else -> log.warn("Unexpected operation: " + json.getString("op"))
153158
// @formatter:on
154159
}
@@ -158,8 +163,8 @@ class SocketServer(
158163
val shardCount = shardCounts.getOrDefault(member.userId, 1)
159164
val shardId = Util.getShardFromSnowflake(member.guildId, shardCount)
160165

161-
return sendFactories.computeIfAbsent(shardId % audioSendFactoryConfiguration.audioSendFactoryCount)
162-
{
166+
return sendFactories.computeIfAbsent(shardId % audioSendFactoryConfiguration.audioSendFactoryCount
167+
) {
163168
val customBuffer = serverConfig.bufferDurationMs
164169
val nativeAudioSendFactory: NativeAudioSendFactory
165170
nativeAudioSendFactory = if (customBuffer != null) {

LavalinkServer/src/main/java/lavalink/server/io/StatsTask.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,9 @@ private void sendStats() {
8989
JSONObject cpu = new JSONObject();
9090
cpu.put("cores", Runtime.getRuntime().availableProcessors());
9191
cpu.put("systemLoad", hal.getProcessor().getSystemCpuLoad());
92-
cpu.put("lavalinkLoad", getProcessRecentCpuUsage());
92+
double load = getProcessRecentCpuUsage();
93+
if (!Double.isFinite(load)) load = 0;
94+
cpu.put("lavalinkLoad", load);
9395

9496
out.put("cpu", cpu);
9597

LavalinkServer/src/main/java/lavalink/server/io/WebSocketHandlers.kt

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,7 @@ import org.springframework.web.socket.WebSocketSession
88
import space.npstr.magma.MagmaMember
99
import space.npstr.magma.MagmaServerUpdate
1010

11-
class WebSocketHandlers(socketServer: SocketServer) {
12-
13-
private val contextMap = socketServer.contextMap
11+
class WebSocketHandlers(private val contextMap: Map<String, SocketContext>) {
1412

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

92+
fun equalizer(session: WebSocketSession, json: JSONObject) {
93+
val player = contextMap[session.id]!!.getPlayer(json.getString("guildId"))
94+
val bands = json.getJSONArray("bands")
95+
96+
for (i in 0 until bands.length()) {
97+
val band = bands.getJSONObject(i)
98+
player.setBandGain(band.getInt("band"), band.getFloat("gain"))
99+
}
100+
}
101+
94102
fun destroy(session: WebSocketSession, json: JSONObject) {
95103
val socketContext = contextMap[session.id]!!
96104
val player = socketContext.players.remove(json.getString("guildId"))
@@ -108,5 +116,4 @@ class WebSocketHandlers(socketServer: SocketServer) {
108116
socketContext.resumeKey = json.optString("key")
109117
if (json.has("timeout")) socketContext.resumeTimeout = json.getLong("timeout")
110118
}
111-
112119
}

0 commit comments

Comments
 (0)