Merge remote-tracking branch 'origin/master'

# Conflicts:
#	src/main/java/com/github/manevolent/ts3j/protocol/socket/client/LocalTeamspeakClientSocket.java
This commit is contained in:
Manevolent
2018-10-22 13:42:29 -04:00
6 changed files with 113 additions and 23 deletions
@@ -2,6 +2,8 @@ package com.github.manevolent.ts3j.protocol.packet;
import com.github.manevolent.ts3j.enums.CodecType;
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 java.nio.ByteBuffer;
@@ -12,6 +14,13 @@ public class PacketBody0Voice extends PacketBody {
private CodecType codecType;
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) {
super(PacketBodyType.VOICE, role);
}
@@ -44,6 +53,12 @@ public class PacketBody0Voice extends PacketBody {
return clientId;
}
public Byte getServerFlag0() { return serverFlag0; }
public void setServerFlag0(Byte flag) {
this.serverFlag0 = flag;
}
public void setClientId(int clientId) {
if (getRole() != ProtocolRole.SERVER)
throw new IllegalStateException("cannot set client ID field on non-server packet");
@@ -51,6 +66,32 @@ public class PacketBody0Voice extends PacketBody {
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
public void read(ByteBuffer buffer) {
packetId = buffer.getShort() & 0x0000FFFF;
@@ -59,10 +100,6 @@ public class PacketBody0Voice extends PacketBody {
clientId = buffer.getShort() & 0x0000FFFF;
codecType = CodecType.fromId(buffer.get() & 0xFF);
codecData = new byte[buffer.remaining()];
buffer.get(codecData);
}
@Override
@@ -75,10 +112,17 @@ public class PacketBody0Voice extends PacketBody {
buffer.put((byte)(codecType.getIndex() & 0xFF));
buffer.put(codecData);
if (serverFlag0 != null)
buffer.put(serverFlag0);
}
@Override
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);
}
}
@@ -16,20 +16,42 @@ public class PacketBody1VoiceWhisper extends PacketBody {
private WhisperTarget target;
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) {
super(PacketBodyType.VOICE_WHISPER, role);
}
public Byte getServerFlag0() { return serverFlag0; }
public void setServerFlag0(Byte flag) {
this.serverFlag0 = flag;
}
@Override
public void setHeaderValues(PacketHeader header) {
if (target instanceof WhisperTargetGroup)
header.setPacketFlag(HeaderFlag.NEW_PROTOCOL, true);
else
header.setPacketFlag(HeaderFlag.NEW_PROTOCOL, false);
if (serverFlag0 != null) // Ensure padding is signaled
header.setPacketFlag(HeaderFlag.COMPRESSED, true);
}
@Override
public void read(PacketHeader header, ByteBuffer buffer) {
int padding = 0;
boolean compressed = header.getPacketFlag(HeaderFlag.COMPRESSED);
if (compressed)
padding ++;
packetId = buffer.getShort() & 0xFFFF;
if (getRole() == ProtocolRole.SERVER)
@@ -37,7 +59,6 @@ public class PacketBody1VoiceWhisper extends PacketBody {
codecType = CodecType.fromId((int) (buffer.get() & 0xFF));
if (getRole() == ProtocolRole.CLIENT) {
if (header.getPacketFlag(HeaderFlag.NEW_PROTOCOL)) {
setTarget(new WhisperTargetGroup());
@@ -50,14 +71,20 @@ public class PacketBody1VoiceWhisper extends PacketBody {
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.
@Override
public void read(ByteBuffer buffer) {
codecData = new byte[buffer.remaining()];
buffer.get(codecData);
throw new UnsupportedOperationException();
}
@Override
@@ -73,15 +100,18 @@ public class PacketBody1VoiceWhisper extends PacketBody {
target.write(buffer);
buffer.put(codecData);
if (serverFlag0 != null)
buffer.put(serverFlag0);
}
@Override
public int getSize() {
switch (getRole()) {
case CLIENT:
return 2 + 1 + target.getSize() + codecData.length;
return 2 + 1 + target.getSize() + codecData.length + (serverFlag0 != null ? 1 : 0);
case SERVER:
return 2 + 2 + 1 + codecData.length;
return 2 + 2 + 1 + codecData.length + (serverFlag0 != null ? 1 : 0);
default:
throw new IllegalArgumentException("unknown role");
}
@@ -54,6 +54,7 @@ public abstract class LocalClientHandlerFull extends LocalClientHandler {
}
break;
case VOICE:
Consumer<PacketBody0Voice> handler = getClient().getVoiceHandler();
if (handler != null) handler.accept((PacketBody0Voice)packet.getBody());
@@ -515,6 +515,8 @@ public class LocalTeamspeakClientSocket
private class MicrophoneTask implements Runnable {
private boolean wasSendingAudio = false;
private byte sessionId = 1;
private int flaggedPackets = 5;
@Override
public void run() {
@@ -531,14 +533,19 @@ public class LocalTeamspeakClientSocket
// TODO
// Set a state and send a muted event
} else if (microphone.isReady()) {
byte[] data = microphone.provide();
if (data.length <= 0) return;
PacketBody0Voice voice = new PacketBody0Voice(getRole().getOut());
voice.setCodecType(microphone.getCodec());
voice.setCodecData(microphone.provide());
voice.setCodecData(data);
if (flaggedPackets > 0) voice.setServerFlag0(sessionId);
try {
writePacket(voice);
flaggedPackets --;
wasSendingAudio = true;
} catch (Exception e) {
// All we are really concerned about here is a disconnection event, in which case the loop
@@ -554,6 +561,13 @@ public class LocalTeamspeakClientSocket
try {
writePacket(voice);
// reset decoder flag
flaggedPackets = 5;
sessionId ++;
if (sessionId >= 8)
sessionId = 1;
wasSendingAudio = false;
} catch (Exception e) {
// 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()) {
case RETRIEVING_DATA:
case CONNECTED:
Command banCommand = new SingleCommand("clientupdate", ProtocolRole.CLIENT);
banCommand.add(new CommandSingleParameter("client_nickname", nickname));
Command command = new SingleCommand("clientupdate", ProtocolRole.CLIENT);
command.add(new CommandSingleParameter("client_nickname", nickname));
try {
executeCommand(banCommand).complete();
executeCommand(command).complete();
} catch (Exception 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.ScalarOperations;
import Punisher.NaCl.Internal.Sha512;
import com.github.manevolent.ts3j.api.Message;
import com.github.manevolent.ts3j.identity.*;
import com.github.manevolent.ts3j.license.License;
import com.github.manevolent.ts3j.util.Pair;
import org.bouncycastle.asn1.*;
import org.bouncycastle.crypto.digests.SHA256Digest;
import org.bouncycastle.crypto.params.ECDomainParameters;
@@ -25,7 +23,6 @@ import java.io.IOException;
import java.math.BigInteger;
import java.nio.ByteBuffer;
import java.security.*;
import java.util.Base64;
import java.util.List;
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.event.*;
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.packet.PacketBody0Voice;
import com.github.manevolent.ts3j.protocol.socket.client.LocalTeamspeakClientSocket;
@@ -22,14 +23,18 @@ public class ServerConnectionTest {
LocalTeamspeakClientSocket client = new LocalTeamspeakClientSocket();
Ts3Debugging.setEnabled(true);
Ts3Debugging.setEnabled(false);
LocalIdentity identity = LocalIdentity.generateNew(9);
LocalIdentity identity = LocalIdentity.generateNew(10);
client.setIdentity(identity);
client.setNickname("ts3j issue 2");
client.setHWID("TestTestTest");
client.setVoiceHandler(packet ->
System.out.println(packet.getServerFlag0())
);
while (true) {
try {
client.connect(