Skip to content

Commit a364833

Browse files
authored
Merge pull request #551 from freyacodes/dev
Release v3.4
2 parents 26cfc2a + c46cd72 commit a364833

19 files changed

+502
-89
lines changed

CHANGELOG.md

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,22 @@
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+
## 3.4
7+
* New filters system
8+
* Deprecation of `TrackExceptionEvent.error`, replaced by `TrackExceptionEvent.exception`
9+
* Added the `connected` boolean to player updates.
10+
* Updated lavaplayer, fixes Soundcloud
11+
* Added source name to REST api track objects
12+
* Clients are now requested to make their name known during handshake
13+
14+
Contributors:
15+
[@freyacodes](https://github.com/freyacodes),
16+
[@duncte123](https://github.com/duncte123),
17+
[@DaliborTrampota](https://github.com/DaliborTrampota),
18+
[@Mandruyd](https://github.com/Mandruyd),
19+
[@Allvaa](https://github.com/@Allvaa), and
20+
[@TopiSenpai](https://github.com/TopiSenpai)
21+
622
## 3.3.2.5
723
* Update Lavaplayer to 1.3.76
824

IMPLEMENTATION.md

Lines changed: 111 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,14 @@ The Java client has support for JDA, but can also be adapted to work with other
66
* You must be able to send messages via a shard's mainWS connection.
77
* You must be able to intercept voice server updates from mainWS on your shard connection.
88

9+
## Significant changes v3.3 -> v3.4
10+
* Added filters
11+
* The `error` string on the `TrackExceptionEvent` has been deprecated and replaced by
12+
the `exception` object following the same structure as the `LOAD_FAILED` error on [`/loadtracks`](#rest-api)
13+
* Added the `connected` boolean to player updates.
14+
* Added source name to REST api track objects
15+
* Clients are now requested to make their name known during handshake
16+
917
## Significant changes v2.0 -> v3.0
1018
* The response of `/loadtracks` has been completely changed (again since the initial v3.0 pre-release).
1119
* Lavalink v3.0 now reports its version as a handshake response header.
@@ -41,8 +49,8 @@ the JDA client takes advantage of JDA's websocket write thread to send OP 4s for
4149
When opening a websocket connection, you must supply 3 required headers:
4250
```
4351
Authorization: Password matching the server config
44-
Num-Shards: Total number of shards your bot is operating on
4552
User-Id: The user id of the bot you are playing music with
53+
Client-Name: The name of your client. Optionally in the format NAME/VERSION
4654
```
4755

4856
### Outgoing messages
@@ -81,7 +89,7 @@ If `pause` is set to true, the playback will be paused. This is an optional fiel
8189
"endTime": "120000",
8290
"volume": "100",
8391
"noReplace": false,
84-
"pause": false,
92+
"pause": false
8593
}
8694
```
8795

@@ -128,23 +136,96 @@ Volume may range from 0 to 1000. 100 is default.
128136
}
129137
```
130138

131-
#### Using the player equalizer
139+
#### Using filters
132140

133-
There are 15 bands (0-14) that can be changed.
134-
`gain` is the multiplier for the given band. The default value is 0. Valid values range from -0.25 to 1.0,
135-
where -0.25 means the given band is completely muted, and 0.25 means it is doubled. Modifying the gain could
136-
also change the volume of the output.
141+
The `filters` op sets the filters. All the filters are optional, and leaving them out of this message will disable them.
137142

138-
```json
143+
Adding a filter can have adverse effects on performance. These filters force Lavaplayer to decode all audio to PCM,
144+
even if the input was already in the Opus format that Discord uses. This means decoding and encoding audio that would
145+
normally require very little processing. This is often the case with YouTube videos.
146+
147+
JSON comments are for illustration purposes only, and will not be accepted by the server.
148+
149+
Note that filters may take a moment to apply.
150+
151+
```yaml
139152
{
140-
"op": "equalizer",
153+
"op": "filters",
141154
"guildId": "...",
142-
"bands": [
155+
156+
// Float value where 1.0 is 100%. Values >1.0 may cause clipping
157+
"volume": 1.0,
158+
159+
// There are 15 bands (0-14) that can be changed.
160+
// "gain" is the multiplier for the given band. The default value is 0. Valid values range from -0.25 to 1.0,
161+
// where -0.25 means the given band is completely muted, and 0.25 means it is doubled. Modifying the gain could
162+
// also change the volume of the output.
163+
"equalizer": [
143164
{
144165
"band": 0,
145166
"gain": 0.2
146167
}
147-
]
168+
],
169+
170+
// Uses equalization to eliminate part of a band, usually targeting vocals.
171+
"karaoke": {
172+
"level": 1.0,
173+
"monoLevel": 1.0,
174+
"filterBand": 220.0,
175+
"filterWidth": 100.0
176+
},
177+
178+
// Changes the speed, pitch, and rate. All default to 1.
179+
"timescale": {
180+
"speed": 1.0,
181+
"pitch": 1.0,
182+
"rate": 1.0
183+
},
184+
185+
// Uses amplification to create a shuddering effect, where the volume quickly oscillates.
186+
// Example: https://en.wikipedia.org/wiki/File:Fuse_Electronics_Tremolo_MK-III_Quick_Demo.ogv
187+
"tremolo": {
188+
"frequency": 2.0, // 0 < x
189+
"depth": 0.5 // 0 < x ≤ 1
190+
},
191+
192+
// Similar to tremolo. While tremolo oscillates the volume, vibrato oscillates the pitch.
193+
"vibrato": {
194+
"frequency": 2.0, // 0 < x ≤ 14
195+
"depth": 0.5 // 0 < x ≤ 1
196+
},
197+
198+
// Rotates the sound around the stereo channels/user headphones aka Audio Panning. It can produce an effect similar to: https://youtu.be/QB9EB8mTKcc (without the reverb)
199+
"rotation": {
200+
"rotationHz": 0 // The frequency of the audio rotating around the listener in Hz. 0.2 is similar to the example video above.
201+
},
202+
203+
// Distortion effect. It can generate some pretty unique audio effects.
204+
"distortion": {
205+
"sinOffset": 0,
206+
"sinScale": 1,
207+
"cosOffset": 0,
208+
"cosScale": 1,
209+
"tanOffset": 0,
210+
"tanScale": 1,
211+
"offset": 0,
212+
"scale": 1
213+
}
214+
215+
// Mixes both channels (left and right), with a configurable factor on how much each channel affects the other.
216+
// With the defaults, both channels are kept independent from each other.
217+
// Setting all factors to 0.5 means both channels get the same audio.
218+
"channelMix": {
219+
"leftToLeft": 1.0,
220+
"leftToRight": 0.0,
221+
"rightToLeft": 0.0,
222+
"rightToRight": 1.0,
223+
}
224+
225+
// Higher frequencies get suppressed, while lower frequencies pass through this filter, thus the name low pass.
226+
"lowPass": {
227+
"smoothing": 20.0
228+
}
148229
}
149230
```
150231

@@ -165,14 +246,18 @@ and you can send the same VOICE_SERVER_UPDATE to a new node.
165246

166247
See [LavalinkSocket.java](https://github.com/freyacodes/lavalink-client/blob/master/src/main/java/lavalink/client/io/LavalinkSocket.java) for client implementation
167248

168-
Position information about a player. Includes unix timestamp.
249+
This event includes:
250+
* Unix timestamp in milliseconds.
251+
* Track position in milliseconds. Omitted if not playing anything.
252+
* `connected` is true when connected to the voice gateway.
169253
```json
170254
{
171255
"op": "playerUpdate",
172256
"guildId": "...",
173257
"state": {
174258
"time": 1500467109,
175-
"position": 60000
259+
"position": 60000,
260+
"connected": true
176261
}
177262
}
178263
```
@@ -246,9 +331,14 @@ private void handleEvent(JSONObject json) throws IOException {
246331
);
247332
break;
248333
case "TrackExceptionEvent":
334+
JSONObject jsonEx = json.getJSONObject("exception");
249335
event = new TrackExceptionEvent(player,
250336
LavalinkUtil.toAudioTrack(json.getString("track")),
251-
new RemoteTrackException(json.getString("error"))
337+
new FriendlyException(
338+
jsonEx.getString("message"),
339+
FriendlyException.Severity.valueOf(jsonEx.getString("severity")),
340+
new RuntimeException(jsonEx.getString("cause"))
341+
)
252342
);
253343
break;
254344
case "TrackStuckEvent":
@@ -308,7 +398,8 @@ Response:
308398
"isStream": false,
309399
"position": 0,
310400
"title": "Rick Astley - Never Gonna Give You Up",
311-
"uri": "https://www.youtube.com/watch?v=dQw4w9WgXcQ"
401+
"uri": "https://www.youtube.com/watch?v=dQw4w9WgXcQ",
402+
"sourceName": "youtube"
312403
}
313404
}
314405
]
@@ -371,7 +462,8 @@ Response:
371462
"isStream": false,
372463
"position": 0,
373464
"title": "Rick Astley - Never Gonna Give You Up",
374-
"uri": "https://www.youtube.com/watch?v=dQw4w9WgXcQ"
465+
"uri": "https://www.youtube.com/watch?v=dQw4w9WgXcQ",
466+
"sourceName": "youtube"
375467
}
376468
```
377469

@@ -403,7 +495,8 @@ Response:
403495
"isStream": false,
404496
"position": 0,
405497
"title": "Rick Astley - Never Gonna Give You Up",
406-
"uri": "https://www.youtube.com/watch?v=dQw4w9WgXcQ"
498+
"uri": "https://www.youtube.com/watch?v=dQw4w9WgXcQ",
499+
"sourceName": "youtube"
407500
}
408501
},
409502
...
@@ -558,7 +651,7 @@ queue is then emptied and the events are then replayed.
558651
```
559652

560653
# Common pitfalls
561-
Admidtedly Lavalink isn't inherently the most intuitive thing ever, and people tend to run into the same mistakes over again. Please double check the following if you run into problems developing your client and you can't connect to a voice channel or play audio:
654+
Admittedly Lavalink isn't inherently the most intuitive thing ever, and people tend to run into the same mistakes over again. Please double check the following if you run into problems developing your client and you can't connect to a voice channel or play audio:
562655

563656
1. Check that you are forwarding sendWS events to **Discord**.
564657
2. Check that you are intercepting **VOICE_SERVER_UPDATE**s to **Lavalink**. Do not edit the event object from Discord.

LavalinkServer/application.yml.example

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,8 @@ lavalink:
1212
vimeo: true
1313
http: true
1414
local: false
15-
bufferDurationMs: 400
15+
bufferDurationMs: 400 # The duration of the NAS buffer. Higher values fare better against longer GC pauses
16+
frameBufferDurationMs: 5000 # How many milliseconds of audio to keep buffered
1617
youtubePlaylistLoadLimit: 6 # Number of pages at 100 each
1718
playerUpdateInterval: 5 # How frequently to send player updates to clients, in seconds
1819
youtubeSearchEnabled: true

LavalinkServer/build.gradle

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -39,15 +39,20 @@ dependencies {
3939
exclude group: "org.slf4j", module: "slf4j-api"
4040
}
4141
compile group: 'moe.kyokobot.koe', name: 'ext-udpqueue', version: koeVersion
42-
compile group: 'com.sedmelluq', name: 'lavaplayer', version: lavaplayerVersion
43-
compile group: 'com.sedmelluq', name: 'lavaplayer-ext-youtube-rotator', version: lavaplayerIpRotatorVersion
42+
compile group: 'com.github.walkyst', name: 'lavaplayer-fork', version: '1.3.96'
43+
//compile group: 'com.sedmelluq', name: 'lavaplayer', version: lavaplayerVersion
44+
compile(group: 'com.sedmelluq', name: 'lavaplayer-ext-youtube-rotator', version: lavaplayerIpRotatorVersion) {
45+
exclude group: 'com.sedmelluq', module: 'lavaplayer'
46+
}
47+
compile group: 'com.github.natanbc', name: 'lavadsp', version: lavaDspVersion
4448
compile group: 'org.jetbrains.kotlin', name: 'kotlin-reflect', version: kotlinVersion
4549

4650
compile group: 'org.springframework', name: 'spring-websocket', version: springWebSocketVersion
4751
compile group: 'ch.qos.logback', name: 'logback-classic', version: logbackVersion
4852
compile group: 'io.sentry', name: 'sentry-logback', version: sentryLogbackVersion
4953
compile group: 'com.github.oshi', name: 'oshi-core', version: oshiVersion
5054
compile group: 'org.json', name: 'json', version: jsonOrgVersion
55+
compile group: 'com.google.code.gson', name: 'gson', version: gsonVersion
5156
compile(group: 'org.springframework.boot', name: 'spring-boot-starter-web', version: springBootVersion) {
5257
exclude group: 'org.springframework.boot', module: 'spring-boot-starter-tomcat'
5358
}

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

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ import com.sedmelluq.discord.lavaplayer.source.http.HttpAudioSourceManager
88
import com.sedmelluq.discord.lavaplayer.source.local.LocalAudioSourceManager
99
import com.sedmelluq.discord.lavaplayer.source.soundcloud.DefaultSoundCloudDataReader
1010
import com.sedmelluq.discord.lavaplayer.source.soundcloud.DefaultSoundCloudFormatHandler
11-
import com.sedmelluq.discord.lavaplayer.source.soundcloud.DefaultSoundCloudHtmlDataLoader
11+
import com.sedmelluq.discord.lavaplayer.source.soundcloud.DefaultSoundCloudDataLoader
1212
import com.sedmelluq.discord.lavaplayer.source.soundcloud.DefaultSoundCloudPlaylistLoader
1313
import com.sedmelluq.discord.lavaplayer.source.soundcloud.SoundCloudAudioSourceManager
1414
import com.sedmelluq.discord.lavaplayer.source.twitch.TwitchStreamAudioSourceManager
@@ -45,6 +45,17 @@ class AudioPlayerConfiguration {
4545
audioPlayerManager.enableGcMonitoring()
4646
}
4747

48+
val defaultFrameBufferDuration = audioPlayerManager.frameBufferDuration
49+
serverConfig.frameBufferDurationMs?.let {
50+
if (it < 200) { // At the time of writing, LP enforces a minimum of 200ms.
51+
log.warn("Buffer size of {}ms is illegal. Defaulting to {}", it, defaultFrameBufferDuration)
52+
}
53+
54+
val bufferDuration = it.takeIf { it >= 200 } ?: defaultFrameBufferDuration
55+
log.debug("Setting frame buffer duration to {}", bufferDuration)
56+
audioPlayerManager.frameBufferDuration = bufferDuration
57+
}
58+
4859
if (sources.isYoutube) {
4960
val youtube = YoutubeAudioSourceManager(serverConfig.isYoutubeSearchEnabled)
5061
if (routePlanner != null) {
@@ -62,15 +73,15 @@ class AudioPlayerConfiguration {
6273
}
6374
if (sources.isSoundcloud) {
6475
val dataReader = DefaultSoundCloudDataReader();
65-
val htmlDataLoader = DefaultSoundCloudHtmlDataLoader();
76+
val dataLoader = DefaultSoundCloudDataLoader();
6677
val formatHandler = DefaultSoundCloudFormatHandler();
6778

6879
audioPlayerManager.registerSourceManager(SoundCloudAudioSourceManager(
6980
serverConfig.isSoundcloudSearchEnabled,
7081
dataReader,
71-
htmlDataLoader,
82+
dataLoader,
7283
formatHandler,
73-
DefaultSoundCloudPlaylistLoader(htmlDataLoader, dataReader, formatHandler)
84+
DefaultSoundCloudPlaylistLoader(dataLoader, dataReader, formatHandler)
7485
));
7586
}
7687
if (sources.isBandcamp) audioPlayerManager.registerSourceManager(BandcampAudioSourceManager())

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ public SentryConfiguration(ServerConfig serverConfig, SentryConfigProperties sen
3131
boolean warnDeprecatedDsnConfig = false;
3232
if (dsn == null || dsn.isEmpty()) {
3333
//try deprecated config location
34+
//noinspection deprecation
3435
dsn = serverConfig.getSentryDsn();
3536
warnDeprecatedDsnConfig = true;
3637
}

LavalinkServer/src/main/java/lavalink/server/config/ServerConfig.kt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ class ServerConfig {
3232
@get:Deprecated("use {@link SentryConfigProperties} instead.")
3333
var sentryDsn = ""
3434
var bufferDurationMs: Int? = null
35+
var frameBufferDurationMs: Int? = null
3536
var youtubePlaylistLoadLimit: Int? = null
3637
var playerUpdateInterval: Int? = 5
3738
var isGcWarnings = true

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

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
package lavalink.server.io
22

33
import lavalink.server.config.ServerConfig
4-
import org.slf4j.Logger
54
import org.slf4j.LoggerFactory
65
import org.springframework.beans.factory.annotation.Autowired
76
import org.springframework.http.HttpStatus
@@ -10,7 +9,6 @@ import org.springframework.http.server.ServerHttpResponse
109
import org.springframework.stereotype.Controller
1110
import org.springframework.web.socket.WebSocketHandler
1211
import org.springframework.web.socket.server.HandshakeInterceptor
13-
import java.util.Objects
1412

1513
@Controller
1614
class HandshakeInterceptorImpl @Autowired

0 commit comments

Comments
 (0)