Search in sources :

Example 1 with ExceptionEvent

use of net.dv8tion.jda.api.events.ExceptionEvent in project JDA by DV8FromTheWorld.

the class Request method onSuccess.

public void onSuccess(T successObj) {
    if (done)
        return;
    done = true;
    api.getCallbackPool().execute(() -> {
        try (ThreadLocalReason.Closable __ = ThreadLocalReason.closable(localReason);
            CallbackContext ___ = CallbackContext.getInstance()) {
            onSuccess.accept(successObj);
        } catch (Throwable t) {
            RestActionImpl.LOG.error("Encountered error while processing success consumer", t);
            if (t instanceof Error) {
                api.handleEvent(new ExceptionEvent(api, t, true));
                throw (Error) t;
            }
        }
    });
}
Also used : ExceptionEvent(net.dv8tion.jda.api.events.ExceptionEvent) ThreadLocalReason(net.dv8tion.jda.api.audit.ThreadLocalReason) CallbackContext(net.dv8tion.jda.internal.requests.CallbackContext)

Example 2 with ExceptionEvent

use of net.dv8tion.jda.api.events.ExceptionEvent in project JDA by DV8FromTheWorld.

the class AudioWebSocket method handleCallbackError.

@Override
public void handleCallbackError(WebSocket websocket, Throwable cause) {
    LOG.error("There was some audio websocket error", cause);
    JDAImpl api = getJDA();
    api.handleEvent(new ExceptionEvent(api, cause, true));
}
Also used : ExceptionEvent(net.dv8tion.jda.api.events.ExceptionEvent) JDAImpl(net.dv8tion.jda.internal.JDAImpl)

Example 3 with ExceptionEvent

use of net.dv8tion.jda.api.events.ExceptionEvent in project JDA by DV8FromTheWorld.

the class AudioConnection method setupReceiveThread.

private synchronized void setupReceiveThread() {
    if (receiveThread == null) {
        receiveThread = new Thread(() -> {
            getJDA().setContext();
            try {
                udpSocket.setSoTimeout(1000);
            } catch (SocketException e) {
                LOG.error("Couldn't set SO_TIMEOUT for UDP socket", e);
            }
            while (!udpSocket.isClosed() && !Thread.currentThread().isInterrupted()) {
                DatagramPacket receivedPacket = new DatagramPacket(new byte[1920], 1920);
                try {
                    udpSocket.receive(receivedPacket);
                    boolean shouldDecode = receiveHandler != null && (receiveHandler.canReceiveUser() || receiveHandler.canReceiveCombined());
                    boolean canReceive = receiveHandler != null && (receiveHandler.canReceiveUser() || receiveHandler.canReceiveCombined() || receiveHandler.canReceiveEncoded());
                    if (canReceive && webSocket.getSecretKey() != null) {
                        if (!couldReceive) {
                            couldReceive = true;
                            sendSilentPackets();
                        }
                        AudioPacket decryptedPacket = AudioPacket.decryptAudioPacket(webSocket.encryption, receivedPacket, webSocket.getSecretKey());
                        if (decryptedPacket == null)
                            continue;
                        int ssrc = decryptedPacket.getSSRC();
                        final long userId = ssrcMap.get(ssrc);
                        Decoder decoder = opusDecoders.get(ssrc);
                        if (userId == ssrcMap.getNoEntryValue()) {
                            ByteBuffer audio = decryptedPacket.getEncodedAudio();
                            // and as such, we haven't yet received information to pair the SSRC with the UserId.
                            if (!audio.equals(silenceBytes))
                                LOG.debug("Received audio data with an unknown SSRC id. Ignoring");
                            continue;
                        }
                        if (decoder == null) {
                            if (AudioNatives.ensureOpus()) {
                                opusDecoders.put(ssrc, decoder = new Decoder(ssrc));
                            } else if (!receiveHandler.canReceiveEncoded()) {
                                LOG.error("Unable to decode audio due to missing opus binaries!");
                                break;
                            }
                        }
                        OpusPacket opusPacket = new OpusPacket(decryptedPacket, userId, decoder);
                        if (receiveHandler.canReceiveEncoded())
                            receiveHandler.handleEncodedAudio(opusPacket);
                        if (!shouldDecode || !opusPacket.canDecode())
                            continue;
                        User user = getJDA().getUserById(userId);
                        if (user == null) {
                            LOG.warn("Received audio data with a known SSRC, but the userId associate with the SSRC is unknown to JDA!");
                            continue;
                        }
                        short[] decodedAudio = opusPacket.decode();
                        // If decodedAudio is null, then the Opus decode failed, so throw away the packet.
                        if (decodedAudio == null) {
                            // decoder error logged in method
                            continue;
                        }
                        if (receiveHandler.canReceiveUser()) {
                            receiveHandler.handleUserAudio(new UserAudio(user, decodedAudio));
                        }
                        if (receiveHandler.canReceiveCombined() && receiveHandler.includeUserInCombinedAudio(user)) {
                            Queue<AudioData> queue = combinedQueue.get(user);
                            if (queue == null) {
                                queue = new ConcurrentLinkedQueue<>();
                                combinedQueue.put(user, queue);
                            }
                            queue.add(new AudioData(decodedAudio));
                        }
                    } else if (couldReceive) {
                        couldReceive = false;
                        sendSilentPackets();
                    }
                } catch (SocketTimeoutException e) {
                // Ignore. We set a low timeout so that we wont block forever so we can properly shutdown the loop.
                } catch (SocketException e) {
                // The socket was closed while we were listening for the next packet.
                // This is expected. Ignore the exception. The thread will exit during the next while
                // iteration because the udpSocket.isClosed() will return true.
                } catch (Exception e) {
                    LOG.error("There was some random exception while waiting for udp packets", e);
                }
            }
        });
        receiveThread.setUncaughtExceptionHandler((thread, throwable) -> {
            LOG.error("There was some uncaught exception in the audio receive thread", throwable);
            JDAImpl api = getJDA();
            api.handleEvent(new ExceptionEvent(api, throwable, true));
        });
        receiveThread.setDaemon(true);
        receiveThread.setName(threadIdentifier + " Receiving Thread");
        receiveThread.start();
    }
    if (receiveHandler.canReceiveCombined()) {
        setupCombinedExecutor();
    }
}
Also used : ExceptionEvent(net.dv8tion.jda.api.events.ExceptionEvent) User(net.dv8tion.jda.api.entities.User) JDAImpl(net.dv8tion.jda.internal.JDAImpl) ByteBuffer(java.nio.ByteBuffer)

Example 4 with ExceptionEvent

use of net.dv8tion.jda.api.events.ExceptionEvent in project JDA by DV8FromTheWorld.

the class AudioConnection method prepareReady.

/* Used by AudioWebSocket */
protected void prepareReady() {
    Thread readyThread = new Thread(() -> {
        getJDA().setContext();
        final long timeout = getGuild().getAudioManager().getConnectTimeout();
        final long started = System.currentTimeMillis();
        while (!webSocket.isReady()) {
            if (timeout > 0 && System.currentTimeMillis() - started > timeout)
                break;
            try {
                Thread.sleep(10);
            } catch (InterruptedException e) {
                LOG.error("AudioConnection ready thread got interrupted while sleeping", e);
                Thread.currentThread().interrupt();
            }
        }
        if (webSocket.isReady()) {
            setupSendSystem();
            setupReceiveSystem();
        } else {
            webSocket.close(ConnectionStatus.ERROR_CONNECTION_TIMEOUT);
        }
    });
    readyThread.setUncaughtExceptionHandler((thread, throwable) -> {
        LOG.error("Uncaught exception in Audio ready-thread", throwable);
        JDAImpl api = getJDA();
        api.handleEvent(new ExceptionEvent(api, throwable, true));
    });
    readyThread.setDaemon(true);
    readyThread.setName(threadIdentifier + " Ready Thread");
    readyThread.start();
}
Also used : ExceptionEvent(net.dv8tion.jda.api.events.ExceptionEvent) JDAImpl(net.dv8tion.jda.internal.JDAImpl)

Example 5 with ExceptionEvent

use of net.dv8tion.jda.api.events.ExceptionEvent in project JDA by DV8FromTheWorld.

the class AudioConnection method setupCombinedExecutor.

private synchronized void setupCombinedExecutor() {
    if (combinedAudioExecutor == null) {
        combinedAudioExecutor = Executors.newSingleThreadScheduledExecutor((task) -> {
            final Thread t = new Thread(task, threadIdentifier + " Combined Thread");
            t.setDaemon(true);
            t.setUncaughtExceptionHandler((thread, throwable) -> {
                LOG.error("I have no idea how, but there was an uncaught exception in the combinedAudioExecutor", throwable);
                JDAImpl api = getJDA();
                api.handleEvent(new ExceptionEvent(api, throwable, true));
            });
            return t;
        });
        combinedAudioExecutor.scheduleAtFixedRate(() -> {
            getJDA().setContext();
            try {
                List<User> users = new LinkedList<>();
                List<short[]> audioParts = new LinkedList<>();
                if (receiveHandler != null && receiveHandler.canReceiveCombined()) {
                    long currentTime = System.currentTimeMillis();
                    for (Map.Entry<User, Queue<AudioData>> entry : combinedQueue.entrySet()) {
                        User user = entry.getKey();
                        Queue<AudioData> queue = entry.getValue();
                        if (queue.isEmpty())
                            continue;
                        AudioData audioData = queue.poll();
                        // Make sure the audio packet is younger than 100ms
                        while (audioData != null && currentTime - audioData.time > queueTimeout) {
                            audioData = queue.poll();
                        }
                        // If none of the audio packets were younger than 100ms, then there is nothing to add.
                        if (audioData == null) {
                            continue;
                        }
                        users.add(user);
                        audioParts.add(audioData.data);
                    }
                    if (!audioParts.isEmpty()) {
                        int audioLength = audioParts.stream().mapToInt(it -> it.length).max().getAsInt();
                        // 960 PCM samples for each channel
                        short[] mix = new short[1920];
                        int sample;
                        for (int i = 0; i < audioLength; i++) {
                            sample = 0;
                            for (Iterator<short[]> iterator = audioParts.iterator(); iterator.hasNext(); ) {
                                short[] audio = iterator.next();
                                if (i < audio.length)
                                    sample += audio[i];
                                else
                                    iterator.remove();
                            }
                            if (sample > Short.MAX_VALUE)
                                mix[i] = Short.MAX_VALUE;
                            else if (sample < Short.MIN_VALUE)
                                mix[i] = Short.MIN_VALUE;
                            else
                                mix[i] = (short) sample;
                        }
                        receiveHandler.handleCombinedAudio(new CombinedAudio(users, mix));
                    } else {
                        // No audio to mix, provide 20 MS of silence. (960 PCM samples for each channel)
                        receiveHandler.handleCombinedAudio(new CombinedAudio(Collections.emptyList(), new short[1920]));
                    }
                }
            } catch (Exception e) {
                LOG.error("There was some unexpected exception in the combinedAudioExecutor!", e);
            }
        }, 0, 20, TimeUnit.MILLISECONDS);
    }
}
Also used : ConnectionStatus(net.dv8tion.jda.api.audio.hooks.ConnectionStatus) TIntObjectHashMap(gnu.trove.map.hash.TIntObjectHashMap) java.util(java.util) TIntObjectMap(gnu.trove.map.TIntObjectMap) IAudioSendSystem(net.dv8tion.jda.api.audio.factory.IAudioSendSystem) IOUtil(net.dv8tion.jda.internal.utils.IOUtil) ShortBuffer(java.nio.ShortBuffer) TIntLongMap(gnu.trove.map.TIntLongMap) ByteBuffer(java.nio.ByteBuffer) User(net.dv8tion.jda.api.entities.User) Opus(tomp2p.opuswrapper.Opus) Guild(net.dv8tion.jda.api.entities.Guild) java.net(java.net) IntBuffer(java.nio.IntBuffer) AtomicInteger(java.util.concurrent.atomic.AtomicInteger) JDAImpl(net.dv8tion.jda.internal.JDAImpl) Buffer(java.nio.Buffer) DataObject(net.dv8tion.jda.api.utils.data.DataObject) Nonnull(javax.annotation.Nonnull) IAudioSendFactory(net.dv8tion.jda.api.audio.factory.IAudioSendFactory) IPacketProvider(net.dv8tion.jda.api.audio.factory.IPacketProvider) AudioChannel(net.dv8tion.jda.api.entities.AudioChannel) Logger(org.slf4j.Logger) java.util.concurrent(java.util.concurrent) net.dv8tion.jda.api.audio(net.dv8tion.jda.api.audio) ExceptionEvent(net.dv8tion.jda.api.events.ExceptionEvent) PointerByReference(com.sun.jna.ptr.PointerByReference) AudioManagerImpl(net.dv8tion.jda.internal.managers.AudioManagerImpl) WebSocket(com.neovisionaries.ws.client.WebSocket) TweetNaclFast(com.iwebpp.crypto.TweetNaclFast) TIntLongHashMap(gnu.trove.map.hash.TIntLongHashMap) JDALogger(net.dv8tion.jda.internal.utils.JDALogger) ExceptionEvent(net.dv8tion.jda.api.events.ExceptionEvent) User(net.dv8tion.jda.api.entities.User) JDAImpl(net.dv8tion.jda.internal.JDAImpl) TIntObjectHashMap(gnu.trove.map.hash.TIntObjectHashMap) TIntObjectMap(gnu.trove.map.TIntObjectMap) TIntLongMap(gnu.trove.map.TIntLongMap) TIntLongHashMap(gnu.trove.map.hash.TIntLongHashMap)

Aggregations

ExceptionEvent (net.dv8tion.jda.api.events.ExceptionEvent)6 JDAImpl (net.dv8tion.jda.internal.JDAImpl)4 ByteBuffer (java.nio.ByteBuffer)2 ThreadLocalReason (net.dv8tion.jda.api.audit.ThreadLocalReason)2 User (net.dv8tion.jda.api.entities.User)2 CallbackContext (net.dv8tion.jda.internal.requests.CallbackContext)2 TweetNaclFast (com.iwebpp.crypto.TweetNaclFast)1 WebSocket (com.neovisionaries.ws.client.WebSocket)1 PointerByReference (com.sun.jna.ptr.PointerByReference)1 TIntLongMap (gnu.trove.map.TIntLongMap)1 TIntObjectMap (gnu.trove.map.TIntObjectMap)1 TIntLongHashMap (gnu.trove.map.hash.TIntLongHashMap)1 TIntObjectHashMap (gnu.trove.map.hash.TIntObjectHashMap)1 java.net (java.net)1 Buffer (java.nio.Buffer)1 IntBuffer (java.nio.IntBuffer)1 ShortBuffer (java.nio.ShortBuffer)1 java.util (java.util)1 java.util.concurrent (java.util.concurrent)1 AtomicInteger (java.util.concurrent.atomic.AtomicInteger)1