Welcome to mirror list, hosted at ThFree Co, Russian Federation.

gitlab.com/quite/humla.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndrew Comminos <andrewcomminos@gmail.com>2013-08-18 02:22:44 +0400
committerAndrew Comminos <andrewcomminos@gmail.com>2013-08-18 02:22:44 +0400
commit3f44098d66e3d117db6312f9e49ce6d43333f178 (patch)
tree9ffc0be00961015f25bc9941bd8de7c542077ccd /src/main/java
parentf76b49c3e8072795e13f6bd4fb1634ab38514e10 (diff)
More audio and Tor work, added libonionkit.
Diffstat (limited to 'src/main/java')
-rw-r--r--src/main/java/com/morlunk/jumble/Constants.java6
-rw-r--r--src/main/java/com/morlunk/jumble/JumbleService.java23
-rw-r--r--src/main/java/com/morlunk/jumble/audio/AudioOutput.java54
-rw-r--r--src/main/java/com/morlunk/jumble/audio/AudioOutputSpeech.java9
-rw-r--r--src/main/java/com/morlunk/jumble/model/Server.java12
-rw-r--r--src/main/java/com/morlunk/jumble/net/JumbleConnection.java33
-rw-r--r--src/main/java/com/morlunk/jumble/net/JumbleSSLSocketFactory.java80
7 files changed, 128 insertions, 89 deletions
diff --git a/src/main/java/com/morlunk/jumble/Constants.java b/src/main/java/com/morlunk/jumble/Constants.java
index eb9522b..83e6b54 100644
--- a/src/main/java/com/morlunk/jumble/Constants.java
+++ b/src/main/java/com/morlunk/jumble/Constants.java
@@ -31,9 +31,9 @@ public class Constants {
static {
// Load CELT bitstream versions from JNI. TODO clean me with renamed types for version
- int error = 0;
- com.morlunk.jumble.audio.celt11.SWIGTYPE_p_CELTMode celt11Mode = CELT11.celt_mode_create(Audio.SAMPLE_RATE, Audio.FRAME_SIZE, new int[] { error });
- com.morlunk.jumble.audio.celt7.SWIGTYPE_p_CELTMode celt7Mode = CELT7.celt_mode_create(Audio.SAMPLE_RATE, Audio.FRAME_SIZE, new int[] { error });
+ int[] error = new int[1];
+ com.morlunk.jumble.audio.celt11.SWIGTYPE_p_CELTMode celt11Mode = CELT11.celt_mode_create(Audio.SAMPLE_RATE, Audio.FRAME_SIZE, error);
+ com.morlunk.jumble.audio.celt7.SWIGTYPE_p_CELTMode celt7Mode = CELT7.celt_mode_create(Audio.SAMPLE_RATE, Audio.FRAME_SIZE, error);
int[] celt11Version = new int[1];
int[] celt7Version = new int[1];
diff --git a/src/main/java/com/morlunk/jumble/JumbleService.java b/src/main/java/com/morlunk/jumble/JumbleService.java
index e458fd5..b68e5f7 100644
--- a/src/main/java/com/morlunk/jumble/JumbleService.java
+++ b/src/main/java/com/morlunk/jumble/JumbleService.java
@@ -181,6 +181,13 @@ public class JumbleService extends Service implements JumbleConnection.JumbleCon
}
@Override
+ public void sendAccessTokens(List tokens) throws RemoteException {
+ Mumble.Authenticate.Builder ab = Mumble.Authenticate.newBuilder();
+ ab.addAllTokens(tokens);
+ mConnection.sendTCPMessage(ab.build(), JumbleTCPMessageType.Authenticate);
+ }
+
+ @Override
public void requestBanList() throws RemoteException {
}
@@ -191,6 +198,20 @@ public class JumbleService extends Service implements JumbleConnection.JumbleCon
}
@Override
+ public void requestComment(int session) throws RemoteException {
+ Mumble.RequestBlob.Builder rbb = Mumble.RequestBlob.newBuilder();
+ rbb.addSessionComment(session);
+ mConnection.sendTCPMessage(rbb.build(), JumbleTCPMessageType.RequestBlob);
+ }
+
+ @Override
+ public void requestChannelDescription(int channel) throws RemoteException {
+ Mumble.RequestBlob.Builder rbb = Mumble.RequestBlob.newBuilder();
+ rbb.addChannelDescription(channel);
+ mConnection.sendTCPMessage(rbb.build(), JumbleTCPMessageType.RequestBlob);
+ }
+
+ @Override
public void registerUser(int session) throws RemoteException {
Mumble.UserState.Builder usb = Mumble.UserState.newBuilder();
usb.setSession(session);
@@ -347,6 +368,8 @@ public class JumbleService extends Service implements JumbleConnection.JumbleCon
public void onConnectionEstablished() {
Log.v(Constants.TAG, "Connected");
+ mAudioOutput.startPlaying();
+
notifyObservers(new ObserverRunnable() {
@Override
public void run(IJumbleObserver observer) throws RemoteException {
diff --git a/src/main/java/com/morlunk/jumble/audio/AudioOutput.java b/src/main/java/com/morlunk/jumble/audio/AudioOutput.java
index 740ddfb..830c91c 100644
--- a/src/main/java/com/morlunk/jumble/audio/AudioOutput.java
+++ b/src/main/java/com/morlunk/jumble/audio/AudioOutput.java
@@ -19,6 +19,8 @@ package com.morlunk.jumble.audio;
import android.media.AudioFormat;
import android.media.AudioManager;
import android.media.AudioTrack;
+import android.os.Handler;
+import android.os.Looper;
import android.os.Process;
import android.os.RemoteException;
import android.util.Log;
@@ -46,6 +48,7 @@ public class AudioOutput extends JumbleMessageHandler.Stub implements Runnable,
private AudioTrack mAudioTrack;
private Thread mThread;
+ private Object mInactiveLock = new Object(); // Lock that the audio thread waits on when there's no audio to play. Wake when we get a frame.
private boolean mRunning = false;
public AudioOutput(JumbleService service) {
@@ -75,17 +78,32 @@ public class AudioOutput extends JumbleMessageHandler.Stub implements Runnable,
@Override
public void run() {
- Log.v(Constants.TAG, "Started audio output");
+ Log.v(Constants.TAG, "Started audio output thread.");
android.os.Process.setThreadPriority(Process.THREAD_PRIORITY_URGENT_AUDIO);
mRunning = true;
+ mAudioTrack.play();
final short[] mix = new short[Audio.FRAME_SIZE*12];
while(mRunning) {
- mix(mix, mix.length);
- mAudioTrack.write(mix, 0, mix.length);
- mAudioTrack.play();
+ boolean play = mix(mix, mix.length);
+ if(play) {
+ mAudioTrack.write(mix, 0, mix.length);
+ } else {
+ Log.v(Constants.TAG, "Pausing audio output thread.");
+ synchronized (mInactiveLock) {
+ try {
+ mInactiveLock.wait();
+ } catch (InterruptedException e) {
+ e.printStackTrace();
+ }
+ }
+ Log.v(Constants.TAG, "Resuming audio output thread.");
+ }
}
+
+ mAudioTrack.flush();
+ mAudioTrack.stop();
}
private boolean mix(short[] outBuffer, int bufferSize) {
@@ -95,7 +113,7 @@ public class AudioOutput extends JumbleMessageHandler.Stub implements Runnable,
// TODO add priority speaker support
for(AudioOutputSpeech speech : mAudioOutputs.values()) {
- if(speech.needSamples(bufferSize))
+ if(!speech.needSamples(bufferSize))
del.add(speech);
else
mix.add(speech);
@@ -134,7 +152,7 @@ public class AudioOutput extends JumbleMessageHandler.Stub implements Runnable,
if(user != null && !user.isLocalMuted()) {
// TODO check for whispers here
int seq = pds.next();
- ByteBuffer packet = ByteBuffer.allocate(pds.left() + 1);
+ ByteBuffer packet = ByteBuffer.allocate(pds.left() + 4);
packet.putInt(msgFlags);
packet.put(pds.dataBlock(pds.left()));
@@ -149,6 +167,9 @@ public class AudioOutput extends JumbleMessageHandler.Stub implements Runnable,
}
aop.addFrameToBuffer(packet.array(), seq);
+ synchronized (mInactiveLock) {
+ mInactiveLock.notify();
+ }
}
}
@@ -156,11 +177,20 @@ public class AudioOutput extends JumbleMessageHandler.Stub implements Runnable,
@Override
public void onTalkStateUpdated(int session, User.TalkState state) {
final User user = mService.getUserHandler().getUser(session);
- mService.notifyObservers(new JumbleService.ObserverRunnable() {
- @Override
- public void run(IJumbleObserver observer) throws RemoteException {
- observer.onUserTalkStateUpdated(user);
- }
- });;
+ if(user.getTalkState() != state) {
+ user.setTalkState(state);
+ Handler handler = new Handler(Looper.getMainLooper());
+ handler.post(new Runnable() {
+ @Override
+ public void run() {
+ mService.notifyObservers(new JumbleService.ObserverRunnable() {
+ @Override
+ public void run(IJumbleObserver observer) throws RemoteException {
+ observer.onUserTalkStateUpdated(user);
+ }
+ });;
+ }
+ });
+ }
}
}
diff --git a/src/main/java/com/morlunk/jumble/audio/AudioOutputSpeech.java b/src/main/java/com/morlunk/jumble/audio/AudioOutputSpeech.java
index e56ff8b..3ce543b 100644
--- a/src/main/java/com/morlunk/jumble/audio/AudioOutputSpeech.java
+++ b/src/main/java/com/morlunk/jumble/audio/AudioOutputSpeech.java
@@ -16,6 +16,9 @@
package com.morlunk.jumble.audio;
+import android.util.Log;
+
+import com.morlunk.jumble.Constants;
import com.morlunk.jumble.audio.celt11.CELT11;
import com.morlunk.jumble.audio.celt7.CELT7;
import com.morlunk.jumble.audio.opus.Opus;
@@ -93,6 +96,7 @@ public class AudioOutputSpeech {
break;
}
+ mBuffer = new float[mAudioBufferSize];
mJitterBuffer = Speex.jitter_buffer_init(Audio.FRAME_SIZE);
Speex.jitter_buffer_ctl(mJitterBuffer, SpeexConstants.JITTER_BUFFER_SET_MARGIN, new int[] { 10 * Audio.FRAME_SIZE });
}
@@ -154,7 +158,6 @@ public class AudioOutputSpeech {
while(mBufferFilled < num) {
int decodedSamples = Audio.FRAME_SIZE;
resizeBuffer(mBufferFilled + mAudioBufferSize);
- System.arraycopy(mBuffer, mBufferFilled, out, 0, mAudioBufferSize);
if(!mLastAlive)
Arrays.fill(out, 0);
@@ -212,7 +215,7 @@ public class AudioOutputSpeech {
}
} else {
synchronized (mJitterBuffer) {
- Speex.jitter_buffer_update_delay(mJitterBuffer, jbp, null);
+ Speex.jitter_buffer_update_delay(mJitterBuffer, jbp, new int[] { 0 });
}
mMissCount++;
@@ -281,6 +284,7 @@ public class AudioOutputSpeech {
}
}
+ System.arraycopy(out, 0, mBuffer, mBufferFilled, mAudioBufferSize);
mBufferFilled += mAudioBufferSize;
}
@@ -306,6 +310,7 @@ public class AudioOutputSpeech {
boolean tmp = mLastAlive;
mLastAlive = nextAlive;
+
return tmp;
}
diff --git a/src/main/java/com/morlunk/jumble/model/Server.java b/src/main/java/com/morlunk/jumble/model/Server.java
index b66b185..d93f54c 100644
--- a/src/main/java/com/morlunk/jumble/model/Server.java
+++ b/src/main/java/com/morlunk/jumble/model/Server.java
@@ -21,7 +21,7 @@ import android.os.Parcelable;
public class Server implements Parcelable {
- private int mId;
+ private long mId;
private String mName;
private String mHost;
private int mPort;
@@ -41,7 +41,7 @@ public class Server implements Parcelable {
}
};
- public Server(int id, String name, String host, int port, String username, String password) {
+ public Server(long id, String name, String host, int port, String username, String password) {
mId = id;
mName = name;
mHost = host;
@@ -57,7 +57,7 @@ public class Server implements Parcelable {
@Override
public void writeToParcel(Parcel parcel, int i) {
- parcel.writeInt(mId);
+ parcel.writeLong(mId);
parcel.writeString(mName);
parcel.writeString(mHost);
parcel.writeInt(mPort);
@@ -66,7 +66,7 @@ public class Server implements Parcelable {
}
public void readFromParcel(Parcel in) {
- mId = in.readInt();
+ mId = in.readLong();
mName = in.readString();
mHost = in.readString();
mPort = in.readInt();
@@ -79,11 +79,11 @@ public class Server implements Parcelable {
return 0;
}
- public int getId() {
+ public long getId() {
return mId;
}
- public void setId(int id) {
+ public void setId(long id) {
mId = id;
}
diff --git a/src/main/java/com/morlunk/jumble/net/JumbleConnection.java b/src/main/java/com/morlunk/jumble/net/JumbleConnection.java
index fc9400c..c0c6a5c 100644
--- a/src/main/java/com/morlunk/jumble/net/JumbleConnection.java
+++ b/src/main/java/com/morlunk/jumble/net/JumbleConnection.java
@@ -29,21 +29,24 @@ import com.morlunk.jumble.Constants;
import com.morlunk.jumble.model.Server;
import com.morlunk.jumble.protobuf.Mumble;
-import org.apache.http.params.BasicHttpParams;
-import org.apache.http.params.HttpParams;
-
import javax.net.ssl.SSLSocket;
+import javax.net.ssl.SSLSocketFactory;
+
import java.io.*;
import java.net.*;
import java.nio.ByteBuffer;
import java.security.*;
import java.security.cert.CertificateException;
+import java.util.Arrays;
+import java.util.List;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
+import ch.boye.httpclientandroidlib.params.BasicHttpParams;
+import ch.boye.httpclientandroidlib.params.HttpParams;
import socks.Socks5Proxy;
import socks.SocksSocket;
@@ -55,6 +58,14 @@ public class JumbleConnection {
public void onConnectionWarning(String warning);
}
+ /**
+ * Message types that aren't shown in logcat.
+ * For annoying types like UDPTunnel.
+ */
+ public static final List<JumbleTCPMessageType> UNLOGGED_MESSAGES = Arrays.asList(new JumbleTCPMessageType[] {
+ JumbleTCPMessageType.UDPTunnel
+ });
+
// Tor connection details
public static final String TOR_HOST = "localhost";
public static final int TOR_PORT = 9050;
@@ -464,7 +475,8 @@ public class JumbleConnection {
}
private final void handleTCPMessage(byte[] data, int length, JumbleTCPMessageType messageType) {
- Log.v(Constants.TAG, "IN: "+messageType);
+ if(!UNLOGGED_MESSAGES.contains(messageType))
+ Log.v(Constants.TAG, "IN: "+messageType);
if(messageType == JumbleTCPMessageType.UDPTunnel) {
handleUDPMessage(data);
@@ -694,15 +706,10 @@ public class JumbleConnection {
handleFatalException(new JumbleConnectionException("Could not resolve host", e, true));
}
- HttpParams httpParams = new BasicHttpParams();
-
- if(mUseTor) {
- Socks5Proxy proxy = new Socks5Proxy(TOR_HOST, TOR_PORT);
- proxy.resolveAddrLocally(false); // Tor requirement for SOCKS5 is to let it resolve the host.
- SocksSocket proxySocket = new SocksSocket(proxy, mServer.getHost(), mServer.getPort());
- mTCPSocket = (SSLSocket) mSocketFactory.connectSocket(proxySocket, mServer.getHost(), mServer.getPort(), null, 0, httpParams);
- } else
- mTCPSocket = (SSLSocket) mSocketFactory.connectSocket(null, mServer.getHost(), mServer.getPort(), null, 0, httpParams);
+ if(mUseTor)
+ mTCPSocket = mSocketFactory.createTorSocket(mServer.getHost(), mServer.getPort(), TOR_HOST, TOR_PORT);
+ else
+ mTCPSocket = mSocketFactory.createSocket(mServer.getHost(), mServer.getPort());
mTCPSocket.startHandshake();
diff --git a/src/main/java/com/morlunk/jumble/net/JumbleSSLSocketFactory.java b/src/main/java/com/morlunk/jumble/net/JumbleSSLSocketFactory.java
index 55697a5..28344de 100644
--- a/src/main/java/com/morlunk/jumble/net/JumbleSSLSocketFactory.java
+++ b/src/main/java/com/morlunk/jumble/net/JumbleSSLSocketFactory.java
@@ -17,9 +17,8 @@
package com.morlunk.jumble.net;
import java.io.IOException;
-import java.net.Proxy;
+import java.net.InetSocketAddress;
import java.net.Socket;
-import java.net.SocketAddress;
import java.security.KeyManagementException;
import java.security.KeyStore;
import java.security.KeyStoreException;
@@ -27,66 +26,41 @@ import java.security.NoSuchAlgorithmException;
import java.security.NoSuchProviderException;
import java.security.SecureRandom;
import java.security.UnrecoverableKeyException;
-import java.security.cert.CertificateException;
-import java.security.cert.X509Certificate;
-import javax.net.ssl.KeyManager;
-import javax.net.ssl.KeyManagerFactory;
-import javax.net.ssl.SSLContext;
-import javax.net.ssl.TrustManager;
-import javax.net.ssl.X509TrustManager;
+import javax.net.ssl.SSLSocket;
-import org.apache.http.conn.ssl.SSLSocketFactory;
+import ch.boye.httpclientandroidlib.conn.ssl.SSLSocketFactory;
+import ch.boye.httpclientandroidlib.params.BasicHttpParams;
+import ch.boye.httpclientandroidlib.params.HttpParams;
+import socks.Socks5Proxy;
+import socks.SocksSocket;
-public class JumbleSSLSocketFactory extends SSLSocketFactory {
-
- /**
- * A trust manager which will accept all remote certificates, regardless of validity.
- * FIXME: this is poor cryptographic practice and allows for a potential MitM attack -AC
- */
- private static final TrustManager sPermissiveTrustManager = new X509TrustManager() {
- @Override
- public void checkClientTrusted(X509Certificate[] x509Certificates, String s) throws CertificateException {
-
- }
-
- @Override
- public void checkServerTrusted(X509Certificate[] x509Certificates, String s) throws CertificateException {
-
- }
-
- @Override
- public X509Certificate[] getAcceptedIssuers() {
- return new X509Certificate[0];
- }
- };
-
- private SSLContext mSslContext = SSLContext.getInstance(TLS);
+public class JumbleSSLSocketFactory {
+ private SSLSocketFactory mSocketFactory;
public JumbleSSLSocketFactory(KeyStore keystore, String keystorePassword) throws NoSuchAlgorithmException, KeyManagementException, KeyStoreException,
UnrecoverableKeyException, NoSuchProviderException {
- super(keystore, keystorePassword, null); // No need for trust store at the moment. FIXME security
-
- setHostnameVerifier(ALLOW_ALL_HOSTNAME_VERIFIER); // FIXME security
-
- KeyManager[] keyManagers = null;
-
- if(keystore != null) {
- KeyManagerFactory factory = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
- factory.init(keystore, keystorePassword != null ? keystorePassword.toCharArray() : null);
- keyManagers = factory.getKeyManagers();
- }
-
- mSslContext.init(keyManagers, new TrustManager[] { sPermissiveTrustManager }, new SecureRandom());
+ mSocketFactory = new SSLSocketFactory(SSLSocketFactory.TLS,
+ keystore,
+ keystorePassword,
+ null,
+ new SecureRandom(),
+ SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER); // No need for trust store at the moment. FIXME security
}
- @Override
- public Socket createSocket(Socket socket, String host, int port, boolean autoClose) throws IOException {
- return mSslContext.getSocketFactory().createSocket(socket, host, port, autoClose);
+ /**
+ * Creates a new SSLSocket that runs through a SOCKS5 proxy to reach its destination.
+ */
+ public SSLSocket createTorSocket(String host, int port, String proxyHost, int proxyPort) throws IOException {
+ Socks5Proxy proxy = new Socks5Proxy(proxyHost, proxyPort);
+ proxy.resolveAddrLocally(false); // Let SOCKS5 proxy resolve host. Useful for Tor.
+ SocksSocket socksSocket = new SocksSocket(proxy, host, port);
+ return (SSLSocket) mSocketFactory.createLayeredSocket(socksSocket, proxyHost, proxyPort, new BasicHttpParams());
}
- @Override
- public Socket createSocket() throws IOException {
- return mSslContext.getSocketFactory().createSocket();
+ public SSLSocket createSocket(String host, int port) throws IOException {
+ HttpParams params = new BasicHttpParams();
+ Socket socket = mSocketFactory.createSocket(params);
+ return (SSLSocket) mSocketFactory.connectSocket(socket, new InetSocketAddress(host, port), null, params);
}
} \ No newline at end of file