Skip to content

Releases: KyokoBot/koe

3.1.0

Choose a tag to compare

@alula alula released this 07 Oct 11:18
e9147ed

What's Changed

Significant optimizations for transport encryption and a lot of bug fixes for long-standing issues.

Two defaults changed, see Behavior changes and the migration guide.

Security

  • With DAVE enabled, audio and video were sent without E2EE until the key ratchet was ready. Koe now waits for it before polling audio. Anything sent before then is replaced with silence or dropped. See GHSA-pw4q-x846-j45m.

Performance

  • XChaCha20-Poly1305 is ~20% faster and no longer allocates per packet (it used to allocate 2-10 KB per packet).
  • XSalsa20-Poly1305 is ~14% faster.
  • AES-GCM uses JCE directly instead of going through Tink, and reuses the Cipher and key for the whole session.
  • Koe prefers AES-GCM only if the JVM uses AES instructions, otherwise XChaCha20-Poly1305. Without them AES-GCM is several times slower, e.g. on JDK 17 on Apple Silicon.
  • DAVE can use FFM (Java 22+) instead of JNI, which has lower call overhead.

Average time and memory allocated to encrypt one packet on a single thread, measured with JMH, 3.0.0 → 3.1.0:

Mode Payload Zen 4 x86-64, Temurin 25 Apple M2, Temurin 17 Allocated per packet (x86-64)
aead_xchacha20_poly1305_rtpsize 160 B 1600 ns → 1261 ns 1670 ns → 1338 ns 2184 B → 0 B
aead_xchacha20_poly1305_rtpsize 1276 B 8664 ns → 6995 ns 9774 ns → 7576 ns 10600 B → 0 B
xsalsa20_poly1305_lite 160 B 1164 ns → 998 ns 1267 ns → 1067 ns 0 B
xsalsa20_poly1305_lite 1276 B 7713 ns → 6644 ns 8263 ns → 7224 ns 0 B
aead_aes256_gcm_rtpsize 160 B 347 ns → 339 ns 3567 ns → 3368 ns 1440 B → 1456 B
aead_aes256_gcm_rtpsize 1276 B 698 ns → 701 ns 20826 ns → 19931 ns 3808 B → 2848 B

160 B is a 20 ms Opus frame at 64 kbps, 1276 B is the largest Opus frame.

On the M2, switching to XChaCha20-Poly1305 makes encryption ~2.5x faster.

Removed dependencies

  • Tink. AES-GCM now uses JCE and XChaCha20-Poly1305 is implemented in Koe.

Bug fixes

  • connect() never completed if the voice gateway connection failed, e.g. for an endpoint with a wss:// prefix. Endpoints with a scheme now work, and failed connections complete exceptionally. (#23)
  • udp-queue kept sending packets to the old voice server after a server change.
  • Fixed race and reentrancy bugs in DAVE handling.
  • Fixed SSRCs above 2^31 being sent as negative numbers, which could make bots silent in stage channels. Stage channels also need a workaround for a Discord bug, see DISCORD_VOICE_QUIRKS.md. (#43)
  • Fixed the speaking state not being resent after a new session description.
  • Fixed packets sent with an RTP header extension (ConnectionHandler.sendFrame with extension = true) failing to decrypt with the _rtpsize modes, and the extension being end-to-end encrypted by DAVE along with the frame.
  • Fixed various internal minor bugs

Behavior changes

  • Voice gateway connections time out after 10 seconds. Change it with KoeOptionsBuilder.setGatewayConnectTimeout (0 disables it).
  • Koe no longer sends a speaking update with an empty mask when playback stops, since it could cut off buffered audio. KoeOptionsBuilder.setSendSpeakingStop(true) restores the old behavior. (#21)
  • The encryption mode is picked by preference instead of the server's order, see Performance.

Improvements

  • To use DAVE over FFM, add moe.kyokobot.libdave:impl-ffm. Koe falls back to JNI if it's missing or fails to load. It's built for Java 22, so projects targeting older Java need:
    runtimeOnly("moe.kyokobot.libdave:impl-ffm:VERSION") {
        attributes {
            attribute(TargetJvmVersion.TARGET_JVM_VERSION_ATTRIBUTE, 22)
        }
    }
  • The secret key from the voice server is validated.
  • When resuming fails with 4006 (session no longer valid), Koe now starts a new session instead of giving up. If that fails too, the new KoeEventListener.sessionLost event tells you to rejoin the voice channel.
  • Added MediaConnection.setSpeakingMask and getSpeakingMask.
  • Added the aead_aes256_gcm and xsalsa20_poly1305_lite_rtpsize encryption modes, so every documented mode is supported. Discord itself no longer offers them.
  • All KoeEventListener methods now have empty default implementations, so you can implement only the events you need. KoeEventAdapter is deprecated.
  • Updated Netty to 4.2.18.Final and libdave-jvm to 0.2.0.

New experimental APIs

May change in minor releases.

  • KoeOptionsBuilderExperimental.setCipherPreferencePolicy to choose the encryption mode yourself.
  • CipherBenchmark to measure the encryption modes on the current JVM and build a policy from the results. Results can be saved as JSON.
  • KoeOptionsBuilderExperimental.setDaveFactoryProvider to use your own DAVE implementation selection strategy.

Documentation

  • Added JVM flags for Java 24+ to the README. Without them Netty can't use sun.misc.Unsafe and falls back to slower buffers.
  • Added DISCORD_VOICE_QUIRKS.md that publicly documents known Discord voice server quirks :)
  • Interfaces only Koe implements are now marked @ApiStatus.NonExtendable, so they may get new methods in minor releases.

Development

  • Added unit tests and CI for pull requests.
  • API compatibility is checked against the last release with japicmp.
  • Snapshots are no longer uploaded to Maven Central.

Full Changelog: 3.0.0...3.1.0

3.0.0

Choose a tag to compare

@alula alula released this 03 Oct 03:15
7436cf8

What's Changed

THIS IS A MAJOR RELEASE WITH MANY BREAKING CHANGES

PLEASE READ THE MIGRATION GUIDE (for this specific release)

https://github.com/KyokoBot/koe/blob/3.0.0/MIGRATION.md

Full Changelog: 2.2.0...3.0.0

3.0.0-pre6

3.0.0-pre6 Pre-release
Pre-release

Choose a tag to compare

@alula alula released this 06 Mar 22:05
7436cf8

What's Changed

THIS IS A MAJOR RELEASE WITH MANY BREAKING CHANGES

PLEASE READ THE MIGRATION GUIDE (for this specific release)

  • Updated libdave-jvm to 0.1.2 (published on Maven Central)
  • Set up publishing on Maven Central.

https://github.com/KyokoBot/koe/blob/3.0.0-pre6/MIGRATION.md

Full Changelog: 2.2.0-rc2...3.0.0-pre6

** Changelog since last prerelease**: 3.0.0-pre5...3.0.0-pre6

3.0.0-pre5

3.0.0-pre5 Pre-release
Pre-release

Choose a tag to compare

@alula alula released this 01 Mar 18:25
fc1bbab

What's Changed

THIS IS A MAJOR RELEASE WITH MANY BREAKING CHANGES

PLEASE READ THE MIGRATION GUIDE (for this specific release)

  • Added support for forwarding logs from libdave (Requires at least libdave-jvm 5e12c7dff)
  • Fixed data races in DAVEManager leading to JVM crashes.

https://github.com/KyokoBot/koe/blob/3.0.0-pre5/MIGRATION.md

Full Changelog: 2.2.0-rc2...3.0.0-pre5

** Changelog since last prerelease**: 3.0.0-pre4...3.0.0-pre5

3.0.0-pre4

3.0.0-pre4 Pre-release
Pre-release

Choose a tag to compare

@alula alula released this 01 Mar 11:22
2782200

What's Changed

THIS IS A MAJOR RELEASE WITH MANY BREAKING CHANGES

PLEASE READ THE MIGRATION GUIDE (for this specific release)

  • Fixed data races in DAVEManager leading to JVM crashes.

https://github.com/KyokoBot/koe/blob/3.0.0-pre4/MIGRATION.md

Full Changelog: 2.2.0-rc2...3.0.0-pre4

** Changelog since last prerelease**: 3.0.0-pre3...3.0.0-pre4

3.0.0-pre3

3.0.0-pre3 Pre-release
Pre-release

Choose a tag to compare

@alula alula released this 24 Feb 19:51
379c5dd

What's Changed

THIS IS A MAJOR RELEASE WITH MANY BREAKING CHANGES

PLEASE READ THE MIGRATION GUIDE (for this specific release)

  • Fixed a bug with DAVE not working unless the Netty allocator is configured to always allocate direct buffers.

https://github.com/KyokoBot/koe/blob/3.0.0-pre3/MIGRATION.md

Full Changelog: 2.2.0-rc2...3.0.0-pre3

** Changelog since last prerelease**: 3.0.0-pre2...3.0.0-pre3

3.0.0-pre2

3.0.0-pre2 Pre-release
Pre-release

Choose a tag to compare

@alula alula released this 24 Feb 17:32
1f509c9

What's Changed

THIS IS A MAJOR RELEASE WITH MANY BREAKING CHANGES

PLEASE READ THE MIGRATION GUIDE (for this specific release)

  • Fixed memory leaks
  • Fixed bugs caued by incomplete MLS groups

https://github.com/KyokoBot/koe/blob/3.0.0-pre2/MIGRATION.md

Full Changelog: 2.2.0-rc2...3.0.0-pre2

** Changelog since last prerelease**: 3.0.0-pre1...3.0.0-pre2

3.0.0-pre1

3.0.0-pre1 Pre-release
Pre-release

Choose a tag to compare

@alula alula released this 24 Feb 05:30
374c321

What's Changed

THIS IS A MAJOR RELEASE WITH MANY BREAKING CHANGES

PLEASE READ THE MIGRATION GUIDE (for this specific release)

https://github.com/KyokoBot/koe/blob/3.0.0-pre1/MIGRATION.md

  • Actually keep track of the last received sequence by @viztea in #40
  • add github actions to publish koe by @topi314 in #42

Full Changelog: 2.2.0-rc2...3.0.0-pre1

Note: This release has been retagged from 317ab86 to 374c321 to disable JitPack builds

2.2.0

Choose a tag to compare

@alula alula released this 01 Mar 16:07
8810540

What's Changed

  • add close code constants & handle reconnect of more close codes by @topi314 in #36
  • fix: remove unnecessary close codes from reconnect handling by @topi314 in #39
  • Actually keep track of the last received sequence by @viztea in #40

This is the final release in 2.x series. It does not support DAVE and will remain broken as of 2nd March 2026.

Full Changelog: 2.1.1...2.2.0

2.2.0-rc2

2.2.0-rc2 Pre-release
Pre-release

Choose a tag to compare

@alula alula released this 19 Jun 20:16

What's Changed

  • add close code constants & handle reconnect of more close codes by @topi314 in #36
  • fix: remove unnecessary close codes from reconnect handling by @topi314 in #39
  • fix: port :80 stripping logic (#38) and added an option (KoeOptionsBuilder#setEnableWSSPortOverride()) to disable this behavior completely (Koe will always use the specified port)

API Changes

  • Deprecated public KoeOptions constructor. Use KoeOptions.builder() if you're not using it already.

Full Changelog: 2.1.1...2.2.0-rc2