Whisper support
This commit is contained in:
+1
-1
@@ -31,7 +31,7 @@ out/
|
|||||||
.userlibraries
|
.userlibraries
|
||||||
|
|
||||||
# Maven
|
# Maven
|
||||||
target/
|
targetId/
|
||||||
pom.xml.tag
|
pom.xml.tag
|
||||||
pom.xml.releaseBackup
|
pom.xml.releaseBackup
|
||||||
pom.xml.versionsBackup
|
pom.xml.versionsBackup
|
||||||
|
|||||||
@@ -10,7 +10,7 @@
|
|||||||
|
|
||||||
<properties>
|
<properties>
|
||||||
<maven.compiler.source>1.8</maven.compiler.source>
|
<maven.compiler.source>1.8</maven.compiler.source>
|
||||||
<maven.compiler.target>1.8</maven.compiler.target>
|
<maven.compiler.targetId>1.8</maven.compiler.targetId>
|
||||||
</properties>
|
</properties>
|
||||||
|
|
||||||
<dependencies>
|
<dependencies>
|
||||||
|
|||||||
@@ -0,0 +1,30 @@
|
|||||||
|
package com.github.manevolent.ts3j.enums;
|
||||||
|
|
||||||
|
public enum GroupWhisperTarget {
|
||||||
|
ALL_CHANNELS(0),
|
||||||
|
CURRENT_CHANNEL(1),
|
||||||
|
PARENT_CHANNEL(2),
|
||||||
|
ALL_PARENT_CHANNEL(3),
|
||||||
|
CHANNEL_FAMILY(4),
|
||||||
|
COMPLETE_CHANNEL_FAMILY(5),
|
||||||
|
SUBCHANNELS(6)
|
||||||
|
|
||||||
|
;
|
||||||
|
|
||||||
|
private final int index;
|
||||||
|
|
||||||
|
GroupWhisperTarget(int index) {
|
||||||
|
this.index = index;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getIndex() {
|
||||||
|
return index;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static GroupWhisperTarget fromId(int index) {
|
||||||
|
for (GroupWhisperTarget value : values())
|
||||||
|
if (value.getIndex() == index) return value;
|
||||||
|
|
||||||
|
throw new IllegalArgumentException("invalid index: " + index);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,27 @@
|
|||||||
|
package com.github.manevolent.ts3j.enums;
|
||||||
|
|
||||||
|
public enum GroupWhisperType {
|
||||||
|
SERVER_GROUP(0),
|
||||||
|
CHANNEL_GROUP(1),
|
||||||
|
CHANNEL_COMMANDER(2),
|
||||||
|
ALL_CLIENTS(3)
|
||||||
|
|
||||||
|
;
|
||||||
|
|
||||||
|
private final int index;
|
||||||
|
|
||||||
|
GroupWhisperType(int index) {
|
||||||
|
this.index = index;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getIndex() {
|
||||||
|
return index;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static GroupWhisperType fromId(int index) {
|
||||||
|
for (GroupWhisperType value : values())
|
||||||
|
if (value.getIndex() == index) return value;
|
||||||
|
|
||||||
|
throw new IllegalArgumentException("invalid index: " + index);
|
||||||
|
}
|
||||||
|
}
|
||||||
+195
-24
@@ -1,63 +1,63 @@
|
|||||||
package com.github.manevolent.ts3j.protocol.packet;
|
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.enums.GroupWhisperTarget;
|
||||||
|
import com.github.manevolent.ts3j.enums.GroupWhisperType;
|
||||||
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.HeaderFlag;
|
||||||
import com.github.manevolent.ts3j.protocol.header.PacketHeader;
|
import com.github.manevolent.ts3j.protocol.header.PacketHeader;
|
||||||
|
|
||||||
import java.nio.ByteBuffer;
|
import java.nio.ByteBuffer;
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
public class PacketBody1VoiceWhisper extends PacketBody {
|
public class PacketBody1VoiceWhisper extends PacketBody {
|
||||||
private int packetId;
|
private int packetId;
|
||||||
private int clientId;
|
private int clientId;
|
||||||
private CodecType codecType;
|
private CodecType codecType;
|
||||||
|
private WhisperTarget target;
|
||||||
private byte[] codecData;
|
private byte[] codecData;
|
||||||
|
|
||||||
public PacketBody1VoiceWhisper(ProtocolRole role) {
|
public PacketBody1VoiceWhisper(ProtocolRole role) {
|
||||||
super(PacketBodyType.VOICE_WHISPER, role);
|
super(PacketBodyType.VOICE_WHISPER, role);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setHeaderValues(PacketHeader header) {
|
||||||
|
if (target instanceof WhisperTargetGroup)
|
||||||
|
header.setPacketFlag(HeaderFlag.NEW_PROTOCOL, true);
|
||||||
|
else
|
||||||
|
header.setPacketFlag(HeaderFlag.NEW_PROTOCOL, false);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void read(PacketHeader header, ByteBuffer buffer) {
|
public void read(PacketHeader header, ByteBuffer buffer) {
|
||||||
packetId = buffer.getShort() & 0x0000FFFF;
|
packetId = buffer.getShort() & 0xFFFF;
|
||||||
|
|
||||||
if (getRole() == ProtocolRole.SERVER)
|
if (getRole() == ProtocolRole.SERVER)
|
||||||
clientId = buffer.getShort() & 0x0000FFFF;
|
clientId = buffer.getShort() & 0xFFFF;
|
||||||
|
|
||||||
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)) {
|
||||||
int groupWhisperType = buffer.get() & 0xFF;
|
setTarget(new WhisperTargetGroup());
|
||||||
int groupWhisperTarget = buffer.get() & 0xFF;
|
|
||||||
long targetChannelIdorGroupId = buffer.getLong();
|
|
||||||
|
|
||||||
// TODO
|
|
||||||
} else {
|
} else {
|
||||||
int channelIdCount = buffer.get() & 0xFF;
|
setTarget(new WhisperTargetMultiple());
|
||||||
int clientIdCount = buffer.get() & 0xFF;
|
|
||||||
|
|
||||||
List<Long> channelIds = new ArrayList<>(channelIdCount);
|
|
||||||
for (int i = 0; i < channelIdCount; i ++) channelIds.add(buffer.getLong());
|
|
||||||
|
|
||||||
List<Integer> clientIds = new ArrayList<>(clientIdCount);
|
|
||||||
for (int i = 0; i < clientIdCount; i ++) clientIds.add(buffer.getShort() & 0xFFFF);
|
|
||||||
|
|
||||||
// TODO
|
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
setTarget(new WhisperTargetServerToClient());
|
||||||
}
|
}
|
||||||
|
|
||||||
codecData = new byte[buffer.remaining()];
|
target.read(buffer);
|
||||||
|
|
||||||
buffer.get(codecData);
|
read(buffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// We implemented the above so this is unneccessary.
|
||||||
@Override
|
@Override
|
||||||
public void read(ByteBuffer buffer) {
|
public void read(ByteBuffer buffer) {
|
||||||
throw new UnsupportedOperationException();
|
codecData = new byte[buffer.remaining()];
|
||||||
|
buffer.get(codecData);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -69,6 +69,9 @@ public class PacketBody1VoiceWhisper extends PacketBody {
|
|||||||
|
|
||||||
buffer.put((byte)(codecType.getIndex() & 0xFF));
|
buffer.put((byte)(codecType.getIndex() & 0xFF));
|
||||||
|
|
||||||
|
if (getRole() == ProtocolRole.CLIENT)
|
||||||
|
target.write(buffer);
|
||||||
|
|
||||||
buffer.put(codecData);
|
buffer.put(codecData);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -76,8 +79,7 @@ public class PacketBody1VoiceWhisper extends PacketBody {
|
|||||||
public int getSize() {
|
public int getSize() {
|
||||||
switch (getRole()) {
|
switch (getRole()) {
|
||||||
case CLIENT:
|
case CLIENT:
|
||||||
// TODO
|
return 2 + 1 + target.getSize() + codecData.length;
|
||||||
throw new UnsupportedOperationException();
|
|
||||||
case SERVER:
|
case SERVER:
|
||||||
return 2 + 2 + 1 + codecData.length;
|
return 2 + 2 + 1 + codecData.length;
|
||||||
default:
|
default:
|
||||||
@@ -119,4 +121,173 @@ public class PacketBody1VoiceWhisper extends PacketBody {
|
|||||||
|
|
||||||
this.clientId = clientId;
|
this.clientId = clientId;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public WhisperTarget getTarget() {
|
||||||
|
return target;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setTarget(WhisperTarget target) {
|
||||||
|
this.target = target;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static abstract class WhisperTarget {
|
||||||
|
public abstract void write(ByteBuffer buffer);
|
||||||
|
public abstract void read(ByteBuffer buffer);
|
||||||
|
|
||||||
|
public abstract int getSize();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class WhisperTargetServerToClient extends WhisperTarget {
|
||||||
|
@Override
|
||||||
|
public void write(ByteBuffer buffer) {
|
||||||
|
// Do nothing
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void read(ByteBuffer buffer) {
|
||||||
|
// Do nothing
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getSize() {
|
||||||
|
return 0; // Empty
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class WhisperTargetMultiple extends WhisperTarget {
|
||||||
|
private int[] channelIds;
|
||||||
|
private int[] clientIds;
|
||||||
|
|
||||||
|
public int[] getChannelIds() {
|
||||||
|
return channelIds;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setChannelIds(int[] channelIds) {
|
||||||
|
this.channelIds = channelIds;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int[] getClientIds() {
|
||||||
|
return clientIds;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setClientIds(int[] clientIds) {
|
||||||
|
this.clientIds = clientIds;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void write(ByteBuffer buffer) {
|
||||||
|
if (channelIds != null)
|
||||||
|
buffer.put((byte) (channelIds.length & 0xFF));
|
||||||
|
else
|
||||||
|
buffer.put((byte) 0x00);
|
||||||
|
|
||||||
|
if (clientIds != null)
|
||||||
|
buffer.put((byte) (clientIds.length & 0xFF));
|
||||||
|
else
|
||||||
|
buffer.put((byte) 0x00);
|
||||||
|
|
||||||
|
if (channelIds != null) {
|
||||||
|
for (int channelId : channelIds) {
|
||||||
|
buffer.putLong((long) channelId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (clientIds != null) {
|
||||||
|
for (int clientId : clientIds) {
|
||||||
|
buffer.putShort((short) (clientId & 0xFFFF));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void read(ByteBuffer buffer) {
|
||||||
|
int channelIdCount = buffer.get() & 0xFF;
|
||||||
|
int clientIdCount = buffer.get() & 0xFF;
|
||||||
|
|
||||||
|
channelIds = new int[channelIdCount];
|
||||||
|
for (int n = 0; n < channelIdCount; n ++)
|
||||||
|
channelIds[n] = (int) (buffer.getLong());
|
||||||
|
|
||||||
|
clientIds = new int[clientIdCount];
|
||||||
|
for (int n = 0; n < channelIdCount; n ++)
|
||||||
|
clientIds[n] = (buffer.getShort() & 0xFFFF);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getSize() {
|
||||||
|
return 2 + 2 +
|
||||||
|
(channelIds == null ? 0 : channelIds.length * 8) +
|
||||||
|
(clientIds == null ? 0 : clientIds.length * 2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class WhisperTargetGroup extends WhisperTarget {
|
||||||
|
private GroupWhisperType whisperType;
|
||||||
|
private GroupWhisperTarget whisperTarget;
|
||||||
|
private long targetId;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void write(ByteBuffer buffer) {
|
||||||
|
buffer.put((byte) (whisperType.getIndex() & 0xFF));
|
||||||
|
buffer.put((byte) (whisperTarget.getIndex() & 0xFF));
|
||||||
|
buffer.putLong(targetId);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void read(ByteBuffer buffer) {
|
||||||
|
whisperType = GroupWhisperType.fromId(buffer.get() & 0xFF);
|
||||||
|
whisperTarget = GroupWhisperTarget.fromId(buffer.get() & 0xFF);
|
||||||
|
targetId = buffer.getLong();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getSize() {
|
||||||
|
return 1 + 1 + 8;
|
||||||
|
}
|
||||||
|
|
||||||
|
public GroupWhisperType getWhisperType() {
|
||||||
|
return whisperType;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setWhisperType(GroupWhisperType whisperType) {
|
||||||
|
this.whisperType = whisperType;
|
||||||
|
}
|
||||||
|
|
||||||
|
public GroupWhisperTarget getWhisperTarget() {
|
||||||
|
return whisperTarget;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setWhisperTarget(GroupWhisperTarget whisperTarget) {
|
||||||
|
this.whisperTarget = whisperTarget;
|
||||||
|
}
|
||||||
|
|
||||||
|
public long getTargetId() {
|
||||||
|
return targetId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setTargetId(long targetId) {
|
||||||
|
this.targetId = targetId;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static WhisperTarget createChannel(int channelId) {
|
||||||
|
WhisperTargetMultiple multiple = new WhisperTargetMultiple();
|
||||||
|
multiple.setChannelIds(new int[] { channelId });
|
||||||
|
return multiple;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static WhisperTarget createClient(int clientId) {
|
||||||
|
WhisperTargetMultiple multiple = new WhisperTargetMultiple();
|
||||||
|
multiple.setClientIds(new int[] { clientId });
|
||||||
|
return multiple;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static WhisperTarget createServer() {
|
||||||
|
WhisperTargetGroup group = new WhisperTargetGroup();
|
||||||
|
|
||||||
|
group.setWhisperTarget(GroupWhisperTarget.ALL_CHANNELS);
|
||||||
|
group.setWhisperType(GroupWhisperType.ALL_CLIENTS);
|
||||||
|
|
||||||
|
return group;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+5
@@ -5,6 +5,7 @@ import com.github.manevolent.ts3j.command.CommandProcessor;
|
|||||||
import com.github.manevolent.ts3j.command.MultiCommand;
|
import com.github.manevolent.ts3j.command.MultiCommand;
|
||||||
import com.github.manevolent.ts3j.protocol.Packet;
|
import com.github.manevolent.ts3j.protocol.Packet;
|
||||||
import com.github.manevolent.ts3j.protocol.packet.PacketBody0Voice;
|
import com.github.manevolent.ts3j.protocol.packet.PacketBody0Voice;
|
||||||
|
import com.github.manevolent.ts3j.protocol.packet.PacketBody1VoiceWhisper;
|
||||||
import com.github.manevolent.ts3j.protocol.packet.PacketBody2Command;
|
import com.github.manevolent.ts3j.protocol.packet.PacketBody2Command;
|
||||||
import com.github.manevolent.ts3j.protocol.packet.PacketBody3CommandLow;
|
import com.github.manevolent.ts3j.protocol.packet.PacketBody3CommandLow;
|
||||||
import com.github.manevolent.ts3j.protocol.socket.client.LocalTeamspeakClientSocket;
|
import com.github.manevolent.ts3j.protocol.socket.client.LocalTeamspeakClientSocket;
|
||||||
@@ -57,6 +58,10 @@ public abstract class LocalClientHandlerFull extends LocalClientHandler {
|
|||||||
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:
|
||||||
|
Consumer<PacketBody1VoiceWhisper> whisperConsumer = getClient().getWhisperHandler();
|
||||||
|
if (whisperConsumer != null) whisperConsumer.accept((PacketBody1VoiceWhisper) packet.getBody());
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+10
@@ -70,6 +70,8 @@ public abstract class AbstractTeamspeakClientSocket
|
|||||||
private CommandProcessor commandProcessor;
|
private CommandProcessor commandProcessor;
|
||||||
|
|
||||||
private Consumer<PacketBody0Voice> voiceHandler;
|
private Consumer<PacketBody0Voice> voiceHandler;
|
||||||
|
private Consumer<PacketBody1VoiceWhisper> whisperHandler;
|
||||||
|
|
||||||
private Consumer<Throwable> exceptionHandler = Throwable::printStackTrace;
|
private Consumer<Throwable> exceptionHandler = Throwable::printStackTrace;
|
||||||
|
|
||||||
private Identity identity = null;
|
private Identity identity = null;
|
||||||
@@ -886,6 +888,14 @@ public abstract class AbstractTeamspeakClientSocket
|
|||||||
this.voiceHandler = voiceHandler;
|
this.voiceHandler = voiceHandler;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Consumer<PacketBody1VoiceWhisper> getWhisperHandler() {
|
||||||
|
return whisperHandler;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setWhisperHandler(Consumer<PacketBody1VoiceWhisper> whisperHandler) {
|
||||||
|
this.whisperHandler = whisperHandler;
|
||||||
|
}
|
||||||
|
|
||||||
private class NetworkHandler implements Runnable {
|
private class NetworkHandler implements Runnable {
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
|
|||||||
Reference in New Issue
Block a user