Skip to content

Commit

Permalink
Merge pull request #551 from freyacodes/dev
Browse files Browse the repository at this point in the history
Release v3.4
  • Loading branch information
freyacodes authored Oct 26, 2021
2 parents 26cfc2a + c46cd72 commit a364833
Show file tree
Hide file tree
Showing 19 changed files with 502 additions and 89 deletions.
16 changes: 16 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,22 @@
Each release usually includes various fixes and improvements.
The most noteworthy of these, as well as any features and breaking changes, are listed here.

## 3.4
* New filters system
* Deprecation of `TrackExceptionEvent.error`, replaced by `TrackExceptionEvent.exception`
* Added the `connected` boolean to player updates.
* Updated lavaplayer, fixes Soundcloud
* Added source name to REST api track objects
* Clients are now requested to make their name known during handshake

Contributors:
[@freyacodes](https://github.com/freyacodes),
[@duncte123](https://github.com/duncte123),
[@DaliborTrampota](https://github.com/DaliborTrampota),
[@Mandruyd](https://github.com/Mandruyd),
[@Allvaa](https://github.com/@Allvaa), and
[@TopiSenpai](https://github.com/TopiSenpai)

## 3.3.2.5
* Update Lavaplayer to 1.3.76

Expand Down
129 changes: 111 additions & 18 deletions IMPLEMENTATION.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,14 @@ The Java client has support for JDA, but can also be adapted to work with other
* You must be able to send messages via a shard's mainWS connection.
* You must be able to intercept voice server updates from mainWS on your shard connection.

## Significant changes v3.3 -> v3.4
* Added filters
* The `error` string on the `TrackExceptionEvent` has been deprecated and replaced by
the `exception` object following the same structure as the `LOAD_FAILED` error on [`/loadtracks`](#rest-api)
* Added the `connected` boolean to player updates.
* Added source name to REST api track objects
* Clients are now requested to make their name known during handshake

## Significant changes v2.0 -> v3.0
* The response of `/loadtracks` has been completely changed (again since the initial v3.0 pre-release).
* Lavalink v3.0 now reports its version as a handshake response header.
Expand Down Expand Up @@ -41,8 +49,8 @@ the JDA client takes advantage of JDA's websocket write thread to send OP 4s for
When opening a websocket connection, you must supply 3 required headers:
```
Authorization: Password matching the server config
Num-Shards: Total number of shards your bot is operating on
User-Id: The user id of the bot you are playing music with
Client-Name: The name of your client. Optionally in the format NAME/VERSION
```

### Outgoing messages
Expand Down Expand Up @@ -81,7 +89,7 @@ If `pause` is set to true, the playback will be paused. This is an optional fiel
"endTime": "120000",
"volume": "100",
"noReplace": false,
"pause": false,
"pause": false
}
```

Expand Down Expand Up @@ -128,23 +136,96 @@ Volume may range from 0 to 1000. 100 is default.
}
```

#### Using the player equalizer
#### Using filters

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.
The `filters` op sets the filters. All the filters are optional, and leaving them out of this message will disable them.

```json
Adding a filter can have adverse effects on performance. These filters force Lavaplayer to decode all audio to PCM,
even if the input was already in the Opus format that Discord uses. This means decoding and encoding audio that would
normally require very little processing. This is often the case with YouTube videos.

JSON comments are for illustration purposes only, and will not be accepted by the server.

Note that filters may take a moment to apply.

```yaml
{
"op": "equalizer",
"op": "filters",
"guildId": "...",
"bands": [

// Float value where 1.0 is 100%. Values >1.0 may cause clipping
"volume": 1.0,

// 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.
"equalizer": [
{
"band": 0,
"gain": 0.2
}
]
],

// Uses equalization to eliminate part of a band, usually targeting vocals.
"karaoke": {
"level": 1.0,
"monoLevel": 1.0,
"filterBand": 220.0,
"filterWidth": 100.0
},

// Changes the speed, pitch, and rate. All default to 1.
"timescale": {
"speed": 1.0,
"pitch": 1.0,
"rate": 1.0
},

// Uses amplification to create a shuddering effect, where the volume quickly oscillates.
// Example: https://en.wikipedia.org/wiki/File:Fuse_Electronics_Tremolo_MK-III_Quick_Demo.ogv
"tremolo": {
"frequency": 2.0, // 0 < x
"depth": 0.5 // 0 < x ≤ 1
},

// Similar to tremolo. While tremolo oscillates the volume, vibrato oscillates the pitch.
"vibrato": {
"frequency": 2.0, // 0 < x ≤ 14
"depth": 0.5 // 0 < x ≤ 1
},

// 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)
"rotation": {
"rotationHz": 0 // The frequency of the audio rotating around the listener in Hz. 0.2 is similar to the example video above.
},

// Distortion effect. It can generate some pretty unique audio effects.
"distortion": {
"sinOffset": 0,
"sinScale": 1,
"cosOffset": 0,
"cosScale": 1,
"tanOffset": 0,
"tanScale": 1,
"offset": 0,
"scale": 1
}

// Mixes both channels (left and right), with a configurable factor on how much each channel affects the other.
// With the defaults, both channels are kept independent from each other.
// Setting all factors to 0.5 means both channels get the same audio.
"channelMix": {
"leftToLeft": 1.0,
"leftToRight": 0.0,
"rightToLeft": 0.0,
"rightToRight": 1.0,
}

// Higher frequencies get suppressed, while lower frequencies pass through this filter, thus the name low pass.
"lowPass": {
"smoothing": 20.0
}
}
```

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

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

Position information about a player. Includes unix timestamp.
This event includes:
* Unix timestamp in milliseconds.
* Track position in milliseconds. Omitted if not playing anything.
* `connected` is true when connected to the voice gateway.
```json
{
"op": "playerUpdate",
"guildId": "...",
"state": {
"time": 1500467109,
"position": 60000
"position": 60000,
"connected": true
}
}
```
Expand Down Expand Up @@ -246,9 +331,14 @@ private void handleEvent(JSONObject json) throws IOException {
);
break;
case "TrackExceptionEvent":
JSONObject jsonEx = json.getJSONObject("exception");
event = new TrackExceptionEvent(player,
LavalinkUtil.toAudioTrack(json.getString("track")),
new RemoteTrackException(json.getString("error"))
new FriendlyException(
jsonEx.getString("message"),
FriendlyException.Severity.valueOf(jsonEx.getString("severity")),
new RuntimeException(jsonEx.getString("cause"))
)
);
break;
case "TrackStuckEvent":
Expand Down Expand Up @@ -308,7 +398,8 @@ Response:
"isStream": false,
"position": 0,
"title": "Rick Astley - Never Gonna Give You Up",
"uri": "https://www.youtube.com/watch?v=dQw4w9WgXcQ"
"uri": "https://www.youtube.com/watch?v=dQw4w9WgXcQ",
"sourceName": "youtube"
}
}
]
Expand Down Expand Up @@ -371,7 +462,8 @@ Response:
"isStream": false,
"position": 0,
"title": "Rick Astley - Never Gonna Give You Up",
"uri": "https://www.youtube.com/watch?v=dQw4w9WgXcQ"
"uri": "https://www.youtube.com/watch?v=dQw4w9WgXcQ",
"sourceName": "youtube"
}
```

Expand Down Expand Up @@ -403,7 +495,8 @@ Response:
"isStream": false,
"position": 0,
"title": "Rick Astley - Never Gonna Give You Up",
"uri": "https://www.youtube.com/watch?v=dQw4w9WgXcQ"
"uri": "https://www.youtube.com/watch?v=dQw4w9WgXcQ",
"sourceName": "youtube"
}
},
...
Expand Down Expand Up @@ -558,7 +651,7 @@ queue is then emptied and the events are then replayed.
```

# Common pitfalls
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:
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:

1. Check that you are forwarding sendWS events to **Discord**.
2. Check that you are intercepting **VOICE_SERVER_UPDATE**s to **Lavalink**. Do not edit the event object from Discord.
Expand Down
3 changes: 2 additions & 1 deletion LavalinkServer/application.yml.example
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,8 @@ lavalink:
vimeo: true
http: true
local: false
bufferDurationMs: 400
bufferDurationMs: 400 # The duration of the NAS buffer. Higher values fare better against longer GC pauses
frameBufferDurationMs: 5000 # How many milliseconds of audio to keep buffered
youtubePlaylistLoadLimit: 6 # Number of pages at 100 each
playerUpdateInterval: 5 # How frequently to send player updates to clients, in seconds
youtubeSearchEnabled: true
Expand Down
9 changes: 7 additions & 2 deletions LavalinkServer/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -39,15 +39,20 @@ dependencies {
exclude group: "org.slf4j", module: "slf4j-api"
}
compile group: 'moe.kyokobot.koe', name: 'ext-udpqueue', version: koeVersion
compile group: 'com.sedmelluq', name: 'lavaplayer', version: lavaplayerVersion
compile group: 'com.sedmelluq', name: 'lavaplayer-ext-youtube-rotator', version: lavaplayerIpRotatorVersion
compile group: 'com.github.walkyst', name: 'lavaplayer-fork', version: '1.3.96'
//compile group: 'com.sedmelluq', name: 'lavaplayer', version: lavaplayerVersion
compile(group: 'com.sedmelluq', name: 'lavaplayer-ext-youtube-rotator', version: lavaplayerIpRotatorVersion) {
exclude group: 'com.sedmelluq', module: 'lavaplayer'
}
compile group: 'com.github.natanbc', name: 'lavadsp', version: lavaDspVersion
compile group: 'org.jetbrains.kotlin', name: 'kotlin-reflect', version: kotlinVersion

compile group: 'org.springframework', name: 'spring-websocket', version: springWebSocketVersion
compile group: 'ch.qos.logback', name: 'logback-classic', version: logbackVersion
compile group: 'io.sentry', name: 'sentry-logback', version: sentryLogbackVersion
compile group: 'com.github.oshi', name: 'oshi-core', version: oshiVersion
compile group: 'org.json', name: 'json', version: jsonOrgVersion
compile group: 'com.google.code.gson', name: 'gson', version: gsonVersion
compile(group: 'org.springframework.boot', name: 'spring-boot-starter-web', version: springBootVersion) {
exclude group: 'org.springframework.boot', module: 'spring-boot-starter-tomcat'
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import com.sedmelluq.discord.lavaplayer.source.http.HttpAudioSourceManager
import com.sedmelluq.discord.lavaplayer.source.local.LocalAudioSourceManager
import com.sedmelluq.discord.lavaplayer.source.soundcloud.DefaultSoundCloudDataReader
import com.sedmelluq.discord.lavaplayer.source.soundcloud.DefaultSoundCloudFormatHandler
import com.sedmelluq.discord.lavaplayer.source.soundcloud.DefaultSoundCloudHtmlDataLoader
import com.sedmelluq.discord.lavaplayer.source.soundcloud.DefaultSoundCloudDataLoader
import com.sedmelluq.discord.lavaplayer.source.soundcloud.DefaultSoundCloudPlaylistLoader
import com.sedmelluq.discord.lavaplayer.source.soundcloud.SoundCloudAudioSourceManager
import com.sedmelluq.discord.lavaplayer.source.twitch.TwitchStreamAudioSourceManager
Expand Down Expand Up @@ -45,6 +45,17 @@ class AudioPlayerConfiguration {
audioPlayerManager.enableGcMonitoring()
}

val defaultFrameBufferDuration = audioPlayerManager.frameBufferDuration
serverConfig.frameBufferDurationMs?.let {
if (it < 200) { // At the time of writing, LP enforces a minimum of 200ms.
log.warn("Buffer size of {}ms is illegal. Defaulting to {}", it, defaultFrameBufferDuration)
}

val bufferDuration = it.takeIf { it >= 200 } ?: defaultFrameBufferDuration
log.debug("Setting frame buffer duration to {}", bufferDuration)
audioPlayerManager.frameBufferDuration = bufferDuration
}

if (sources.isYoutube) {
val youtube = YoutubeAudioSourceManager(serverConfig.isYoutubeSearchEnabled)
if (routePlanner != null) {
Expand All @@ -62,15 +73,15 @@ class AudioPlayerConfiguration {
}
if (sources.isSoundcloud) {
val dataReader = DefaultSoundCloudDataReader();
val htmlDataLoader = DefaultSoundCloudHtmlDataLoader();
val dataLoader = DefaultSoundCloudDataLoader();
val formatHandler = DefaultSoundCloudFormatHandler();

audioPlayerManager.registerSourceManager(SoundCloudAudioSourceManager(
serverConfig.isSoundcloudSearchEnabled,
dataReader,
htmlDataLoader,
dataLoader,
formatHandler,
DefaultSoundCloudPlaylistLoader(htmlDataLoader, dataReader, formatHandler)
DefaultSoundCloudPlaylistLoader(dataLoader, dataReader, formatHandler)
));
}
if (sources.isBandcamp) audioPlayerManager.registerSourceManager(BandcampAudioSourceManager())
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ public SentryConfiguration(ServerConfig serverConfig, SentryConfigProperties sen
boolean warnDeprecatedDsnConfig = false;
if (dsn == null || dsn.isEmpty()) {
//try deprecated config location
//noinspection deprecation
dsn = serverConfig.getSentryDsn();
warnDeprecatedDsnConfig = true;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ class ServerConfig {
@get:Deprecated("use {@link SentryConfigProperties} instead.")
var sentryDsn = ""
var bufferDurationMs: Int? = null
var frameBufferDurationMs: Int? = null
var youtubePlaylistLoadLimit: Int? = null
var playerUpdateInterval: Int? = 5
var isGcWarnings = true
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
package lavalink.server.io

import lavalink.server.config.ServerConfig
import org.slf4j.Logger
import org.slf4j.LoggerFactory
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.http.HttpStatus
Expand All @@ -10,7 +9,6 @@ import org.springframework.http.server.ServerHttpResponse
import org.springframework.stereotype.Controller
import org.springframework.web.socket.WebSocketHandler
import org.springframework.web.socket.server.HandshakeInterceptor
import java.util.Objects

@Controller
class HandshakeInterceptorImpl @Autowired
Expand Down
Loading

0 comments on commit a364833

Please sign in to comment.