diff options
author | Andrew Comminos <andrewcomminos@gmail.com> | 2013-12-09 04:35:36 +0400 |
---|---|---|
committer | Andrew Comminos <andrewcomminos@gmail.com> | 2013-12-09 04:35:36 +0400 |
commit | 32906ccddb0ae0186928ea56692ae088c22525df (patch) | |
tree | 00f3c29364e699a7c3824cdeb176fcd844a8e1fe | |
parent | eae58cca15df72ee7b3cc2d0a0311b38ed739f23 (diff) |
Implemented reconnection procedure, generic audio and user fixes.
6 files changed, 104 insertions, 43 deletions
diff --git a/src/main/aidl/com/morlunk/jumble/IJumbleService.aidl b/src/main/aidl/com/morlunk/jumble/IJumbleService.aidl index 04ab76e..d044c85 100644 --- a/src/main/aidl/com/morlunk/jumble/IJumbleService.aidl +++ b/src/main/aidl/com/morlunk/jumble/IJumbleService.aidl @@ -26,6 +26,8 @@ interface IJumbleService { void disconnect(); boolean isConnected(); boolean isConnecting(); + boolean isReconnecting(); + void cancelReconnect(); /** * Gets the TCP latency, in nanoseconds. */ diff --git a/src/main/java/com/morlunk/jumble/JumbleService.java b/src/main/java/com/morlunk/jumble/JumbleService.java index 279fe61..1ec785d 100644 --- a/src/main/java/com/morlunk/jumble/JumbleService.java +++ b/src/main/java/com/morlunk/jumble/JumbleService.java @@ -53,6 +53,7 @@ import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Date; import java.util.List; +import java.util.concurrent.Executors; public class JumbleService extends Service implements JumbleConnection.JumbleConnectionListener { @@ -64,8 +65,8 @@ public class JumbleService extends Service implements JumbleConnection.JumbleCon /** Intent to connect to a Mumble server. See extras. **/ public static final String ACTION_CONNECT = "com.morlunk.jumble.CONNECT"; public static final String EXTRAS_SERVER = "server"; - public static final String EXTRAS_SHOW_CHAT_NOTIFICATION = "show_chat_notifications"; public static final String EXTRAS_AUTO_RECONNECT = "auto_reconnect"; + public static final String EXTRAS_AUTO_RECONNECT_DELAY = "auto_reconnect_delay"; public static final String EXTRAS_CERTIFICATE = "certificate"; public static final String EXTRAS_CERTIFICATE_PASSWORD = "certificate_password"; public static final String EXTRAS_DETECTION_THRESHOLD = "detection_threshold"; @@ -80,8 +81,8 @@ public class JumbleService extends Service implements JumbleConnection.JumbleCon // Service settings public Server mServer; - public boolean mShowChatNotifications; public boolean mAutoReconnect; + public int mAutoReconnectDelay; public byte[] mCertificate; public String mCertificatePassword; public float mDetectionThreshold; @@ -171,6 +172,7 @@ public class JumbleService extends Service implements JumbleConnection.JumbleCon }; private int mPermissions; + private boolean mReconnecting; private RemoteCallbackList<IJumbleObserver> mObservers = new RemoteCallbackList<IJumbleObserver>(); @@ -185,7 +187,8 @@ public class JumbleService extends Service implements JumbleConnection.JumbleCon @Override public void disconnect() throws RemoteException { - JumbleService.this.disconnect(); + if(isConnected()) + JumbleService.this.disconnect(); } @Override @@ -201,6 +204,16 @@ public class JumbleService extends Service implements JumbleConnection.JumbleCon } @Override + public boolean isReconnecting() throws RemoteException { + return mReconnecting; + } + + @Override + public void cancelReconnect() throws RemoteException { + mReconnecting = false; + } + + @Override public long getTCPLatency() throws RemoteException { return mConnection.getTCPLatency(); } @@ -482,8 +495,8 @@ public class JumbleService extends Service implements JumbleConnection.JumbleCon // Get connection parameters Bundle extras = intent.getExtras(); mServer = extras.getParcelable(EXTRAS_SERVER); - mShowChatNotifications = extras.getBoolean(EXTRAS_SHOW_CHAT_NOTIFICATION, true); mAutoReconnect = extras.getBoolean(EXTRAS_AUTO_RECONNECT, true); + mAutoReconnectDelay = extras.getInt(EXTRAS_AUTO_RECONNECT_DELAY, 5000); mCertificate = extras.getByteArray(EXTRAS_CERTIFICATE); mCertificatePassword = extras.getString(EXTRAS_CERTIFICATE_PASSWORD); mDetectionThreshold = extras.getFloat(EXTRAS_DETECTION_THRESHOLD, 0.5f); @@ -534,7 +547,7 @@ public class JumbleService extends Service implements JumbleConnection.JumbleCon } mPermissions = 0; - + mReconnecting = false; mChannelHandler = new ChannelHandler(this); mUserHandler = new UserHandler(this); mTextMessageHandler = new TextMessageHandler(this); @@ -546,8 +559,13 @@ public class JumbleService extends Service implements JumbleConnection.JumbleCon } public void disconnect() { - mConnection.disconnect(); - mConnection = null; + new Thread(new Runnable() { + @Override + public void run() { + mConnection.disconnect(); + mConnection = null; + } + }).start(); } public boolean isConnected() { @@ -585,7 +603,11 @@ public class JumbleService extends Service implements JumbleConnection.JumbleCon @Override public void onConnectionDisconnected() { Log.v(Constants.TAG, "Disconnected"); - unregisterReceiver(mBluetoothReceiver); + try { + unregisterReceiver(mBluetoothReceiver); + } catch (IllegalArgumentException e) { + e.printStackTrace(); + } mAudioOutput.stopPlaying(); mAudioInput.stopRecordingAndWait(); @@ -605,13 +627,21 @@ public class JumbleService extends Service implements JumbleConnection.JumbleCon mChannelHandler = null; mUserHandler = null; - - stopSelf(); } @Override public void onConnectionError(final JumbleConnectionException e) { Log.e(Constants.TAG, "Connection error: "+e.getMessage()); + if(mAutoReconnect) { + mReconnecting = true; + Handler mainHandler = new Handler(); + mainHandler.postDelayed(new Runnable() { + @Override + public void run() { + if(mReconnecting) connect(); + } + }, mAutoReconnectDelay); + } notifyObservers(new ObserverRunnable() { @Override public void run(IJumbleObserver observer) throws RemoteException { diff --git a/src/main/java/com/morlunk/jumble/audio/AudioInput.java b/src/main/java/com/morlunk/jumble/audio/AudioInput.java index cdc3e35..21bef55 100644 --- a/src/main/java/com/morlunk/jumble/audio/AudioInput.java +++ b/src/main/java/com/morlunk/jumble/audio/AudioInput.java @@ -149,8 +149,7 @@ public class AudioInput extends ProtocolHandler implements Runnable { * Based off of Mumble project's AudioInput method resetAudioProcessor(). */ private void configurePreprocessState() { - if(mPreprocessState != null) - mPreprocessState.destroy(); + if(mPreprocessState != null) mPreprocessState.destroy(); mPreprocessState = new Speex.SpeexPreprocessState(mFrameSize, Audio.SAMPLE_RATE); @@ -181,14 +180,22 @@ public class AudioInput extends ProtocolHandler implements Runnable { return; mCodec = codec; - if(mOpusEncoder != null) + if(mOpusEncoder != null) { Opus.opus_encoder_destroy(mOpusEncoder); - if(mCELTBetaEncoder != null) + mOpusEncoder = null; + } + if(mCELTBetaEncoder != null) { CELT11.celt_encoder_destroy(mCELTBetaEncoder); - if(mCELTAlphaEncoder != null) + mCELTBetaEncoder = null; + } + if(mCELTAlphaEncoder != null) { CELT7.celt_encoder_destroy(mCELTAlphaEncoder); - if(mCELTAlphaMode != null) + mCELTAlphaEncoder = null; + } + if(mCELTAlphaMode != null) { CELT7.celt_mode_destroy(mCELTAlphaMode); + mCELTAlphaMode = null; + } IntPointer error = new IntPointer(1); switch (codec) { diff --git a/src/main/java/com/morlunk/jumble/audio/AudioOutput.java b/src/main/java/com/morlunk/jumble/audio/AudioOutput.java index 32104c4..0bdb8ad 100644 --- a/src/main/java/com/morlunk/jumble/audio/AudioOutput.java +++ b/src/main/java/com/morlunk/jumble/audio/AudioOutput.java @@ -210,7 +210,7 @@ public class AudioOutput extends ProtocolHandler implements Runnable, AudioOutpu @Override public void onTalkStateUpdated(int session, User.TalkState state) { final User user = getService().getUserHandler().getUser(session); - if(user.getTalkState() != state) { + if(user != null && user.getTalkState() != state) { user.setTalkState(state); Handler handler = new Handler(Looper.getMainLooper()); handler.post(new Runnable() { diff --git a/src/main/java/com/morlunk/jumble/net/JumbleConnection.java b/src/main/java/com/morlunk/jumble/net/JumbleConnection.java index 9da8440..ecd8054 100644 --- a/src/main/java/com/morlunk/jumble/net/JumbleConnection.java +++ b/src/main/java/com/morlunk/jumble/net/JumbleConnection.java @@ -40,9 +40,12 @@ import java.security.cert.CertificateException; import java.util.Arrays; import java.util.List; import java.util.concurrent.ConcurrentLinkedQueue; +import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; +import java.util.concurrent.Future; import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.ScheduledFuture; import java.util.concurrent.TimeUnit; public class JumbleConnection { @@ -83,7 +86,9 @@ public class JumbleConnection { // Networking and protocols private InetAddress mHost; private JumbleTCP mTCP; + private Future mTCPTask; private JumbleUDP mUDP; + private ScheduledFuture mPingTask; private boolean mForceTCP; private boolean mUseOpus = true; private boolean mUseTor; @@ -124,7 +129,7 @@ public class JumbleConnection { } // Start TCP/UDP ping thread. FIXME is this the right place? - mPingExecutorService.scheduleAtFixedRate(mPingRunnable, 0, 5, TimeUnit.SECONDS); + mPingTask = mPingExecutorService.scheduleAtFixedRate(mPingRunnable, 0, 5, TimeUnit.SECONDS); mSession = msg.getSession(); mSynchronized = true; @@ -297,7 +302,7 @@ public class JumbleConnection { mUDP = new JumbleUDP(); mNetworkSendThread = new NetworkSendThread(); mExecutorService.submit(mNetworkSendThread); - mExecutorService.submit(mTCP); + mTCPTask = mExecutorService.submit(mTCP); // We'll start UDP thread after TCP is established. FIXME? } @@ -356,26 +361,35 @@ public class JumbleConnection { } /** - * Gracefully shuts down all networking. + * Gracefully shuts down all networking. Blocks until all network threads have stopped. */ public void disconnect() { mConnected = false; mSynchronized = false; - mNetworkSendHandler.postAtFrontOfQueue(new Runnable() { - @Override - public void run() { - try { - mTCP.disconnect(); - if (mUDP != null) mUDP.disconnect(); - } catch (IOException e) { - e.printStackTrace(); - } - mTCP = null; - mUDP = null; - } - }); - mExecutorService.shutdown(); - mPingExecutorService.shutdown(); + + // Stop running network resources + if(mPingTask != null) mPingTask.cancel(true); + try { + if(mTCP != null) mTCP.disconnect(); + if(mUDP != null) mUDP.disconnect(); + } catch (IOException e) { + e.printStackTrace(); + } + + // Block until main listening thread has stopped + try { + if(mTCPTask != null) mTCPTask.get(); + } catch (InterruptedException e) { + e.printStackTrace(); + } catch (ExecutionException e) { + e.printStackTrace(); + } + mTCP = null; + mTCPTask = null; + mUDP = null; + mPingTask = null; + mExecutorService.shutdownNow(); + mPingExecutorService.shutdownNow(); } /** @@ -412,7 +426,7 @@ public class JumbleConnection { } }); } - forceDisconnect(); + disconnect(); } /** @@ -831,6 +845,7 @@ public class JumbleConnection { public void disconnect() { mUDPSocket.disconnect(); + mUDPSocket.close(); } @Override diff --git a/src/main/java/com/morlunk/jumble/protocol/UserHandler.java b/src/main/java/com/morlunk/jumble/protocol/UserHandler.java index 48c1121..c8ac313 100644 --- a/src/main/java/com/morlunk/jumble/protocol/UserHandler.java +++ b/src/main/java/com/morlunk/jumble/protocol/UserHandler.java @@ -135,6 +135,13 @@ public class UserHandler extends ProtocolHandler { getService().logInfo(getService().getString(R.string.chat_notify_now_muted, MessageFormatter.highlightString(user.getName()))); else getService().logInfo(getService().getString(R.string.chat_notify_now_unmuted, MessageFormatter.highlightString(user.getName()))); + } else if(self != null && user.getSession() == self.getSession()) { + if(user.isSelfMuted() && user.isSelfDeafened()) + getService().logInfo(getService().getString(R.string.chat_notify_muted_deafened, MessageFormatter.highlightString(user.getName()))); + else if(user.isSelfMuted()) + getService().logInfo(getService().getString(R.string.chat_notify_muted, MessageFormatter.highlightString(user.getName()))); + else + getService().logInfo(getService().getString(R.string.chat_notify_unmuted, MessageFormatter.highlightString(user.getName()))); } } @@ -168,13 +175,13 @@ public class UserHandler extends ProtocolHandler { if(msg.hasPrioritySpeaker()) user.setPrioritySpeaker(msg.getPrioritySpeaker()); -/* if(self != null && ((user.getChannelId() == self.getChannelId()) || (actor.getSession() == self.getSession()))) { - if(user.getSession() == self.getSession()) { - if(msg.hasMute() && msg.hasDeaf() && user.isMuted() && user.isDeafened()) { - getService().logInfo(); - } - } - }*/ +// if(self != null && ((user.getChannelId() == self.getChannelId()) || (actor.getSession() == self.getSession()))) { +// if(user.getSession() == self.getSession()) { +// if(msg.hasMute() && msg.hasDeaf() && user.isMuted() && user.isDeafened()) { +// getService().logInfo(); +// } +// } +// } /* * TODO: logging |