A voice only API for Discord, focused on delivering music at scale.
Notable features:
- Event based and non-blocking at its core
Not supported:
- Audio Receiving
Magma is a heavily modified fork of JDA-Audio (Apache 2.0)
Big shout-out to the to the original authors and maintainers for doing great work!
Besides making use of most of the code for handling audio packets, Magma reuses some of JDAs APIs, namely:
- IAudioSendSystem
- IAudioSendFactory
- IPacketProvider
- AudioSendHandler
Magma does not ship any implementations for IAudioSendSystem and IAudioSendFactory.
It is important that the implementation you choose will never call any method of the packet provider but
IPacketProvider#getNextPacket
, because none of the others are supported by Magma.
Recommended implementations:
- https://github.com/sedmelluq/jda-nas
- https://github.com/Shredder121/jda-async-packetprovider
Only AudioSendHandler
s that provide packets in the opus format are supported.
Recommended providers:
- JitPack for builds straight from github code
Replace x.y.z
in the snippets below with the desired version. Latest:
repositories {
maven { url 'https://jitpack.io' }
}
dependencies {
compile group: 'space.npstr', name: 'Magma', version: 'x.y.z'
}
<repositories>
<repository>
<id>jitpack.io</id>
<url>https://jitpack.io</url>
</repository>
</repositories>
<dependency>
<groupId>space.npstr</groupId>
<artifactId>Magma</artifactId>
<version>x.z.y</version>
</dependency>
Discord supports one single audio connection per user and guild (also called a "member"). This means, an audio connection is exactly identified by those two datapoints, and all of the methods of Magma require those to correctly identify the connection that you want to open/close/change something about.
Magma uses immutables.org to ensure type and parameter safety, both internally and in the Api you are going to use. Concretely, the Api makes use of immutable Member and ServerUpdate objects.
Member member = MagmaMember.builder()
.userId("...")
.guildId("...")
.build();
ServerUpdate = MagmaServerUpdate.builder()
.sessionId("...")
.endpoint("...")
.token("...")
.build();
Typical usage of the methods offered by the MagmaApi:
IAudioSendFactory audioSendFactory = <your implementation here>;
AudioSendHandler sendHandler = <your implementation here>;
MagmaApi magmaApi = MagmaApi.of(__ -> audioSendFactory);
magmaApi.provideVoiceServerUpdate(member, serverUpdate);
magmaApi.setSendHandler(member, sendHandler);
// music plays, then later:
magmaApi.setSendHandler(member, someOtherHandler);
// other handler plays music / sounds
// to clean up:
magmaApi.removeSendHandler(member);
magmaApi.closeConnection(member);
// on shutting down
magmaApi.shutdown();
// Calling any other methods of a MagmaApi object after having called shutdown()
// will result in undefined behaviour. Do not do this, create a new MagmaApi instead.
// Please note that you are strongly encouraged to use a single MagmaApi object throughout
// the lifecycle of your application.
None of those calls are blocking, as they are translated into events to be processed as soon as possible. Currently, there is no feedback as to when and how these are processed.
You can subscribe to a stream of MagmaEvents
through MagmaApi#getEventStream
:
...
magmaApi.getEventStream()
.subscribe(this::handleMagmaEvent);
...
private void handleMagmaEvent(MagmaEvent magmaEvent) {
if (magmaEvent instanceof space.npstr.magma.events.api.WebSocketClosed) {
WebSocketClosed wsClosedEvent = (WebSocketClosed) magmaEvent;
log.info("WS in guild {} closed with code {} and reason {}", wsClosedEvent.getMember().getGuildId(),
wsClosedEvent.getCloseCode(), wsClosedEvent.getReason());
}
}
(last updated for 0.2.1)
Magma has been written with Lavalink in mind, numbers shown here compare vanilla Lavalink to a Magma-based branch.
Graphs by courtesy of FredBoat.
Enabling TRACE/DEBUG logs can help with pinpointing and reporting issues.
To get the most out of these log levels, make sure your chosen logger implementation and configuration
prints additional MDC information. The MDC keys that Magma uses can be found in the MdcKeys
class.
If you are running Magma in a Spring Boot application with logback as the logger implementation
(Lavalink does this), adding these following lines to your Spring Application's application.yaml
will show the MDC information:
logging:
pattern:
level: "[%mdc] %5p"
level:
space.npstr.magma: TRACE
Expect breaking changes between minor versions while v1 has not been released.
- Introduce
MagmaApi#getEventStream
that allows user code to consume events from Magma, for example when the websocket is closed.
- Port the remaining changes of JDA 3.7 (see #651),
notably the switch from
byte[]
s toByteBuffer
s in most places. This includes a backwards incompatible change toIPacketProvider
, marking it as a non-threadsafe class.
Known issues: Applications using japp 1.2 or below have broken audio output.
- Use direct byte buffers (off heap) for Undertow
- Send our SSRC along with OP 5 Speaking updates
- Add MDC and more trace logs to enable better reporting of issues
- Update close code handling for expected 1xxx codes and warnings on suspicious closes
- Deal with Opus interpolation
- Fix 4003s closes due to sending events before identifying
- Opus conversion removed. Send handlers are expected to provide opus packets.
- Fix for a possible leak of send handlers
- Fully event based AudioConnection
- Correct Schedulers used for event processing
- Dependency updates
- Code quality improvements via SonarCloud
- Log endpoint to which the connection has been closed along with the reason
- Share a BufferPool between all connections to avoid memory leak
- Dependency updates
- Additional experimental build against Java 11
- Type and parameter safety in the Api by introducing a simple DSL
- Handle op 14 events
- Build with java 10
- Implement v4 of Discords Voice API
- Depend on opus-java through jitpack instead of a git submodule
- Ignore more irrelevant events
- Smol docs update
- Licensed as Apache 2.0
- Use IP provided by Discord instead of endpoint address for the UDP connection
- It's working, including resumes.
-
JSON In Java:
-
Simple Logging Facade for Java:
-
Spring Webflux:
-
Undertow Core:
-
SpotBugs Annotations:
-
Immutables.org Value: