Skip to content
forked from schnapster/Magma

A voice only API for Discord, focused on delivering music at scale.

License

Notifications You must be signed in to change notification settings

freyacoded/Magma

 
 

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Magma

Release Build Status Master Branch License SonarCloud

A voice only API for Discord, focused on delivering music at scale.

Lava? Magma?

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:

Only AudioSendHandlers that provide packets in the opus format are supported. Recommended providers:

Get started

Add Magma to your project

  • JitPack for builds straight from github code

Replace x.y.z in the snippets below with the desired version. Latest: Release

Gradle build.gradle
    repositories {
        maven { url 'https://jitpack.io' }
    }

    dependencies {
        compile group: 'space.npstr', name: 'Magma', version: 'x.y.z'
    }
Maven pom.xml
    <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>

Sample code

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.

DSL

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();
    

Api

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());
        }
    }

Numbers

(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.

CPU Usage

Click me

CPU Usage

Threads

Click me

Threads

Garbage Collection

Click me

GC Time Spent
GC Runs

Memory

Click me

JVM Memory
Process Memory

Audio Frames

Click me

Audio Frames Lost

Debugging

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 

Changelog

Expect breaking changes between minor versions while v1 has not been released.

v0.6.0

  • Introduce MagmaApi#getEventStream that allows user code to consume events from Magma, for example when the websocket is closed.

v0.5.0

  • Port the remaining changes of JDA 3.7 (see #651), notably the switch from byte[]s to ByteBuffers in most places. This includes a backwards incompatible change to IPacketProvider, marking it as a non-threadsafe class.
    Known issues: Applications using japp 1.2 or below have broken audio output.

v0.4.5

  • Use direct byte buffers (off heap) for Undertow

v0.4.4

  • 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

v0.4.3

  • Fix 4003s closes due to sending events before identifying

v0.4.0

  • Opus conversion removed. Send handlers are expected to provide opus packets.
  • Fix for a possible leak of send handlers

v0.3.3

  • Fully event based AudioConnection
  • Correct Schedulers used for event processing
  • Dependency updates
  • Code quality improvements via SonarCloud

v0.3.2

  • Log endpoint to which the connection has been closed along with the reason
  • Share a BufferPool between all connections to avoid memory leak

v0.3.1

  • Dependency updates
  • Additional experimental build against Java 11

v0.3.0

  • Type and parameter safety in the Api by introducing a simple DSL

v0.2.1

  • Handle op 14 events

v0.2.0

  • Build with java 10

v0.1.2

  • Implement v4 of Discords Voice API

v0.1.1

  • Depend on opus-java through jitpack instead of a git submodule

v0.1.0

  • 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

v0.0.1

  • It's working, including resumes.

Dependencies:

About

A voice only API for Discord, focused on delivering music at scale.

Resources

License

Stars

Watchers

Forks

Packages

No packages published

Languages

  • Java 100.0%