diff options
6 files changed, 283 insertions, 230 deletions
diff --git a/src/androidTest/java/com/morlunk/jumble/test/JumbleServiceTest.java b/src/androidTest/java/com/morlunk/jumble/test/JumbleServiceTest.java index 1c3fd29..4410f92 100644 --- a/src/androidTest/java/com/morlunk/jumble/test/JumbleServiceTest.java +++ b/src/androidTest/java/com/morlunk/jumble/test/JumbleServiceTest.java @@ -48,7 +48,7 @@ public class JumbleServiceTest extends ServiceTestCase<JumbleService> { assertFalse(service.isReconnecting()); assertNull(service.getConnectionError()); assertEquals(JumbleService.ConnectionState.DISCONNECTED, service.getConnectionState()); - assertEquals(DUMMY_SERVER, service.getConnectedServer()); + assertEquals(DUMMY_SERVER, service.getTargetServer()); } } diff --git a/src/main/java/com/morlunk/jumble/IJumbleService.java b/src/main/java/com/morlunk/jumble/IJumbleService.java index 90b5d23..2080546 100644 --- a/src/main/java/com/morlunk/jumble/IJumbleService.java +++ b/src/main/java/com/morlunk/jumble/IJumbleService.java @@ -24,6 +24,7 @@ import com.morlunk.jumble.model.Server; import com.morlunk.jumble.model.WhisperTarget; import com.morlunk.jumble.net.JumbleUDPMessageType; import com.morlunk.jumble.util.IJumbleObserver; +import com.morlunk.jumble.util.JumbleDisconnectedException; import com.morlunk.jumble.util.JumbleException; import com.morlunk.jumble.util.VoiceTargetMode; @@ -42,6 +43,20 @@ import java.util.List; * will throw IllegalStateException if disconnected or not synchronized. */ public interface IJumbleService { + void registerObserver(IJumbleObserver observer); + + void unregisterObserver(IJumbleObserver observer); + + /** + * @return true if handshaking with the server has completed. + */ + boolean isConnected(); + + /** + * Disconnects from the active connection, or does nothing if no connection is active. + */ + void disconnect(); + /** * Returns the current connection state of the service. * @return one of {@link JumbleService.ConnectionState}. @@ -67,219 +82,15 @@ public interface IJumbleService { void cancelReconnect(); /** - * @return the latency in milliseconds for the TCP connection. - * @throws IllegalStateException if not connected. - */ - long getTCPLatency(); - - /** - * @return the latency in milliseconds for the UDP connection. - * @throws IllegalStateException if not connected. - */ - long getUDPLatency(); - - /** - * @return the maximum bandwidth in bps for audio allowed by the server, or -1 if not set. - * @throws IllegalStateException if not synchronized. - */ - int getMaxBandwidth(); - - /** - * @return the current bandwidth in bps for audio sent to the server, or a negative integer - * if unknown (prior to connection or after disconnection). - * @throws IllegalStateException if not synchronized. - */ - int getCurrentBandwidth(); - - /** - * Returns the protocol version returned by the server in the format 0xAABBCC, where AA - * indicates the major version, BB indicates the minor version, and CC indicates the patch - * version. This is the same formatting used by the Mumble protocol in big-endian format. - * @return the current bandwidth in bps for audio sent to the server, or a negative integer - * if unknown (prior to connection or after disconnection). - * @throws IllegalStateException if not synchronized. - */ - int getServerVersion(); - - /** - * @return a user-readable string with the server's Mumble release info. - * @throws IllegalStateException if not synchronized. - */ - String getServerRelease(); - - /** - * @return a user-readable string with the server's OS name. - * @throws IllegalStateException if not connected. - */ - String getServerOSName(); - - /** - * @return a user-readable string with the server's OS version. - * @throws IllegalStateException if not synchronized. - */ - String getServerOSVersion(); - - /** - * Returns the current user's session. Set during server synchronization. - * @return an integer identifying the current user's connection. - * @throws IllegalStateException if not synchronized. - */ - int getSession(); - - /** - * Returns the current user. Set during server synchronization. - * @return the {@link IUser} representing the current user. - * @throws IllegalStateException if not synchronized. - */ - IUser getSessionUser(); - - /** - * Returns the user's current channel. - * @return the {@link IChannel} representing the user's current channel. - * @throws IllegalStateException if not synchronized. - */ - IChannel getSessionChannel(); - - /** - * @return the server that Jumble is currently connected to (or attempted connection to). - */ - Server getConnectedServer(); - - /** - * Retrieves the user with the given session ID. - * @param session An integer ID identifying a user's session. See {@link IUser#getSession()}. - * @return A user with the given session, or null if not found. - * @throws IllegalStateException if not synchronized. - */ - IUser getUser(int session); - - /** - * Retrieves the channel with the given ID. - * @param id An integer ID identifying a channel. See {@link IChannel#getId()}. - * @return A channel with the given session, or null if not found. - * @throws IllegalStateException if not synchronized. - */ - IChannel getChannel(int id); - - /** - * @return the root channel of the server. - * @throws IllegalStateException if not synchronized. - */ - IChannel getRootChannel(); - - int getPermissions(); - - int getTransmitMode(); - - JumbleUDPMessageType getCodec(); - - boolean usingBluetoothSco(); - - void enableBluetoothSco(); - - void disableBluetoothSco(); - - boolean isTalking(); - - void setTalkingState(boolean talking); - - void joinChannel(int channel); - - void moveUserToChannel(int session, int channel); - - void createChannel(int parent, String name, String description, int position, boolean temporary); - - void sendAccessTokens(List<String> tokens); - - void requestBanList(); - - void requestUserList(); - - void requestPermissions(int channel); - - void requestComment(int session); - - void requestAvatar(int session); - - void requestChannelDescription(int channel); - - void registerUser(int session); - - void kickBanUser(int session, String reason, boolean ban); - - Message sendUserTextMessage(int session, String message); - - Message sendChannelTextMessage(int channel, String message, boolean tree); - - void setUserComment(int session, String comment); - - void setPrioritySpeaker(int session, boolean priority); - - void removeChannel(int channel); - - void setMuteDeafState(int session, boolean mute, boolean deaf); - - void setSelfMuteDeafState(boolean mute, boolean deaf); - - void registerObserver(IJumbleObserver observer); - - void unregisterObserver(IJumbleObserver observer); - - /** - * Links the provided two channels together. - */ - void linkChannels(IChannel channelA, IChannel channelB); - - /** - * Unlinks the two provided channels. - */ - void unlinkChannels(IChannel channelA, IChannel channelB); - - /** - * Unlinks all channels from the provided channel. - * @param channel The channel to be unlinked. - */ - void unlinkAllChannels(IChannel channel); - - /** - * Registers a whisper target to be used as a voice target on the server. - * Note that Mumble only supports a maximum of 30 active voice targets at once. - * @param target The target to register. - * @return A voice target ID in the range [1, 30], or a negative value if all slots are full. - */ - byte registerWhisperTarget(final WhisperTarget target); - - /** - * Unregisters a whisper target from the server. - * Note that Mumble only supports a maximum of 30 active voice targets at once. - * @param target The target ID to unregister. - */ - void unregisterWhisperTarget(byte targetId); - - /** - * Sets the active voice target to the provided ID.<br> - * 0: Normal speech<br> - * 1-30: Whisper targets<br> - * 31: Server loopback - * @param targetId A voice target ID in the range [0, 31]. - */ - void setVoiceTargetId(byte targetId); - - /** - * Gets the current voice target ID in use, in the range [0, 31]. - * @return The active voice target ID. - */ - byte getVoiceTargetId(); - - /** - * Gets the current voice target mode. - * @return The active voice target mode. + * @return the server that Jumble is currently connected to, was connected to, or will attempt connection to. */ - VoiceTargetMode getVoiceTargetMode(); + Server getTargetServer(); /** - * Returns the current whisper target. - * @return the set whisper target, or null if the user is not whispering. + * Returns the active session with the remote, or throws an exception if no session is currently + * active. This can be checked using {@link IJumbleService#isConnected()}. + * @return the active session. + * @throws JumbleDisconnectedException if the connection state is not CONNECTED. */ - WhisperTarget getWhisperTarget(); + IJumbleSession getSession() throws JumbleDisconnectedException; } diff --git a/src/main/java/com/morlunk/jumble/IJumbleSession.java b/src/main/java/com/morlunk/jumble/IJumbleSession.java new file mode 100644 index 0000000..a501f3e --- /dev/null +++ b/src/main/java/com/morlunk/jumble/IJumbleSession.java @@ -0,0 +1,213 @@ +package com.morlunk.jumble; + +import com.morlunk.jumble.model.IChannel; +import com.morlunk.jumble.model.IUser; +import com.morlunk.jumble.model.Message; +import com.morlunk.jumble.model.Server; +import com.morlunk.jumble.model.WhisperTarget; +import com.morlunk.jumble.net.JumbleUDPMessageType; +import com.morlunk.jumble.util.IJumbleObserver; +import com.morlunk.jumble.util.VoiceTargetMode; + +import java.util.List; + +/** + * An interface representing a live connection to the server. + * Created by andrew on 28/02/17. + */ + +public interface IJumbleSession { + /** + * @return the latency in milliseconds for the TCP connection. + */ + long getTCPLatency(); + + /** + * @return the latency in milliseconds for the UDP connection. + */ + long getUDPLatency(); + + /** + * @return the maximum bandwidth in bps for audio allowed by the server, or -1 if not set. + */ + int getMaxBandwidth(); + + /** + * @return the current bandwidth in bps for audio sent to the server, or a negative integer + * if unknown (prior to connection or after disconnection). + */ + int getCurrentBandwidth(); + + /** + * Returns the protocol version returned by the server in the format 0xAABBCC, where AA + * indicates the major version, BB indicates the minor version, and CC indicates the patch + * version. This is the same formatting used by the Mumble protocol in big-endian format. + * @return the current bandwidth in bps for audio sent to the server, or a negative integer + * if unknown (prior to connection or after disconnection). + */ + int getServerVersion(); + + /** + * @return a user-readable string with the server's Mumble release info. + */ + String getServerRelease(); + + /** + * @return a user-readable string with the server's OS name. + */ + String getServerOSName(); + + /** + * @return a user-readable string with the server's OS version. + */ + String getServerOSVersion(); + + /** + * Returns the current user's session. Set during server synchronization. + * @return an integer identifying the current user's connection. + */ + int getSessionId(); + + /** + * Returns the current user. Set during server synchronization. + * @return the {@link IUser} representing the current user. + */ + IUser getSessionUser(); + + /** + * Returns the user's current channel. + * @return the {@link IChannel} representing the user's current channel. + */ + IChannel getSessionChannel(); + + /** + * Retrieves the user with the given session ID. + * @param session An integer ID identifying a user's session. See {@link IUser#getSession()}. + * @return A user with the given session, or null if not found. + */ + IUser getUser(int session); + + /** + * Retrieves the channel with the given ID. + * @param id An integer ID identifying a channel. See {@link IChannel#getId()}. + * @return A channel with the given session, or null if not found. + */ + IChannel getChannel(int id); + + /** + * @return the root channel of the server. + */ + IChannel getRootChannel(); + + int getPermissions(); + + int getTransmitMode(); + + JumbleUDPMessageType getCodec(); + + boolean usingBluetoothSco(); + + void enableBluetoothSco(); + + void disableBluetoothSco(); + + boolean isTalking(); + + void setTalkingState(boolean talking); + + void joinChannel(int channel); + + void moveUserToChannel(int session, int channel); + + void createChannel(int parent, String name, String description, int position, boolean temporary); + + void sendAccessTokens(List<String> tokens); + + void requestBanList(); + + void requestUserList(); + + void requestPermissions(int channel); + + void requestComment(int session); + + void requestAvatar(int session); + + void requestChannelDescription(int channel); + + void registerUser(int session); + + void kickBanUser(int session, String reason, boolean ban); + + Message sendUserTextMessage(int session, String message); + + Message sendChannelTextMessage(int channel, String message, boolean tree); + + void setUserComment(int session, String comment); + + void setPrioritySpeaker(int session, boolean priority); + + void removeChannel(int channel); + + void setMuteDeafState(int session, boolean mute, boolean deaf); + + void setSelfMuteDeafState(boolean mute, boolean deaf); + + /** + * Links the provided two channels together. + */ + void linkChannels(IChannel channelA, IChannel channelB); + + /** + * Unlinks the two provided channels. + */ + void unlinkChannels(IChannel channelA, IChannel channelB); + + /** + * Unlinks all channels from the provided channel. + * @param channel The channel to be unlinked. + */ + void unlinkAllChannels(IChannel channel); + + /** + * Registers a whisper target to be used as a voice target on the server. + * Note that Mumble only supports a maximum of 30 active voice targets at once. + * @param target The target to register. + * @return A voice target ID in the range [1, 30], or a negative value if all slots are full. + */ + byte registerWhisperTarget(final WhisperTarget target); + + /** + * Unregisters a whisper target from the server. + * Note that Mumble only supports a maximum of 30 active voice targets at once. + * @param target The target ID to unregister. + */ + void unregisterWhisperTarget(byte targetId); + + /** + * Sets the active voice target to the provided ID.<br> + * 0: Normal speech<br> + * 1-30: Whisper targets<br> + * 31: Server loopback + * @param targetId A voice target ID in the range [0, 31]. + */ + void setVoiceTargetId(byte targetId); + + /** + * Gets the current voice target ID in use, in the range [0, 31]. + * @return The active voice target ID. + */ + byte getVoiceTargetId(); + + /** + * Gets the current voice target mode. + * @return The active voice target mode. + */ + VoiceTargetMode getVoiceTargetMode(); + + /** + * Returns the current whisper target. + * @return the set whisper target, or null if the user is not whispering. + */ + WhisperTarget getWhisperTarget(); +} diff --git a/src/main/java/com/morlunk/jumble/JumbleService.java b/src/main/java/com/morlunk/jumble/JumbleService.java index 65b5fd5..acbda30 100644 --- a/src/main/java/com/morlunk/jumble/JumbleService.java +++ b/src/main/java/com/morlunk/jumble/JumbleService.java @@ -55,6 +55,7 @@ import com.morlunk.jumble.model.WhisperTargetList; import com.morlunk.jumble.net.JumbleConnection; import com.morlunk.jumble.net.JumbleUDPMessageType; import com.morlunk.jumble.util.IJumbleObserver; +import com.morlunk.jumble.util.JumbleDisconnectedException; import com.morlunk.jumble.util.JumbleException; import com.morlunk.jumble.net.JumbleTCPMessageType; import com.morlunk.jumble.protobuf.Mumble; @@ -67,11 +68,9 @@ import com.morlunk.jumble.util.VoiceTargetMode; import java.security.Security; import java.security.cert.X509Certificate; import java.util.ArrayList; -import java.util.Hashtable; import java.util.List; -import java.util.Queue; -public class JumbleService extends Service implements IJumbleService, JumbleConnection.JumbleConnectionListener, JumbleLogger, BluetoothScoReceiver.Listener { +public class JumbleService extends Service implements IJumbleService, IJumbleSession, JumbleConnection.JumbleConnectionListener, JumbleLogger, BluetoothScoReceiver.Listener { static { // Use Spongy Castle for crypto implementation so we can create and manage PKCS #12 (.p12) certificates. @@ -303,7 +302,9 @@ public class JumbleService extends Service implements IJumbleService, JumbleConn } public void disconnect() { - mConnection.disconnect(); + if (mConnection != null) { + mConnection.disconnect(); + } } public boolean isConnectionEstablished() { @@ -709,6 +710,18 @@ public class JumbleService extends Service implements IJumbleService, JumbleConn } @Override + public Server getTargetServer() { + return mServer; + } + + @Override + public IJumbleSession getSession() throws JumbleDisconnectedException { + if (mConnectionState != ConnectionState.CONNECTED) + throw new JumbleDisconnectedException(); + return this; + } + + @Override public long getTCPLatency() { try { return getConnection().getTCPLatency(); @@ -781,7 +794,7 @@ public class JumbleService extends Service implements IJumbleService, JumbleConn } @Override - public int getSession() { + public int getSessionId() { try { return getConnection().getSession(); } catch (NotSynchronizedException e) { @@ -792,7 +805,7 @@ public class JumbleService extends Service implements IJumbleService, JumbleConn @Override public IUser getSessionUser() { try { - return getModelHandler().getUser(getSession()); + return getModelHandler().getUser(getSessionId()); } catch (NotSynchronizedException e) { throw new IllegalStateException(e); } @@ -807,11 +820,6 @@ public class JumbleService extends Service implements IJumbleService, JumbleConn } @Override - public Server getConnectedServer() { - return mServer; - } - - @Override public IUser getUser(int session) { try { return getModelHandler().getUser(session); @@ -896,7 +904,7 @@ public class JumbleService extends Service implements IJumbleService, JumbleConn @Override public void joinChannel(int channel) { - moveUserToChannel(getSession(), channel); + moveUserToChannel(getSessionId(), channel); } @Override @@ -989,11 +997,11 @@ public class JumbleService extends Service implements IJumbleService, JumbleConn tmb.setMessage(message); getConnection().sendTCPMessage(tmb.build(), JumbleTCPMessageType.TextMessage); - User self = getModelHandler().getUser(getSession()); + User self = getModelHandler().getUser(getSessionId()); User user = getModelHandler().getUser(session); List<User> users = new ArrayList<User>(1); users.add(user); - return new Message(getSession(), self.getName(), new ArrayList<Channel>(0), new ArrayList<Channel>(0), users, message); + return new Message(getSessionId(), self.getName(), new ArrayList<Channel>(0), new ArrayList<Channel>(0), users, message); } catch (NotSynchronizedException e) { throw new IllegalStateException(e); } @@ -1011,11 +1019,11 @@ public class JumbleService extends Service implements IJumbleService, JumbleConn tmb.setMessage(message); getConnection().sendTCPMessage(tmb.build(), JumbleTCPMessageType.TextMessage); - User self = getModelHandler().getUser(getSession()); + User self = getModelHandler().getUser(getSessionId()); Channel targetChannel = getModelHandler().getChannel(channel); List<Channel> targetChannels = new ArrayList<Channel>(); targetChannels.add(targetChannel); - return new Message(getSession(), self.getName(), targetChannels, tree ? targetChannels : new ArrayList<Channel>(0), new ArrayList<User>(0), message); + return new Message(getSessionId(), self.getName(), targetChannels, tree ? targetChannels : new ArrayList<Channel>(0), new ArrayList<User>(0), message); } catch (NotSynchronizedException e) { throw new IllegalStateException(e); } @@ -1071,6 +1079,11 @@ public class JumbleService extends Service implements IJumbleService, JumbleConn } @Override + public boolean isConnected() { + return mConnectionState == ConnectionState.CONNECTED; + } + + @Override public void linkChannels(IChannel channelA, IChannel channelB) { Mumble.ChannelState.Builder csb = Mumble.ChannelState.newBuilder(); csb.setChannelId(channelA.getId()); diff --git a/src/main/java/com/morlunk/jumble/protocol/ModelHandler.java b/src/main/java/com/morlunk/jumble/protocol/ModelHandler.java index 02789f6..f1917e4 100644 --- a/src/main/java/com/morlunk/jumble/protocol/ModelHandler.java +++ b/src/main/java/com/morlunk/jumble/protocol/ModelHandler.java @@ -315,8 +315,8 @@ public class ModelHandler extends JumbleTCPMessageListener.Stub { if(msg.hasPrioritySpeaker()) user.setPrioritySpeaker(msg.getPrioritySpeaker()); -// if(self != null && ((user.getChannelId() == self.getChannelId()) || (actor.getSession() == self.getSession()))) { -// if(user.getSession() == self.getSession()) { +// if(self != null && ((user.getChannelId() == self.getChannelId()) || (actor.getSessionId() == self.getSessionId()))) { +// if(user.getSessionId() == self.getSessionId()) { // if(msg.hasMute() && msg.hasDeaf() && user.isMuted() && user.isDeafened()) { // mLogger.logInfo(); // } diff --git a/src/main/java/com/morlunk/jumble/util/JumbleDisconnectedException.java b/src/main/java/com/morlunk/jumble/util/JumbleDisconnectedException.java new file mode 100644 index 0000000..2b51e6c --- /dev/null +++ b/src/main/java/com/morlunk/jumble/util/JumbleDisconnectedException.java @@ -0,0 +1,16 @@ +package com.morlunk.jumble.util; + +/** + * Called when a + * Created by andrew on 01/03/17. + */ + +public class JumbleDisconnectedException extends RuntimeException { + public JumbleDisconnectedException() { + super("Caller attempted to use the protocol while disconnected."); + } + + public JumbleDisconnectedException(String reason) { + super(reason); + } +} |