Merge remote-tracking branch 'origin/master'
# Conflicts: # src/main/java/com/github/manevolent/ts3j/protocol/socket/client/LocalTeamspeakClientSocket.java
This commit is contained in:
@@ -2,6 +2,8 @@ package com.github.manevolent.ts3j.protocol.packet;
|
|||||||
|
|
||||||
import com.github.manevolent.ts3j.enums.CodecType;
|
import com.github.manevolent.ts3j.enums.CodecType;
|
||||||
import com.github.manevolent.ts3j.protocol.ProtocolRole;
|
import com.github.manevolent.ts3j.protocol.ProtocolRole;
|
||||||
|
import com.github.manevolent.ts3j.protocol.header.HeaderFlag;
|
||||||
|
import com.github.manevolent.ts3j.protocol.header.PacketHeader;
|
||||||
import com.github.manevolent.ts3j.util.Ts3Debugging;
|
import com.github.manevolent.ts3j.util.Ts3Debugging;
|
||||||
|
|
||||||
import java.nio.ByteBuffer;
|
import java.nio.ByteBuffer;
|
||||||
@@ -12,6 +14,13 @@ public class PacketBody0Voice extends PacketBody {
|
|||||||
private CodecType codecType;
|
private CodecType codecType;
|
||||||
private byte[] codecData;
|
private byte[] codecData;
|
||||||
|
|
||||||
|
// Unknown at this time (have seen: 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07)
|
||||||
|
// Set for the first 5 packets of a new voice session
|
||||||
|
// I believe this is related to tracking opening a new decoder
|
||||||
|
// Not all new voice sessions will change this flag
|
||||||
|
// Best to ignore it for now, but it's here if you need it or figure it out
|
||||||
|
private Byte serverFlag0;
|
||||||
|
|
||||||
public PacketBody0Voice(ProtocolRole role) {
|
public PacketBody0Voice(ProtocolRole role) {
|
||||||
super(PacketBodyType.VOICE, role);
|
super(PacketBodyType.VOICE, role);
|
||||||
}
|
}
|
||||||
@@ -44,6 +53,12 @@ public class PacketBody0Voice extends PacketBody {
|
|||||||
return clientId;
|
return clientId;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Byte getServerFlag0() { return serverFlag0; }
|
||||||
|
|
||||||
|
public void setServerFlag0(Byte flag) {
|
||||||
|
this.serverFlag0 = flag;
|
||||||
|
}
|
||||||
|
|
||||||
public void setClientId(int clientId) {
|
public void setClientId(int clientId) {
|
||||||
if (getRole() != ProtocolRole.SERVER)
|
if (getRole() != ProtocolRole.SERVER)
|
||||||
throw new IllegalStateException("cannot set client ID field on non-server packet");
|
throw new IllegalStateException("cannot set client ID field on non-server packet");
|
||||||
@@ -51,6 +66,32 @@ public class PacketBody0Voice extends PacketBody {
|
|||||||
this.clientId = clientId;
|
this.clientId = clientId;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setHeaderValues(PacketHeader header) {
|
||||||
|
if (serverFlag0 != null) // Ensure padding is signaled
|
||||||
|
header.setPacketFlag(HeaderFlag.COMPRESSED, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void read(PacketHeader header, ByteBuffer buffer) {
|
||||||
|
super.read(header, buffer);
|
||||||
|
|
||||||
|
int padding = 0;
|
||||||
|
boolean compressed = header.getPacketFlag(HeaderFlag.COMPRESSED);
|
||||||
|
|
||||||
|
if (compressed)
|
||||||
|
padding ++;
|
||||||
|
|
||||||
|
codecData = new byte[buffer.remaining() - padding];
|
||||||
|
buffer.get(codecData);
|
||||||
|
|
||||||
|
// Handle trailing data
|
||||||
|
if (padding > 0) {
|
||||||
|
if (compressed)
|
||||||
|
serverFlag0 = buffer.get();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void read(ByteBuffer buffer) {
|
public void read(ByteBuffer buffer) {
|
||||||
packetId = buffer.getShort() & 0x0000FFFF;
|
packetId = buffer.getShort() & 0x0000FFFF;
|
||||||
@@ -59,10 +100,6 @@ public class PacketBody0Voice extends PacketBody {
|
|||||||
clientId = buffer.getShort() & 0x0000FFFF;
|
clientId = buffer.getShort() & 0x0000FFFF;
|
||||||
|
|
||||||
codecType = CodecType.fromId(buffer.get() & 0xFF);
|
codecType = CodecType.fromId(buffer.get() & 0xFF);
|
||||||
|
|
||||||
codecData = new byte[buffer.remaining()];
|
|
||||||
|
|
||||||
buffer.get(codecData);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -75,10 +112,17 @@ public class PacketBody0Voice extends PacketBody {
|
|||||||
buffer.put((byte)(codecType.getIndex() & 0xFF));
|
buffer.put((byte)(codecType.getIndex() & 0xFF));
|
||||||
|
|
||||||
buffer.put(codecData);
|
buffer.put(codecData);
|
||||||
|
|
||||||
|
if (serverFlag0 != null)
|
||||||
|
buffer.put(serverFlag0);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int getSize() {
|
public int getSize() {
|
||||||
return 2 + (getRole() == ProtocolRole.SERVER ? 2 : 0) + 1 + codecData.length;
|
return 2 +
|
||||||
|
(getRole() == ProtocolRole.SERVER ? 2 : 0) +
|
||||||
|
1 +
|
||||||
|
codecData.length +
|
||||||
|
(serverFlag0 != null ? 1 : 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+36
-6
@@ -16,20 +16,42 @@ public class PacketBody1VoiceWhisper extends PacketBody {
|
|||||||
private WhisperTarget target;
|
private WhisperTarget target;
|
||||||
private byte[] codecData;
|
private byte[] codecData;
|
||||||
|
|
||||||
|
// Unknown at this time (have seen: 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07)
|
||||||
|
// Set for the first 5 packets of a new voice session
|
||||||
|
// I believe this is related to tracking opening a new decoder
|
||||||
|
// Not all new voice sessions will change this flag
|
||||||
|
// Best to ignore it for now, but it's here if you need it or figure it out
|
||||||
|
private Byte serverFlag0;
|
||||||
|
|
||||||
public PacketBody1VoiceWhisper(ProtocolRole role) {
|
public PacketBody1VoiceWhisper(ProtocolRole role) {
|
||||||
super(PacketBodyType.VOICE_WHISPER, role);
|
super(PacketBodyType.VOICE_WHISPER, role);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Byte getServerFlag0() { return serverFlag0; }
|
||||||
|
|
||||||
|
public void setServerFlag0(Byte flag) {
|
||||||
|
this.serverFlag0 = flag;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setHeaderValues(PacketHeader header) {
|
public void setHeaderValues(PacketHeader header) {
|
||||||
if (target instanceof WhisperTargetGroup)
|
if (target instanceof WhisperTargetGroup)
|
||||||
header.setPacketFlag(HeaderFlag.NEW_PROTOCOL, true);
|
header.setPacketFlag(HeaderFlag.NEW_PROTOCOL, true);
|
||||||
else
|
else
|
||||||
header.setPacketFlag(HeaderFlag.NEW_PROTOCOL, false);
|
header.setPacketFlag(HeaderFlag.NEW_PROTOCOL, false);
|
||||||
|
|
||||||
|
if (serverFlag0 != null) // Ensure padding is signaled
|
||||||
|
header.setPacketFlag(HeaderFlag.COMPRESSED, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void read(PacketHeader header, ByteBuffer buffer) {
|
public void read(PacketHeader header, ByteBuffer buffer) {
|
||||||
|
int padding = 0;
|
||||||
|
boolean compressed = header.getPacketFlag(HeaderFlag.COMPRESSED);
|
||||||
|
|
||||||
|
if (compressed)
|
||||||
|
padding ++;
|
||||||
|
|
||||||
packetId = buffer.getShort() & 0xFFFF;
|
packetId = buffer.getShort() & 0xFFFF;
|
||||||
|
|
||||||
if (getRole() == ProtocolRole.SERVER)
|
if (getRole() == ProtocolRole.SERVER)
|
||||||
@@ -37,7 +59,6 @@ public class PacketBody1VoiceWhisper extends PacketBody {
|
|||||||
|
|
||||||
codecType = CodecType.fromId((int) (buffer.get() & 0xFF));
|
codecType = CodecType.fromId((int) (buffer.get() & 0xFF));
|
||||||
|
|
||||||
|
|
||||||
if (getRole() == ProtocolRole.CLIENT) {
|
if (getRole() == ProtocolRole.CLIENT) {
|
||||||
if (header.getPacketFlag(HeaderFlag.NEW_PROTOCOL)) {
|
if (header.getPacketFlag(HeaderFlag.NEW_PROTOCOL)) {
|
||||||
setTarget(new WhisperTargetGroup());
|
setTarget(new WhisperTargetGroup());
|
||||||
@@ -50,14 +71,20 @@ public class PacketBody1VoiceWhisper extends PacketBody {
|
|||||||
|
|
||||||
target.read(buffer);
|
target.read(buffer);
|
||||||
|
|
||||||
read(buffer);
|
codecData = new byte[buffer.remaining() - padding];
|
||||||
|
buffer.get(codecData);
|
||||||
|
|
||||||
|
// Handle trailing data
|
||||||
|
if (padding > 0) {
|
||||||
|
if (compressed)
|
||||||
|
serverFlag0 = buffer.get();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// We implemented the above so this is unneccessary.
|
// We implemented the above so this is unneccessary.
|
||||||
@Override
|
@Override
|
||||||
public void read(ByteBuffer buffer) {
|
public void read(ByteBuffer buffer) {
|
||||||
codecData = new byte[buffer.remaining()];
|
throw new UnsupportedOperationException();
|
||||||
buffer.get(codecData);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -73,15 +100,18 @@ public class PacketBody1VoiceWhisper extends PacketBody {
|
|||||||
target.write(buffer);
|
target.write(buffer);
|
||||||
|
|
||||||
buffer.put(codecData);
|
buffer.put(codecData);
|
||||||
|
|
||||||
|
if (serverFlag0 != null)
|
||||||
|
buffer.put(serverFlag0);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int getSize() {
|
public int getSize() {
|
||||||
switch (getRole()) {
|
switch (getRole()) {
|
||||||
case CLIENT:
|
case CLIENT:
|
||||||
return 2 + 1 + target.getSize() + codecData.length;
|
return 2 + 1 + target.getSize() + codecData.length + (serverFlag0 != null ? 1 : 0);
|
||||||
case SERVER:
|
case SERVER:
|
||||||
return 2 + 2 + 1 + codecData.length;
|
return 2 + 2 + 1 + codecData.length + (serverFlag0 != null ? 1 : 0);
|
||||||
default:
|
default:
|
||||||
throw new IllegalArgumentException("unknown role");
|
throw new IllegalArgumentException("unknown role");
|
||||||
}
|
}
|
||||||
|
|||||||
+3
-2
@@ -54,13 +54,14 @@ public abstract class LocalClientHandlerFull extends LocalClientHandler {
|
|||||||
}
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case VOICE:
|
case VOICE:
|
||||||
Consumer<PacketBody0Voice> handler = getClient().getVoiceHandler();
|
Consumer<PacketBody0Voice> handler = getClient().getVoiceHandler();
|
||||||
if (handler != null) handler.accept((PacketBody0Voice) packet.getBody());
|
if (handler != null) handler.accept((PacketBody0Voice)packet.getBody());
|
||||||
break;
|
break;
|
||||||
case VOICE_WHISPER:
|
case VOICE_WHISPER:
|
||||||
Consumer<PacketBody1VoiceWhisper> whisperConsumer = getClient().getWhisperHandler();
|
Consumer<PacketBody1VoiceWhisper> whisperConsumer = getClient().getWhisperHandler();
|
||||||
if (whisperConsumer != null) whisperConsumer.accept((PacketBody1VoiceWhisper) packet.getBody());
|
if (whisperConsumer != null) whisperConsumer.accept((PacketBody1VoiceWhisper)packet.getBody());
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+18
-5
@@ -515,6 +515,8 @@ public class LocalTeamspeakClientSocket
|
|||||||
|
|
||||||
private class MicrophoneTask implements Runnable {
|
private class MicrophoneTask implements Runnable {
|
||||||
private boolean wasSendingAudio = false;
|
private boolean wasSendingAudio = false;
|
||||||
|
private byte sessionId = 1;
|
||||||
|
private int flaggedPackets = 5;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
@@ -531,14 +533,19 @@ public class LocalTeamspeakClientSocket
|
|||||||
// TODO
|
// TODO
|
||||||
// Set a state and send a muted event
|
// Set a state and send a muted event
|
||||||
} else if (microphone.isReady()) {
|
} else if (microphone.isReady()) {
|
||||||
|
byte[] data = microphone.provide();
|
||||||
|
if (data.length <= 0) return;
|
||||||
|
|
||||||
PacketBody0Voice voice = new PacketBody0Voice(getRole().getOut());
|
PacketBody0Voice voice = new PacketBody0Voice(getRole().getOut());
|
||||||
|
|
||||||
voice.setCodecType(microphone.getCodec());
|
voice.setCodecType(microphone.getCodec());
|
||||||
voice.setCodecData(microphone.provide());
|
voice.setCodecData(data);
|
||||||
|
if (flaggedPackets > 0) voice.setServerFlag0(sessionId);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
writePacket(voice);
|
writePacket(voice);
|
||||||
|
|
||||||
|
flaggedPackets --;
|
||||||
wasSendingAudio = true;
|
wasSendingAudio = true;
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
// All we are really concerned about here is a disconnection event, in which case the loop
|
// All we are really concerned about here is a disconnection event, in which case the loop
|
||||||
@@ -554,6 +561,13 @@ public class LocalTeamspeakClientSocket
|
|||||||
try {
|
try {
|
||||||
writePacket(voice);
|
writePacket(voice);
|
||||||
|
|
||||||
|
// reset decoder flag
|
||||||
|
flaggedPackets = 5;
|
||||||
|
sessionId ++;
|
||||||
|
|
||||||
|
if (sessionId >= 8)
|
||||||
|
sessionId = 1;
|
||||||
|
|
||||||
wasSendingAudio = false;
|
wasSendingAudio = false;
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
// All we are really concerned about here is a disconnection event, in which case the loop
|
// All we are really concerned about here is a disconnection event, in which case the loop
|
||||||
@@ -697,12 +711,11 @@ public class LocalTeamspeakClientSocket
|
|||||||
switch (getState()) {
|
switch (getState()) {
|
||||||
case RETRIEVING_DATA:
|
case RETRIEVING_DATA:
|
||||||
case CONNECTED:
|
case CONNECTED:
|
||||||
Command banCommand = new SingleCommand("clientupdate", ProtocolRole.CLIENT);
|
Command command = new SingleCommand("clientupdate", ProtocolRole.CLIENT);
|
||||||
|
command.add(new CommandSingleParameter("client_nickname", nickname));
|
||||||
banCommand.add(new CommandSingleParameter("client_nickname", nickname));
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
executeCommand(banCommand).complete();
|
executeCommand(command).complete();
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
throw new RuntimeException(e);
|
throw new RuntimeException(e);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,10 +5,8 @@ import Punisher.NaCl.Internal.Ed25519Ref10.GroupElementP3;
|
|||||||
import Punisher.NaCl.Internal.Ed25519Ref10.GroupOperations;
|
import Punisher.NaCl.Internal.Ed25519Ref10.GroupOperations;
|
||||||
import Punisher.NaCl.Internal.Ed25519Ref10.ScalarOperations;
|
import Punisher.NaCl.Internal.Ed25519Ref10.ScalarOperations;
|
||||||
import Punisher.NaCl.Internal.Sha512;
|
import Punisher.NaCl.Internal.Sha512;
|
||||||
import com.github.manevolent.ts3j.api.Message;
|
|
||||||
import com.github.manevolent.ts3j.identity.*;
|
import com.github.manevolent.ts3j.identity.*;
|
||||||
import com.github.manevolent.ts3j.license.License;
|
import com.github.manevolent.ts3j.license.License;
|
||||||
import com.github.manevolent.ts3j.util.Pair;
|
|
||||||
import org.bouncycastle.asn1.*;
|
import org.bouncycastle.asn1.*;
|
||||||
import org.bouncycastle.crypto.digests.SHA256Digest;
|
import org.bouncycastle.crypto.digests.SHA256Digest;
|
||||||
import org.bouncycastle.crypto.params.ECDomainParameters;
|
import org.bouncycastle.crypto.params.ECDomainParameters;
|
||||||
@@ -25,7 +23,6 @@ import java.io.IOException;
|
|||||||
import java.math.BigInteger;
|
import java.math.BigInteger;
|
||||||
import java.nio.ByteBuffer;
|
import java.nio.ByteBuffer;
|
||||||
import java.security.*;
|
import java.security.*;
|
||||||
import java.util.Base64;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
public final class Ts3Crypt {
|
public final class Ts3Crypt {
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import com.github.manevolent.ts3j.audio.Microphone;
|
|||||||
import com.github.manevolent.ts3j.enums.CodecType;
|
import com.github.manevolent.ts3j.enums.CodecType;
|
||||||
import com.github.manevolent.ts3j.event.*;
|
import com.github.manevolent.ts3j.event.*;
|
||||||
import com.github.manevolent.ts3j.identity.LocalIdentity;
|
import com.github.manevolent.ts3j.identity.LocalIdentity;
|
||||||
|
import com.github.manevolent.ts3j.protocol.Packet;
|
||||||
import com.github.manevolent.ts3j.protocol.client.ClientConnectionState;
|
import com.github.manevolent.ts3j.protocol.client.ClientConnectionState;
|
||||||
import com.github.manevolent.ts3j.protocol.packet.PacketBody0Voice;
|
import com.github.manevolent.ts3j.protocol.packet.PacketBody0Voice;
|
||||||
import com.github.manevolent.ts3j.protocol.socket.client.LocalTeamspeakClientSocket;
|
import com.github.manevolent.ts3j.protocol.socket.client.LocalTeamspeakClientSocket;
|
||||||
@@ -22,14 +23,18 @@ public class ServerConnectionTest {
|
|||||||
|
|
||||||
LocalTeamspeakClientSocket client = new LocalTeamspeakClientSocket();
|
LocalTeamspeakClientSocket client = new LocalTeamspeakClientSocket();
|
||||||
|
|
||||||
Ts3Debugging.setEnabled(true);
|
Ts3Debugging.setEnabled(false);
|
||||||
|
|
||||||
LocalIdentity identity = LocalIdentity.generateNew(9);
|
LocalIdentity identity = LocalIdentity.generateNew(10);
|
||||||
|
|
||||||
client.setIdentity(identity);
|
client.setIdentity(identity);
|
||||||
client.setNickname("ts3j issue 2");
|
client.setNickname("ts3j issue 2");
|
||||||
client.setHWID("TestTestTest");
|
client.setHWID("TestTestTest");
|
||||||
|
|
||||||
|
client.setVoiceHandler(packet ->
|
||||||
|
System.out.println(packet.getServerFlag0())
|
||||||
|
);
|
||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
try {
|
try {
|
||||||
client.connect(
|
client.connect(
|
||||||
|
|||||||
Reference in New Issue
Block a user