├── src
├── main
│ ├── res
│ │ ├── values-eo
│ │ │ └── strings.xml
│ │ ├── values-it
│ │ │ └── strings.xml
│ │ ├── values-pl
│ │ │ └── strings.xml
│ │ ├── values-ja
│ │ │ └── strings.xml
│ │ ├── values-ru
│ │ │ └── strings.xml
│ │ ├── values-nl
│ │ │ └── strings.xml
│ │ ├── values-es
│ │ │ └── strings.xml
│ │ ├── values-fr
│ │ │ └── strings.xml
│ │ ├── values-de
│ │ │ └── strings.xml
│ │ └── values
│ │ │ └── strings.xml
│ ├── jni
│ │ ├── Application.mk
│ │ ├── Android.mk
│ │ ├── celt-0.7.0-build
│ │ │ └── config.h
│ │ └── celt-0.11.0-build
│ │ │ └── config.h
│ ├── java
│ │ └── com
│ │ │ └── morlunk
│ │ │ └── jumble
│ │ │ ├── audio
│ │ │ ├── IAudioMixerSource.java
│ │ │ ├── IAudioMixer.java
│ │ │ ├── BasicClippingShortMixer.java
│ │ │ ├── InvalidSampleRateException.java
│ │ │ ├── inputmode
│ │ │ │ ├── ContinuousInputMode.java
│ │ │ │ ├── IInputMode.java
│ │ │ │ ├── ActivityInputMode.java
│ │ │ │ └── ToggleInputMode.java
│ │ │ ├── AudioUser.java
│ │ │ ├── IDecoder.java
│ │ │ ├── encoder
│ │ │ │ ├── IEncoder.java
│ │ │ │ ├── ResamplingEncoder.java
│ │ │ │ ├── PreprocessingEncoder.java
│ │ │ │ ├── CELT11Encoder.java
│ │ │ │ ├── CELT7Encoder.java
│ │ │ │ └── OpusEncoder.java
│ │ │ ├── BluetoothScoReceiver.java
│ │ │ └── javacpp
│ │ │ │ ├── CELT11.java
│ │ │ │ ├── CELT7.java
│ │ │ │ └── Opus.java
│ │ │ ├── util
│ │ │ ├── JumbleDisconnectedException.java
│ │ │ ├── JumbleLogger.java
│ │ │ ├── VoiceTargetMode.java
│ │ │ ├── MessageFormatter.java
│ │ │ ├── IJumbleObserver.java
│ │ │ ├── MumbleURLParser.java
│ │ │ ├── JumbleObserver.java
│ │ │ ├── JumbleException.java
│ │ │ ├── JumbleNetworkListener.java
│ │ │ └── JumbleCallbacks.java
│ │ │ ├── net
│ │ │ ├── JumbleUDPMessageType.java
│ │ │ ├── Permissions.java
│ │ │ ├── JumbleTCPMessageType.java
│ │ │ ├── JumbleNetworkThread.java
│ │ │ ├── JumbleCertificateGenerator.java
│ │ │ └── JumbleSSLSocketFactory.java
│ │ │ ├── model
│ │ │ ├── IMessage.java
│ │ │ ├── WhisperTarget.java
│ │ │ ├── WhisperTargetUsers.java
│ │ │ ├── IChannel.java
│ │ │ ├── IUser.java
│ │ │ ├── TalkState.java
│ │ │ ├── WhisperTargetChannel.java
│ │ │ ├── WhisperTargetList.java
│ │ │ ├── Server.java
│ │ │ └── Message.java
│ │ │ ├── exception
│ │ │ ├── NotConnectedException.java
│ │ │ ├── AudioException.java
│ │ │ ├── NotSynchronizedException.java
│ │ │ ├── NativeAudioException.java
│ │ │ └── AudioInitializationException.java
│ │ │ ├── protocol
│ │ │ ├── JumbleUDPMessageListener.java
│ │ │ └── JumbleTCPMessageListener.java
│ │ │ ├── Constants.java
│ │ │ └── IJumbleService.java
│ └── AndroidManifest.xml
└── androidTest
│ └── java
│ └── com
│ └── morlunk
│ └── jumble
│ └── test
│ ├── JumbleServiceTest.java
│ ├── MixerTest.java
│ ├── ModelTest.java
│ ├── EncoderTest.java
│ └── URLParserTest.java
├── tools
├── javacpp-0.7.jar
├── jnigen.sh
└── mkp12.sh
├── gradle
└── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── libs
├── sc-morlunk-pkix-1.51.0.0.jar
└── sc-morlunk-prov-1.51.0.0.jar
├── .gitignore
├── .gitmodules
├── README.md
├── gradlew.bat
└── gradlew
/src/main/res/values-eo/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
--------------------------------------------------------------------------------
/tools/javacpp-0.7.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/acomminos/Jumble/HEAD/tools/javacpp-0.7.jar
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/acomminos/Jumble/HEAD/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/libs/sc-morlunk-pkix-1.51.0.0.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/acomminos/Jumble/HEAD/libs/sc-morlunk-pkix-1.51.0.0.jar
--------------------------------------------------------------------------------
/libs/sc-morlunk-prov-1.51.0.0.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/acomminos/Jumble/HEAD/libs/sc-morlunk-prov-1.51.0.0.jar
--------------------------------------------------------------------------------
/src/main/jni/Application.mk:
--------------------------------------------------------------------------------
1 | #APP_OPTIM := debug
2 | APP_ABI := armeabi-v7a armeabi x86
3 | APP_STL := gnustl_static
--------------------------------------------------------------------------------
/src/main/res/values-it/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | Server
4 |
5 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Gradle / Android Studio
2 | build/
3 | .idea/
4 | .gradle/
5 | *.iml
6 |
7 | # Android
8 | local.properties
9 |
10 | # Native
11 | src/main/libs/
12 | src/main/obj/
13 |
14 | # Java
15 | *.class
16 |
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | #Wed Apr 10 15:27:10 PDT 2013
2 | distributionBase=GRADLE_USER_HOME
3 | distributionPath=wrapper/dists
4 | zipStoreBase=GRADLE_USER_HOME
5 | zipStorePath=wrapper/dists
6 | distributionUrl=http\://services.gradle.org/distributions/gradle-1.12-all.zip
7 |
--------------------------------------------------------------------------------
/src/main/java/com/morlunk/jumble/audio/IAudioMixerSource.java:
--------------------------------------------------------------------------------
1 | package com.morlunk.jumble.audio;
2 |
3 | /**
4 | * A source for an {@link IAudioMixer}.
5 | * Stores samples in a collection of type {@link T}.
6 | */
7 | public interface IAudioMixerSource {
8 | T getSamples();
9 | int getNumSamples();
10 | }
11 |
--------------------------------------------------------------------------------
/src/main/java/com/morlunk/jumble/audio/IAudioMixer.java:
--------------------------------------------------------------------------------
1 | package com.morlunk.jumble.audio;
2 |
3 | import java.util.Collection;
4 |
5 | /**
6 | * A mixer for {@link IAudioMixerSource}s, where {@link T} is the source buffer type and {@link U}
7 | * is the destination buffer type.
8 | */
9 | public interface IAudioMixer {
10 | void mix(Collection> sources, U buffer, int bufferOffset,
11 | int bufferLength);
12 | }
13 |
--------------------------------------------------------------------------------
/.gitmodules:
--------------------------------------------------------------------------------
1 | [submodule "src/main/jni/opus"]
2 | path = src/main/jni/opus
3 | url = https://git.xiph.org/opus.git
4 | [submodule "src/main/jni/celt-0.11.0-src"]
5 | path = src/main/jni/celt-0.11.0-src
6 | url = https://git.xiph.org/celt.git
7 | [submodule "src/main/jni/celt-0.7.0-src"]
8 | path = src/main/jni/celt-0.7.0-src
9 | url = https://git.xiph.org/celt.git
10 | [submodule "src/main/jni/speex"]
11 | path = src/main/jni/speex
12 | url = https://git.xiph.org/speex.git
13 |
--------------------------------------------------------------------------------
/tools/jnigen.sh:
--------------------------------------------------------------------------------
1 | # Generates the necessary JNI to use native audio libraries using JavaCPP.
2 | # Call this from the project root.
3 | if [ "$1" == "--build" ]; then
4 | # Build classes if we provide --build
5 | ./gradlew assembleDebug
6 | fi
7 |
8 | java -jar tools/javacpp-0.7.jar -cp build/intermediates/classes/debug/ -d src/main/jni/ -nocompile com.morlunk.jumble.audio.javacpp.*
9 |
10 | if [ "$1" == "--build" ]; then
11 | # Build native libs
12 | ndk-build -C src/main/jni
13 | fi
14 |
--------------------------------------------------------------------------------
/src/main/java/com/morlunk/jumble/util/JumbleDisconnectedException.java:
--------------------------------------------------------------------------------
1 | package com.morlunk.jumble.util;
2 |
3 | /**
4 | * Called when a
5 | * Created by andrew on 01/03/17.
6 | */
7 |
8 | public class JumbleDisconnectedException extends RuntimeException {
9 | public JumbleDisconnectedException() {
10 | super("Caller attempted to use the protocol while disconnected.");
11 | }
12 |
13 | public JumbleDisconnectedException(String reason) {
14 | super(reason);
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/tools/mkp12.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | # Copyright (C) 2013 Andrew Comminos
3 | #
4 | # Licensed under the Apache License, Version 2.0 (the "License");
5 | # you may not use this file except in compliance with the License.
6 | # You may obtain a copy of the License at
7 | #
8 | # http://www.apache.org/licenses/LICENSE-2.0
9 | #
10 | # Unless required by applicable law or agreed to in writing, software
11 | # distributed under the License is distributed on an "AS IS" BASIS,
12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | # See the License for the specific language governing permissions and
14 | # limitations under the License.
15 |
16 | if [ "$1" == "" ]; then
17 | echo "You need to specify an output path."
18 | exit 1
19 | fi
20 |
21 | openssl req -nodes -batch -newkey rsa:2048 -x509 -days 30 -keyout jumble.key -out jumble.crt
22 | openssl pkcs12 -export -out $1 -inkey jumble.key -in jumble.crt
23 | rm jumble.crt
24 | rm jumble.key
--------------------------------------------------------------------------------
/src/main/java/com/morlunk/jumble/audio/BasicClippingShortMixer.java:
--------------------------------------------------------------------------------
1 | package com.morlunk.jumble.audio;
2 |
3 | import java.util.Collection;
4 |
5 | /**
6 | * A simple mixer that downsamples source floating point PCM to shorts, clipping naively.
7 | */
8 | public class BasicClippingShortMixer implements IAudioMixer {
9 | @Override
10 | public void mix(Collection> sources, short[] buffer, int bufferOffset,
11 | int bufferLength) {
12 | for (int i = 0; i < bufferLength; i++) {
13 | float mix = 0;
14 | for (IAudioMixerSource source : sources) {
15 | mix += source.getSamples()[i];
16 | }
17 | // Clip to [-1,1].
18 | if (mix > 1)
19 | mix = 1;
20 | else if (mix < -1)
21 | mix = -1;
22 | buffer[i + bufferOffset] = (short) (mix * Short.MAX_VALUE);
23 | }
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/src/main/java/com/morlunk/jumble/net/JumbleUDPMessageType.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2014 Andrew Comminos
3 | *
4 | * This program is free software: you can redistribute it and/or modify
5 | * it under the terms of the GNU General Public License as published by
6 | * the Free Software Foundation, either version 3 of the License, or
7 | * (at your option) any later version.
8 | *
9 | * This program is distributed in the hope that it will be useful,
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | * GNU General Public License for more details.
13 | *
14 | * You should have received a copy of the GNU General Public License
15 | * along with this program. If not, see .
16 | */
17 |
18 | package com.morlunk.jumble.net;
19 |
20 | public enum JumbleUDPMessageType {
21 | UDPVoiceCELTAlpha,
22 | UDPPing,
23 | UDPVoiceSpeex,
24 | UDPVoiceCELTBeta,
25 | UDPVoiceOpus
26 | }
27 |
--------------------------------------------------------------------------------
/src/main/java/com/morlunk/jumble/util/JumbleLogger.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2014 Andrew Comminos
3 | *
4 | * This program is free software: you can redistribute it and/or modify
5 | * it under the terms of the GNU General Public License as published by
6 | * the Free Software Foundation, either version 3 of the License, or
7 | * (at your option) any later version.
8 | *
9 | * This program is distributed in the hope that it will be useful,
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | * GNU General Public License for more details.
13 | *
14 | * You should have received a copy of the GNU General Public License
15 | * along with this program. If not, see .
16 | */
17 |
18 | package com.morlunk.jumble.util;
19 |
20 | import com.morlunk.jumble.model.Message;
21 |
22 | /**
23 | * An interface for reporting user-readable information.
24 | * Created by andrew on 12/07/14.
25 | */
26 | public interface JumbleLogger {
27 | void logInfo(String message);
28 | void logWarning(String message);
29 | void logError(String message);
30 | }
31 |
--------------------------------------------------------------------------------
/src/main/res/values-pl/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | %1$s został przeniesiony z kanału %2$s przez %3$s.
4 | Ogłuszony oraz wyciszony mikrofon.
5 | Wyciszony mikrofon
6 | Wyłączono wyciszenie mikrofonu.
7 | Wyłączono ogłuszenie oraz wyciszenie mikrofonu.
8 | %s jest teraz ogłuszony oraz wyciszony.
9 | %s jest teraz wyciszony.
10 | %s nie jest już wyciszony.
11 | %s nie jest już ogłuszony.
12 | %s połączony.
13 | %s rozłączony.
14 | %1$s został przeniesiony z kanału %2$s przez %3$s.
15 | Serwer
16 |
17 |
--------------------------------------------------------------------------------
/src/main/java/com/morlunk/jumble/audio/InvalidSampleRateException.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2014 Andrew Comminos
3 | *
4 | * This program is free software: you can redistribute it and/or modify
5 | * it under the terms of the GNU General Public License as published by
6 | * the Free Software Foundation, either version 3 of the License, or
7 | * (at your option) any later version.
8 | *
9 | * This program is distributed in the hope that it will be useful,
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | * GNU General Public License for more details.
13 | *
14 | * You should have received a copy of the GNU General Public License
15 | * along with this program. If not, see .
16 | */
17 |
18 | package com.morlunk.jumble.audio;
19 |
20 | /**
21 | * Created by andrew on 23/04/14.
22 | */
23 | public class InvalidSampleRateException extends Exception {
24 | public InvalidSampleRateException(Exception e) {
25 | super(e);
26 | }
27 |
28 | public InvalidSampleRateException(String message) {
29 | super(message);
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/src/main/java/com/morlunk/jumble/model/IMessage.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2015 Andrew Comminos
3 | *
4 | * This program is free software: you can redistribute it and/or modify
5 | * it under the terms of the GNU General Public License as published by
6 | * the Free Software Foundation, either version 3 of the License, or
7 | * (at your option) any later version.
8 | *
9 | * This program is distributed in the hope that it will be useful,
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | * GNU General Public License for more details.
13 | *
14 | * You should have received a copy of the GNU General Public License
15 | * along with this program. If not, see .
16 | */
17 |
18 | package com.morlunk.jumble.model;
19 |
20 | import java.util.List;
21 |
22 | public interface IMessage {
23 | int getActor();
24 |
25 | String getActorName();
26 |
27 | List getTargetChannels();
28 |
29 | List getTargetTrees();
30 |
31 | List getTargetUsers();
32 |
33 | String getMessage();
34 |
35 | long getReceivedTime();
36 | }
37 |
--------------------------------------------------------------------------------
/src/main/java/com/morlunk/jumble/audio/inputmode/ContinuousInputMode.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2016 Andrew Comminos
3 | *
4 | * This program is free software: you can redistribute it and/or modify
5 | * it under the terms of the GNU General Public License as published by
6 | * the Free Software Foundation, either version 3 of the License, or
7 | * (at your option) any later version.
8 | *
9 | * This program is distributed in the hope that it will be useful,
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | * GNU General Public License for more details.
13 | *
14 | * You should have received a copy of the GNU General Public License
15 | * along with this program. If not, see .
16 | */
17 |
18 | package com.morlunk.jumble.audio.inputmode;
19 |
20 | /**
21 | * An input mode that always transmits audio.
22 | * Created by andrew on 13/02/16.
23 | */
24 | public class ContinuousInputMode implements IInputMode {
25 | @Override
26 | public boolean shouldTransmit(short[] pcm, int length) {
27 | return true;
28 | }
29 |
30 | @Override
31 | public void waitForInput() {
32 |
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/src/main/java/com/morlunk/jumble/exception/NotConnectedException.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2015 Andrew Comminos
3 | *
4 | * This program is free software: you can redistribute it and/or modify
5 | * it under the terms of the GNU General Public License as published by
6 | * the Free Software Foundation, either version 3 of the License, or
7 | * (at your option) any later version.
8 | *
9 | * This program is distributed in the hope that it will be useful,
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | * GNU General Public License for more details.
13 | *
14 | * You should have received a copy of the GNU General Public License
15 | * along with this program. If not, see .
16 | */
17 |
18 | package com.morlunk.jumble.exception;
19 |
20 | /**
21 | * Thrown when a Jumble connection has not yet been established.
22 | * Created by andrew on 24/10/15.
23 | */
24 | public class NotConnectedException extends Exception {
25 | public NotConnectedException() {
26 | super("Not yet connected");
27 | }
28 |
29 | public NotConnectedException(String message) {
30 | super(message);
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/src/main/java/com/morlunk/jumble/exception/AudioException.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2014 Andrew Comminos
3 | *
4 | * This program is free software: you can redistribute it and/or modify
5 | * it under the terms of the GNU General Public License as published by
6 | * the Free Software Foundation, either version 3 of the License, or
7 | * (at your option) any later version.
8 | *
9 | * This program is distributed in the hope that it will be useful,
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | * GNU General Public License for more details.
13 | *
14 | * You should have received a copy of the GNU General Public License
15 | * along with this program. If not, see .
16 | */
17 |
18 | package com.morlunk.jumble.exception;
19 |
20 | /**
21 | * Created by andrew on 28/04/14.
22 | */
23 | public class AudioException extends Exception {
24 | public AudioException(String message) {
25 | super(message);
26 | }
27 |
28 | public AudioException(Throwable throwable) {
29 | super(throwable);
30 | }
31 |
32 | public AudioException(String message, Throwable throwable) {
33 | super(message, throwable);
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/src/main/java/com/morlunk/jumble/model/WhisperTarget.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2016 Andrew Comminos
3 | *
4 | * This program is free software: you can redistribute it and/or modify
5 | * it under the terms of the GNU General Public License as published by
6 | * the Free Software Foundation, either version 3 of the License, or
7 | * (at your option) any later version.
8 | *
9 | * This program is distributed in the hope that it will be useful,
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | * GNU General Public License for more details.
13 | *
14 | * You should have received a copy of the GNU General Public License
15 | * along with this program. If not, see .
16 | */
17 |
18 | package com.morlunk.jumble.model;
19 |
20 | import com.morlunk.jumble.protobuf.Mumble;
21 |
22 | /**
23 | * Created by andrew on 28/04/16.
24 | */
25 | public interface WhisperTarget {
26 | Mumble.VoiceTarget.Target createTarget();
27 |
28 | /**
29 | * Returns a user-readable name for the whisper target, to display in the UI.
30 | * @return A channel name or list of users, depending on the implementation.
31 | */
32 | String getName();
33 | }
--------------------------------------------------------------------------------
/src/main/java/com/morlunk/jumble/exception/NotSynchronizedException.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2015 Andrew Comminos
3 | *
4 | * This program is free software: you can redistribute it and/or modify
5 | * it under the terms of the GNU General Public License as published by
6 | * the Free Software Foundation, either version 3 of the License, or
7 | * (at your option) any later version.
8 | *
9 | * This program is distributed in the hope that it will be useful,
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | * GNU General Public License for more details.
13 | *
14 | * You should have received a copy of the GNU General Public License
15 | * along with this program. If not, see .
16 | */
17 |
18 | package com.morlunk.jumble.exception;
19 |
20 | /**
21 | * Called when Jumble has not yet received the ServerSync message from the server.
22 | * Created by andrew on 24/10/15.
23 | */
24 | public class NotSynchronizedException extends Exception {
25 | public NotSynchronizedException() {
26 | super("Not yet synchronized");
27 | }
28 |
29 | public NotSynchronizedException(String message) {
30 | super(message);
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/src/main/java/com/morlunk/jumble/exception/NativeAudioException.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2014 Andrew Comminos
3 | *
4 | * This program is free software: you can redistribute it and/or modify
5 | * it under the terms of the GNU General Public License as published by
6 | * the Free Software Foundation, either version 3 of the License, or
7 | * (at your option) any later version.
8 | *
9 | * This program is distributed in the hope that it will be useful,
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | * GNU General Public License for more details.
13 | *
14 | * You should have received a copy of the GNU General Public License
15 | * along with this program. If not, see .
16 | */
17 |
18 | package com.morlunk.jumble.exception;
19 |
20 | /**
21 | * Created by andrew on 07/03/14.
22 | */
23 | public class NativeAudioException extends AudioException {
24 | public NativeAudioException(String message) {
25 | super(message);
26 | }
27 |
28 | public NativeAudioException(Throwable throwable) {
29 | super(throwable);
30 | }
31 |
32 | public NativeAudioException(String message, Throwable throwable) {
33 | super(message, throwable);
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/src/main/java/com/morlunk/jumble/model/WhisperTargetUsers.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2016 Andrew Comminos
3 | *
4 | * This program is free software: you can redistribute it and/or modify
5 | * it under the terms of the GNU General Public License as published by
6 | * the Free Software Foundation, either version 3 of the License, or
7 | * (at your option) any later version.
8 | *
9 | * This program is distributed in the hope that it will be useful,
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | * GNU General Public License for more details.
13 | *
14 | * You should have received a copy of the GNU General Public License
15 | * along with this program. If not, see .
16 | */
17 |
18 | package com.morlunk.jumble.model;
19 |
20 | import com.morlunk.jumble.protobuf.Mumble;
21 |
22 | /**
23 | * Created by andrew on 28/04/16.
24 | */
25 | public class WhisperTargetUsers implements WhisperTarget {
26 | @Override
27 | public Mumble.VoiceTarget.Target createTarget() {
28 | throw new UnsupportedOperationException(); // TODO
29 | }
30 |
31 | @Override
32 | public String getName() {
33 | throw new UnsupportedOperationException(); // TODO
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/src/main/java/com/morlunk/jumble/exception/AudioInitializationException.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2014 Andrew Comminos
3 | *
4 | * This program is free software: you can redistribute it and/or modify
5 | * it under the terms of the GNU General Public License as published by
6 | * the Free Software Foundation, either version 3 of the License, or
7 | * (at your option) any later version.
8 | *
9 | * This program is distributed in the hope that it will be useful,
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | * GNU General Public License for more details.
13 | *
14 | * You should have received a copy of the GNU General Public License
15 | * along with this program. If not, see .
16 | */
17 |
18 | package com.morlunk.jumble.exception;
19 |
20 | /**
21 | * Created by andrew on 28/04/14.
22 | */
23 | public class AudioInitializationException extends AudioException {
24 | public AudioInitializationException(String message) {
25 | super(message);
26 | }
27 |
28 | public AudioInitializationException(Throwable throwable) {
29 | super(throwable);
30 | }
31 |
32 | public AudioInitializationException(String message, Throwable throwable) {
33 | super(message, throwable);
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/src/main/java/com/morlunk/jumble/model/IChannel.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2015 Andrew Comminos
3 | *
4 | * This program is free software: you can redistribute it and/or modify
5 | * it under the terms of the GNU General Public License as published by
6 | * the Free Software Foundation, either version 3 of the License, or
7 | * (at your option) any later version.
8 | *
9 | * This program is distributed in the hope that it will be useful,
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | * GNU General Public License for more details.
13 | *
14 | * You should have received a copy of the GNU General Public License
15 | * along with this program. If not, see .
16 | */
17 |
18 | package com.morlunk.jumble.model;
19 |
20 | import java.util.List;
21 |
22 | public interface IChannel {
23 | List extends IUser> getUsers();
24 |
25 | int getId();
26 |
27 | int getPosition();
28 |
29 | boolean isTemporary();
30 |
31 | IChannel getParent();
32 |
33 | String getName();
34 |
35 | String getDescription();
36 |
37 | byte[] getDescriptionHash();
38 |
39 | List extends IChannel> getSubchannels();
40 |
41 | int getSubchannelUserCount();
42 |
43 | List extends IChannel> getLinks();
44 |
45 | int getPermissions();
46 | }
47 |
--------------------------------------------------------------------------------
/src/main/java/com/morlunk/jumble/protocol/JumbleUDPMessageListener.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2014 Andrew Comminos
3 | *
4 | * This program is free software: you can redistribute it and/or modify
5 | * it under the terms of the GNU General Public License as published by
6 | * the Free Software Foundation, either version 3 of the License, or
7 | * (at your option) any later version.
8 | *
9 | * This program is distributed in the hope that it will be useful,
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | * GNU General Public License for more details.
13 | *
14 | * You should have received a copy of the GNU General Public License
15 | * along with this program. If not, see .
16 | */
17 |
18 | package com.morlunk.jumble.protocol;
19 |
20 | import com.morlunk.jumble.net.JumbleUDPMessageType;
21 |
22 | /**
23 | * Created by andrew on 21/01/14.
24 | */
25 |
26 | public interface JumbleUDPMessageListener {
27 |
28 | public void messageUDPPing(byte[] data);
29 | public void messageVoiceData(byte[] data, JumbleUDPMessageType messageType);
30 |
31 | public static class Stub implements JumbleUDPMessageListener {
32 |
33 | public void messageUDPPing(byte[] data) {}
34 | public void messageVoiceData(byte[] data, JumbleUDPMessageType messageType) {}
35 | }
36 | }
--------------------------------------------------------------------------------
/src/main/java/com/morlunk/jumble/net/Permissions.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2014 Andrew Comminos
3 | *
4 | * This program is free software: you can redistribute it and/or modify
5 | * it under the terms of the GNU General Public License as published by
6 | * the Free Software Foundation, either version 3 of the License, or
7 | * (at your option) any later version.
8 | *
9 | * This program is distributed in the hope that it will be useful,
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | * GNU General Public License for more details.
13 | *
14 | * You should have received a copy of the GNU General Public License
15 | * along with this program. If not, see .
16 | */
17 |
18 | package com.morlunk.jumble.net;
19 |
20 | /**
21 | * Created by andrew on 21/08/13.
22 | */
23 | public class Permissions {
24 | public static final int None = 0x0,
25 | Write = 0x1,
26 | Traverse = 0x2,
27 | Enter = 0x4,
28 | Speak = 0x8,
29 | MuteDeafen = 0x10,
30 | Move = 0x20,
31 | MakeChannel = 0x40,
32 | LinkChannel = 0x80,
33 | Whisper = 0x100,
34 | TextMessage = 0x200,
35 | MakeTempChannel = 0x400,
36 |
37 | // Root channel only
38 | Kick = 0x10000,
39 | Ban = 0x20000,
40 | Register = 0x40000,
41 | SelfRegister = 0x80000,
42 |
43 | Cached = 0x8000000,
44 | All = 0xf07ff;
45 | }
46 |
--------------------------------------------------------------------------------
/src/main/java/com/morlunk/jumble/util/VoiceTargetMode.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2016 Andrew Comminos
3 | *
4 | * This program is free software: you can redistribute it and/or modify
5 | * it under the terms of the GNU General Public License as published by
6 | * the Free Software Foundation, either version 3 of the License, or
7 | * (at your option) any later version.
8 | *
9 | * This program is distributed in the hope that it will be useful,
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | * GNU General Public License for more details.
13 | *
14 | * You should have received a copy of the GNU General Public License
15 | * along with this program. If not, see .
16 | */
17 |
18 | package com.morlunk.jumble.util;
19 |
20 | /**
21 | * Created by andrew on 29/04/16.
22 | */
23 | public enum VoiceTargetMode {
24 | NORMAL,
25 | WHISPER,
26 | SERVER_LOOPBACK;
27 |
28 | public static VoiceTargetMode fromId(byte targetId) {
29 | if (targetId == 0) {
30 | return VoiceTargetMode.NORMAL;
31 | } else if (targetId > 0 && targetId < 31) {
32 | return VoiceTargetMode.WHISPER;
33 | } else if (targetId == 31) {
34 | return VoiceTargetMode.SERVER_LOOPBACK;
35 | } else {
36 | throw new IllegalArgumentException();
37 | }
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | Jumble
2 | ======
3 |
4 | An Android service implementation of the Mumble protocol, designed as the backend of [Plumble](https://www.github.com/acomminos/Plumble).
5 |
6 | About
7 | -----
8 |
9 | The primary goal of the Jumble project is to encourage developers to embrace the Mumble protocol on Android through a free, complete, and stable implementation. At the moment, development is focused on improving stability and security.
10 |
11 | Prior to the release of Jumble, all implementations of the Mumble protocol on Android have been using the same non-free code developed by @pcgod. To ensure the unencumbered use of Jumble, no sources or derivatives will be copied from that project.
12 |
13 | Projects using Jumble
14 | ---------------------
15 |
16 | [Plumble 3.0+](https://www.github.com/acomminos/Plumble)
17 |
18 | Including in your project
19 | -------------------------
20 |
21 | Jumble is a standard Android library project using the gradle build system. [See here for instructions on how to include it into your gradle project](http://tools.android.com/tech-docs/new-build-system/user-guide#TOC-Referencing-a-Library).
22 |
23 | Currently, there is no tutorial to integrate Jumble with your project. In the mean time, please examine the exposed interface IJumbleService as well as Plumble's implementation.
24 |
25 | License
26 | -------
27 |
28 | Jumble is now licensed under the GNU GPL v3+. See LICENSE.
29 |
30 | If you wish to incorporate Jumble into your proprietary project, please email me to discuss licensing.
31 |
--------------------------------------------------------------------------------
/src/main/java/com/morlunk/jumble/net/JumbleTCPMessageType.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2014 Andrew Comminos
3 | *
4 | * This program is free software: you can redistribute it and/or modify
5 | * it under the terms of the GNU General Public License as published by
6 | * the Free Software Foundation, either version 3 of the License, or
7 | * (at your option) any later version.
8 | *
9 | * This program is distributed in the hope that it will be useful,
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | * GNU General Public License for more details.
13 | *
14 | * You should have received a copy of the GNU General Public License
15 | * along with this program. If not, see .
16 | */
17 |
18 | package com.morlunk.jumble.net;
19 |
20 | /**
21 | * Message types pulled from the Mumble project's 'Message.h' for protocol version 1.2.4.
22 | */
23 | public enum JumbleTCPMessageType {
24 | Version,
25 | UDPTunnel,
26 | Authenticate,
27 | Ping,
28 | Reject,
29 | ServerSync,
30 | ChannelRemove,
31 | ChannelState,
32 | UserRemove,
33 | UserState,
34 | BanList,
35 | TextMessage,
36 | PermissionDenied,
37 | ACL,
38 | QueryUsers,
39 | CryptSetup,
40 | ContextActionModify,
41 | ContextAction,
42 | UserList,
43 | VoiceTarget,
44 | PermissionQuery,
45 | CodecVersion,
46 | UserStats,
47 | RequestBlob,
48 | ServerConfig,
49 | SuggestConfig
50 | }
51 |
--------------------------------------------------------------------------------
/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
17 |
18 |
22 |
23 |
24 |
25 |
26 |
27 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
--------------------------------------------------------------------------------
/src/main/java/com/morlunk/jumble/util/MessageFormatter.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2014 Andrew Comminos
3 | *
4 | * This program is free software: you can redistribute it and/or modify
5 | * it under the terms of the GNU General Public License as published by
6 | * the Free Software Foundation, either version 3 of the License, or
7 | * (at your option) any later version.
8 | *
9 | * This program is distributed in the hope that it will be useful,
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | * GNU General Public License for more details.
13 | *
14 | * You should have received a copy of the GNU General Public License
15 | * along with this program. If not, see .
16 | */
17 |
18 | package com.morlunk.jumble.util;
19 |
20 | /**
21 | * Formats strings into HTML.
22 | * Created by andrew on 24/08/13.
23 | */
24 | public class MessageFormatter {
25 |
26 | public static final String HIGHLIGHT_COLOR = "33b5e5";
27 |
28 | private static final String HTML_FONT_COLOR_FORMAT = "%s";
29 |
30 | /**
31 | * Highlights the passed string using the service's defined color {@link MessageFormatter#HIGHLIGHT_COLOR}.
32 | * @param string The string to highlight.
33 | * @return The passed string enclosed with HTML font tags specifying the color.
34 | */
35 | public static String highlightString(String string) {
36 | return String.format(HTML_FONT_COLOR_FORMAT, HIGHLIGHT_COLOR, string);
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/src/main/java/com/morlunk/jumble/Constants.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2014 Andrew Comminos
3 | *
4 | * This program is free software: you can redistribute it and/or modify
5 | * it under the terms of the GNU General Public License as published by
6 | * the Free Software Foundation, either version 3 of the License, or
7 | * (at your option) any later version.
8 | *
9 | * This program is distributed in the hope that it will be useful,
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | * GNU General Public License for more details.
13 | *
14 | * You should have received a copy of the GNU General Public License
15 | * along with this program. If not, see .
16 | */
17 |
18 | package com.morlunk.jumble;
19 |
20 | /**
21 | * @deprecated Constant values should be associated with the class in which they are used.
22 | */
23 | public class Constants {
24 | public static final int PROTOCOL_MAJOR = 1;
25 | public static final int PROTOCOL_MINOR = 2;
26 | public static final int PROTOCOL_PATCH = 5;
27 |
28 | public static final int TRANSMIT_VOICE_ACTIVITY = 0;
29 | public static final int TRANSMIT_PUSH_TO_TALK = 1;
30 | public static final int TRANSMIT_CONTINUOUS = 2;
31 |
32 | public static final int PROTOCOL_VERSION = (PROTOCOL_MAJOR << 16) | (PROTOCOL_MINOR << 8) | PROTOCOL_PATCH;
33 | public static final String PROTOCOL_STRING = PROTOCOL_MAJOR+ "." +PROTOCOL_MINOR+"."+PROTOCOL_PATCH;
34 | public static final int DEFAULT_PORT = 64738;
35 |
36 | public static final String TAG = "Jumble";
37 | }
38 |
--------------------------------------------------------------------------------
/src/main/java/com/morlunk/jumble/model/IUser.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2015 Andrew Comminos
3 | *
4 | * This program is free software: you can redistribute it and/or modify
5 | * it under the terms of the GNU General Public License as published by
6 | * the Free Software Foundation, either version 3 of the License, or
7 | * (at your option) any later version.
8 | *
9 | * This program is distributed in the hope that it will be useful,
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | * GNU General Public License for more details.
13 | *
14 | * You should have received a copy of the GNU General Public License
15 | * along with this program. If not, see .
16 | */
17 |
18 | package com.morlunk.jumble.model;
19 |
20 | /**
21 | * Created by andrew on 15/10/15.
22 | */
23 | public interface IUser {
24 | int getSession();
25 |
26 | Channel getChannel();
27 |
28 | int getUserId();
29 |
30 | String getName();
31 |
32 | String getComment();
33 |
34 | byte[] getCommentHash();
35 |
36 | byte[] getTexture();
37 |
38 | byte[] getTextureHash();
39 |
40 | String getHash();
41 |
42 | boolean isMuted();
43 |
44 | boolean isDeafened();
45 |
46 | boolean isSuppressed();
47 |
48 | boolean isSelfMuted();
49 |
50 | boolean isSelfDeafened();
51 |
52 | boolean isPrioritySpeaker();
53 |
54 | boolean isRecording();
55 |
56 | boolean isLocalMuted();
57 |
58 | boolean isLocalIgnored();
59 |
60 | void setLocalMuted(boolean muted);
61 |
62 | void setLocalIgnored(boolean ignored);
63 |
64 | TalkState getTalkState();
65 | }
66 |
--------------------------------------------------------------------------------
/src/main/java/com/morlunk/jumble/model/TalkState.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2015 Andrew Comminos
3 | *
4 | * This program is free software: you can redistribute it and/or modify
5 | * it under the terms of the GNU General Public License as published by
6 | * the Free Software Foundation, either version 3 of the License, or
7 | * (at your option) any later version.
8 | *
9 | * This program is distributed in the hope that it will be useful,
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | * GNU General Public License for more details.
13 | *
14 | * You should have received a copy of the GNU General Public License
15 | * along with this program. If not, see .
16 | */
17 |
18 | package com.morlunk.jumble.model;
19 |
20 | import android.os.Parcel;
21 | import android.os.Parcelable;
22 |
23 | /**
24 | * User talk state.
25 | * Created by andrew on 19/04/15.
26 | */
27 | public enum TalkState implements Parcelable {
28 | TALKING,
29 | SHOUTING,
30 | PASSIVE,
31 | WHISPERING;
32 |
33 | public static Creator CREATOR = new Creator() {
34 | @Override
35 | public TalkState createFromParcel(Parcel source) {
36 | return TalkState.values()[source.readInt()];
37 | }
38 |
39 | @Override
40 | public TalkState[] newArray(int size) {
41 | return new TalkState[size];
42 | }
43 | };
44 |
45 | @Override
46 | public int describeContents() {
47 | return 0;
48 | }
49 |
50 | @Override
51 | public void writeToParcel(Parcel dest, int flags) {
52 | dest.writeInt(ordinal());
53 | }
54 | }
55 |
--------------------------------------------------------------------------------
/src/main/java/com/morlunk/jumble/audio/inputmode/IInputMode.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2016 Andrew Comminos
3 | *
4 | * This program is free software: you can redistribute it and/or modify
5 | * it under the terms of the GNU General Public License as published by
6 | * the Free Software Foundation, either version 3 of the License, or
7 | * (at your option) any later version.
8 | *
9 | * This program is distributed in the hope that it will be useful,
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | * GNU General Public License for more details.
13 | *
14 | * You should have received a copy of the GNU General Public License
15 | * along with this program. If not, see .
16 | */
17 |
18 | package com.morlunk.jumble.audio.inputmode;
19 |
20 | import java.util.concurrent.locks.Condition;
21 |
22 | /**
23 | * A talk state engine, providing information regarding when it is appropriate to send audio.
24 | * Created by andrew on 13/02/16.
25 | */
26 | public interface IInputMode {
27 | /**
28 | * Called when new input is received from the audio recording thread.
29 | * @param pcm PCM data.
30 | * @param length The number of shorts in the PCM data.
31 | * @return true if the input should be transmitted.
32 | */
33 | boolean shouldTransmit(short[] pcm, int length);
34 |
35 | /**
36 | * Called before any audio processing to wait for a change in input availability.
37 | * For example, a push to talk implementation will block the audio input thread until the
38 | * button has been activated. Other implementations may do nothing.
39 | *
40 | * This function should return immediately when shouldTransmit is returning true.
41 | */
42 | void waitForInput();
43 | }
44 |
--------------------------------------------------------------------------------
/src/main/java/com/morlunk/jumble/audio/AudioUser.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2015 Andrew Comminos
3 | *
4 | * This program is free software: you can redistribute it and/or modify
5 | * it under the terms of the GNU General Public License as published by
6 | * the Free Software Foundation, either version 3 of the License, or
7 | * (at your option) any later version.
8 | *
9 | * This program is distributed in the hope that it will be useful,
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | * GNU General Public License for more details.
13 | *
14 | * You should have received a copy of the GNU General Public License
15 | * along with this program. If not, see .
16 | */
17 |
18 | package com.morlunk.jumble.audio;
19 |
20 | /**
21 | * Created by andrew on 05/04/15.
22 | */
23 | public class AudioUser {
24 | private static final float AVERAGE_DECAY = 0.99f;
25 |
26 | private int mSession;
27 | /** The average amount of packets in the jitter buffer. */
28 | private float mAverageAvailable;
29 |
30 | public AudioUser(int session) {
31 | mSession = session;
32 | mAverageAvailable = 0.f;
33 | }
34 |
35 | public int getSession() {
36 | return mSession;
37 | }
38 |
39 | /**
40 | * Use the given packet data to update the average available packets.
41 | * If the number of packets present is greater than the accumulated average, update our average
42 | * to it- otherwise, decay our average by a factor of {@link #AVERAGE_DECAY}.
43 | * @param numPackets The number of packets present in this cycle of the jitter buffer.
44 | */
45 | public void updateAveragePackets(int numPackets) {
46 | mAverageAvailable = Math.max(numPackets, mAverageAvailable * AVERAGE_DECAY);
47 | }
48 |
49 | public int getAveragePackets() {
50 | return (int) Math.ceil(mAverageAvailable);
51 | }
52 | }
53 |
--------------------------------------------------------------------------------
/src/main/java/com/morlunk/jumble/util/IJumbleObserver.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2015 Andrew Comminos
3 | *
4 | * This program is free software: you can redistribute it and/or modify
5 | * it under the terms of the GNU General Public License as published by
6 | * the Free Software Foundation, either version 3 of the License, or
7 | * (at your option) any later version.
8 | *
9 | * This program is distributed in the hope that it will be useful,
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | * GNU General Public License for more details.
13 | *
14 | * You should have received a copy of the GNU General Public License
15 | * along with this program. If not, see .
16 | */
17 |
18 | package com.morlunk.jumble.util;
19 |
20 | import com.morlunk.jumble.model.IChannel;
21 | import com.morlunk.jumble.model.IMessage;
22 | import com.morlunk.jumble.model.IUser;
23 |
24 | import java.security.cert.X509Certificate;
25 |
26 | /**
27 | * Created by andrew on 18/10/15.
28 | */
29 | public interface IJumbleObserver {
30 | void onConnected();
31 |
32 | void onConnecting();
33 |
34 | void onDisconnected(JumbleException e);
35 |
36 | void onTLSHandshakeFailed(X509Certificate[] chain);
37 |
38 | void onChannelAdded(IChannel channel);
39 |
40 | void onChannelStateUpdated(IChannel channel);
41 |
42 | void onChannelRemoved(IChannel channel);
43 |
44 | void onChannelPermissionsUpdated(IChannel channel);
45 |
46 | void onUserConnected(IUser user);
47 |
48 | void onUserStateUpdated(IUser user);
49 |
50 | void onUserTalkStateUpdated(IUser user);
51 |
52 | void onUserJoinedChannel(IUser user, IChannel newChannel, IChannel oldChannel);
53 |
54 | void onUserRemoved(IUser user, String reason);
55 |
56 | void onPermissionDenied(String reason);
57 |
58 | void onMessageLogged(IMessage message);
59 |
60 | void onVoiceTargetChanged(VoiceTargetMode mode);
61 |
62 | void onLogInfo(String message);
63 |
64 | void onLogWarning(String message);
65 |
66 | void onLogError(String message);
67 | }
68 |
--------------------------------------------------------------------------------
/src/androidTest/java/com/morlunk/jumble/test/JumbleServiceTest.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2015 Andrew Comminos
3 | *
4 | * This program is free software: you can redistribute it and/or modify
5 | * it under the terms of the GNU General Public License as published by
6 | * the Free Software Foundation, either version 3 of the License, or
7 | * (at your option) any later version.
8 | *
9 | * This program is distributed in the hope that it will be useful,
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | * GNU General Public License for more details.
13 | *
14 | * You should have received a copy of the GNU General Public License
15 | * along with this program. If not, see .
16 | */
17 |
18 | package com.morlunk.jumble.test;
19 |
20 | import android.content.Intent;
21 | import android.os.RemoteException;
22 | import android.test.ServiceTestCase;
23 |
24 | import com.morlunk.jumble.IJumbleService;
25 | import com.morlunk.jumble.JumbleService;
26 | import com.morlunk.jumble.model.Server;
27 |
28 | /**
29 | * Tests to ensure the integrity of {@link JumbleService}'s state.
30 | * Created by andrew on 02/02/15.
31 | */
32 | public class JumbleServiceTest extends ServiceTestCase {
33 | private static final Server DUMMY_SERVER = new Server(-1, "dummy","example.com", 64738,
34 | "dummy_user", "dummy_pass");
35 |
36 | public JumbleServiceTest() {
37 | super(JumbleService.class);
38 | }
39 |
40 | /**
41 | * Tests the state of a JumbleService prior to connection.
42 | */
43 | public void testPreconnection() throws RemoteException {
44 | Intent intent = new Intent(getContext(), JumbleService.class);
45 | intent.putExtra(JumbleService.EXTRAS_SERVER, DUMMY_SERVER);
46 | startService(intent);
47 | IJumbleService service = getService();
48 | assertFalse(service.isReconnecting());
49 | assertNull(service.getConnectionError());
50 | assertEquals(JumbleService.ConnectionState.DISCONNECTED, service.getConnectionState());
51 | assertEquals(DUMMY_SERVER, service.getTargetServer());
52 | }
53 |
54 | }
55 |
--------------------------------------------------------------------------------
/src/main/java/com/morlunk/jumble/model/WhisperTargetChannel.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2016 Andrew Comminos
3 | *
4 | * This program is free software: you can redistribute it and/or modify
5 | * it under the terms of the GNU General Public License as published by
6 | * the Free Software Foundation, either version 3 of the License, or
7 | * (at your option) any later version.
8 | *
9 | * This program is distributed in the hope that it will be useful,
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | * GNU General Public License for more details.
13 | *
14 | * You should have received a copy of the GNU General Public License
15 | * along with this program. If not, see .
16 | */
17 |
18 | package com.morlunk.jumble.model;
19 |
20 | import android.os.Parcel;
21 | import android.os.Parcelable;
22 |
23 | import com.morlunk.jumble.protobuf.Mumble;
24 |
25 | import java.util.List;
26 |
27 | /**
28 | * An abstraction around a channel whisper target.
29 | * Created by andrew on 28/04/16.
30 | */
31 | public class WhisperTargetChannel implements WhisperTarget {
32 | private final IChannel mChannel;
33 | private final boolean mIncludeLinked;
34 | private final boolean mIncludeSubchannels;
35 | private final String mGroupRestriction;
36 |
37 | public WhisperTargetChannel(final IChannel channel, boolean includeLinked,
38 | boolean includeSubchannels, String groupRestriction) {
39 | mChannel = channel;
40 | mIncludeLinked = includeLinked;
41 | mIncludeSubchannels = includeSubchannels;
42 | mGroupRestriction = groupRestriction;
43 | }
44 |
45 | @Override
46 | public Mumble.VoiceTarget.Target createTarget() {
47 | Mumble.VoiceTarget.Target.Builder vtb = Mumble.VoiceTarget.Target.newBuilder();
48 | vtb.setLinks(mIncludeLinked);
49 | vtb.setChildren(mIncludeSubchannels);
50 | if (mGroupRestriction != null)
51 | vtb.setGroup(mGroupRestriction);
52 | vtb.setChannelId(mChannel.getId());
53 | return vtb.build();
54 | }
55 |
56 | @Override
57 | public String getName() {
58 | return mChannel.getName();
59 | }
60 | }
61 |
--------------------------------------------------------------------------------
/src/androidTest/java/com/morlunk/jumble/test/MixerTest.java:
--------------------------------------------------------------------------------
1 | package com.morlunk.jumble.test;
2 |
3 | import com.morlunk.jumble.audio.BasicClippingShortMixer;
4 | import com.morlunk.jumble.audio.IAudioMixer;
5 | import com.morlunk.jumble.audio.IAudioMixerSource;
6 |
7 | import junit.framework.TestCase;
8 |
9 | import java.util.ArrayList;
10 | import java.util.Collection;
11 | import java.util.List;
12 |
13 | /**
14 | * Created by andrew on 16/07/15.
15 | */
16 | public class MixerTest extends TestCase {
17 | /**
18 | * Tests that mixing order should not affect the output.
19 | */
20 | public void testMixerCommutativity(IAudioMixer mixer) {
21 | BasicSource pcmA = new BasicSource<>(new float[] { 0.2f, 0.5f, 0.7f }, 3);
22 | BasicSource pcmB = new BasicSource<>(new float[] { 0.3f, 0.5f, 0.5f }, 3);
23 | BasicSource pcmC = new BasicSource<>(new float[] { 0.0f, 0.0f, -0.5f }, 3);
24 | final short[] outputABC = new short[3];
25 | final short[] outputCBA = new short[3];
26 |
27 | List> sourcesABC = new ArrayList<>();
28 | sourcesABC.add(pcmA);
29 | sourcesABC.add(pcmB);
30 | sourcesABC.add(pcmC);
31 | List> sourcesCBA = new ArrayList<>();
32 | sourcesCBA.add(pcmC);
33 | sourcesCBA.add(pcmB);
34 | sourcesCBA.add(pcmA);
35 |
36 | mixer.mix(sourcesABC, outputABC, 0, 3);
37 | mixer.mix(sourcesCBA, outputCBA, 0, 3);
38 |
39 | for (int i = 0; i < 3; i++) {
40 | assertEquals("Mixing should be commutative.", outputABC[i], outputCBA[i]);
41 | }
42 | }
43 |
44 | public void testBasicClippingShortMixer() {
45 | testMixerCommutativity(new BasicClippingShortMixer());
46 | }
47 |
48 | private static class BasicSource implements IAudioMixerSource {
49 | private T mSamples;
50 | private int mLength;
51 |
52 | public BasicSource(T samples, int length) {
53 | mSamples = samples;
54 | mLength = length;
55 | }
56 |
57 | @Override
58 | public T getSamples() {
59 | return mSamples;
60 | }
61 |
62 | @Override
63 | public int getNumSamples() {
64 | return mLength;
65 | }
66 | }
67 | }
68 |
--------------------------------------------------------------------------------
/src/main/java/com/morlunk/jumble/util/MumbleURLParser.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2014 Andrew Comminos
3 | *
4 | * This program is free software: you can redistribute it and/or modify
5 | * it under the terms of the GNU General Public License as published by
6 | * the Free Software Foundation, either version 3 of the License, or
7 | * (at your option) any later version.
8 | *
9 | * This program is distributed in the hope that it will be useful,
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | * GNU General Public License for more details.
13 | *
14 | * You should have received a copy of the GNU General Public License
15 | * along with this program. If not, see .
16 | */
17 |
18 | package com.morlunk.jumble.util;
19 |
20 | import com.morlunk.jumble.Constants;
21 | import com.morlunk.jumble.model.Server;
22 |
23 | import java.net.MalformedURLException;
24 | import java.util.regex.Matcher;
25 | import java.util.regex.Pattern;
26 |
27 | /**
28 | * An implementation of the Mumble URL scheme.
29 | * @see http://mumble.sourceforge.net/Mumble_URL
30 | * Created by andrew on 03/03/14.
31 | */
32 | public class MumbleURLParser {
33 |
34 | private static final Pattern URL_PATTERN = Pattern.compile("mumble://(([^:]+)?(:(.+?))?@)?(.+?)(:([0-9]+?))?/");
35 |
36 | /**
37 | * Parses the passed Mumble URL into a Server object.
38 | * @param url A URL with the Mumble scheme.
39 | * @return A server with the data specified in the Mumble URL.
40 | * @throws MalformedURLException if the URL cannot be parsed.
41 | */
42 | public static Server parseURL(String url) throws MalformedURLException {
43 | Matcher matcher = URL_PATTERN.matcher(url);
44 | if(matcher.find()) {
45 | String username = matcher.group(2);
46 | String password = matcher.group(4);
47 | String host = matcher.group(5);
48 | String portString = matcher.group(7);
49 | int port = portString == null ? Constants.DEFAULT_PORT : Integer.parseInt(portString);
50 | return new Server(-1, null, host, port, username, password);
51 | } else {
52 | throw new MalformedURLException();
53 | }
54 | }
55 | }
56 |
--------------------------------------------------------------------------------
/src/androidTest/java/com/morlunk/jumble/test/ModelTest.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2015 Andrew Comminos
3 | *
4 | * This program is free software: you can redistribute it and/or modify
5 | * it under the terms of the GNU General Public License as published by
6 | * the Free Software Foundation, either version 3 of the License, or
7 | * (at your option) any later version.
8 | *
9 | * This program is distributed in the hope that it will be useful,
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | * GNU General Public License for more details.
13 | *
14 | * You should have received a copy of the GNU General Public License
15 | * along with this program. If not, see .
16 | */
17 |
18 | package com.morlunk.jumble.test;
19 |
20 | import com.morlunk.jumble.model.Channel;
21 | import com.morlunk.jumble.model.User;
22 |
23 | import junit.framework.TestCase;
24 |
25 | /**
26 | * Tests the Channel-User tree model.
27 | * Created by andrew on 24/10/15.
28 | */
29 | public class ModelTest extends TestCase {
30 |
31 | public void testUserAddRemove() {
32 | Channel root = new Channel(0, false);
33 | User user = new User(0, "Test user");
34 | user.setChannel(root);
35 | assertEquals("Channel user list count is sane", 1, root.getUsers().size());
36 | assertEquals("Channel subchannel user count is sane", 1, root.getSubchannelUserCount());
37 |
38 | Channel sub = new Channel(1, false);
39 | root.addSubchannel(sub);
40 | User subuser = new User(1, "Test user in subchannel");
41 | subuser.setChannel(sub);
42 | assertEquals("Adding a user to a subchannel doesn't affect the number of direct children of the root", 1, root.getUsers().size());
43 | assertEquals("Adding a user to a subchannel updates the recursive user count", 2, root.getSubchannelUserCount());
44 |
45 | user.setChannel(sub);
46 | assertEquals("Moving a user to a subchannel updates the number of children of the root", 0, root.getUsers().size());
47 | assertEquals("Moving a user to a subchannel does not change the recursive user count of the root", 2, root.getSubchannelUserCount());
48 | assertEquals("Subchannel user count is sane", 2, sub.getUsers().size());
49 | }
50 | }
51 |
--------------------------------------------------------------------------------
/src/main/java/com/morlunk/jumble/audio/IDecoder.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2014 Andrew Comminos
3 | *
4 | * This program is free software: you can redistribute it and/or modify
5 | * it under the terms of the GNU General Public License as published by
6 | * the Free Software Foundation, either version 3 of the License, or
7 | * (at your option) any later version.
8 | *
9 | * This program is distributed in the hope that it will be useful,
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | * GNU General Public License for more details.
13 | *
14 | * You should have received a copy of the GNU General Public License
15 | * along with this program. If not, see .
16 | */
17 |
18 | package com.morlunk.jumble.audio;
19 |
20 | import com.morlunk.jumble.exception.NativeAudioException;
21 |
22 | import java.nio.ByteBuffer;
23 |
24 | /**
25 | * Created by andrew on 07/03/14.
26 | */
27 | public interface IDecoder {
28 | /**
29 | * Decodes the encoded data provided into float PCM data.
30 | * @param input A byte array of encoded data of size inputSize.
31 | * @param inputSize The size of the encoded data.
32 | * @param output An initialized output array at least frameSize for float PCM data.
33 | * @param frameSize The maximum frame size possible.
34 | * @return The number of decoded samples.
35 | * @throws com.morlunk.jumble.exception.NativeAudioException if encoding failed.
36 | */
37 | public int decodeFloat(ByteBuffer input, int inputSize, float[] output, int frameSize) throws NativeAudioException;
38 |
39 | /**
40 | * Decodes the encoded data provided into short PCM data.
41 | * @param input A byte array of encoded data of size inputSize.
42 | * @param inputSize The size of the encoded data.
43 | * @param output An initialized output array at least frameSize for short PCM data.
44 | * @param frameSize The maximum frame size possible.
45 | * @return The number of decoded samples.
46 | * @throws NativeAudioException if encoding failed.
47 | */
48 | public int decodeShort(ByteBuffer input, int inputSize, short[] output, int frameSize) throws NativeAudioException;
49 |
50 | /**
51 | * Deallocates native resources. The decoder must no longer be called after this.
52 | */
53 | public void destroy();
54 | }
55 |
--------------------------------------------------------------------------------
/src/main/java/com/morlunk/jumble/audio/inputmode/ActivityInputMode.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2016 Andrew Comminos
3 | *
4 | * This program is free software: you can redistribute it and/or modify
5 | * it under the terms of the GNU General Public License as published by
6 | * the Free Software Foundation, either version 3 of the License, or
7 | * (at your option) any later version.
8 | *
9 | * This program is distributed in the hope that it will be useful,
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | * GNU General Public License for more details.
13 | *
14 | * You should have received a copy of the GNU General Public License
15 | * along with this program. If not, see .
16 | */
17 |
18 | package com.morlunk.jumble.audio.inputmode;
19 |
20 | /**
21 | * An input mode that sends audio if the amplitude exceeds a certain threshold.
22 | * Created by andrew on 13/02/16.
23 | */
24 | public class ActivityInputMode implements IInputMode {
25 | // Continue speech for 250ms to prevent dropping.
26 | private static final int SPEECH_DELAY = (int) (0.25 * Math.pow(10, 9));
27 |
28 | private float mVADThreshold;
29 | private long mVADLastDetected;
30 |
31 | public ActivityInputMode(float detectionThreshold) {
32 | mVADThreshold = detectionThreshold;
33 | }
34 |
35 | @Override
36 | public boolean shouldTransmit(short[] pcm, int length) {
37 | // Use a logarithmic energy-based scale for VAD.
38 | float sum = 1.0f;
39 | for (int i = 0; i < length; i++) {
40 | sum += pcm[i] * pcm[i];
41 | }
42 | float micLevel = (float) Math.sqrt(sum / (float)length);
43 | float peakSignal = (float) (20.0f * Math.log10(micLevel / 32768.0f)) / 96.0f;
44 | boolean talking = (peakSignal + 1) >= mVADThreshold;
45 |
46 | // Record the last time where VAD was detected in order to prevent speech dropping.
47 | if(talking) {
48 | mVADLastDetected = System.nanoTime();
49 | }
50 |
51 | talking |= (System.nanoTime() - mVADLastDetected) < SPEECH_DELAY;
52 |
53 | return talking;
54 | }
55 |
56 | @Override
57 | public void waitForInput() {
58 |
59 | }
60 |
61 | public void setThreshold(float threshold) {
62 | mVADThreshold = threshold;
63 | }
64 | }
65 |
--------------------------------------------------------------------------------
/src/main/java/com/morlunk/jumble/audio/encoder/IEncoder.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2014 Andrew Comminos
3 | *
4 | * This program is free software: you can redistribute it and/or modify
5 | * it under the terms of the GNU General Public License as published by
6 | * the Free Software Foundation, either version 3 of the License, or
7 | * (at your option) any later version.
8 | *
9 | * This program is distributed in the hope that it will be useful,
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | * GNU General Public License for more details.
13 | *
14 | * You should have received a copy of the GNU General Public License
15 | * along with this program. If not, see .
16 | */
17 |
18 | package com.morlunk.jumble.audio.encoder;
19 |
20 | import com.morlunk.jumble.exception.NativeAudioException;
21 | import com.morlunk.jumble.net.PacketBuffer;
22 |
23 | import java.nio.BufferUnderflowException;
24 |
25 | /**
26 | * IEncoder provides an interface for native audio encoders to buffer and serve encoded audio
27 | * data.
28 | * Created by andrew on 07/03/14.
29 | */
30 | public interface IEncoder {
31 | /**
32 | * Encodes the provided input and returns the number of bytes encoded.
33 | * @param input The short PCM data to encode.
34 | * @param inputSize The number of samples to encode.
35 | * @return The number of bytes encoded.
36 | * @throws NativeAudioException if there was an error encoding.
37 | */
38 | public int encode(short[] input, int inputSize) throws NativeAudioException;
39 |
40 | /**
41 | * @return the number of audio frames buffered.
42 | */
43 | public int getBufferedFrames();
44 |
45 | /**
46 | * @return true if enough buffered audio has been encoded to send to the server.
47 | */
48 | public boolean isReady();
49 |
50 | /**
51 | * Writes the currently encoded audio data into the provided {@link PacketBuffer}.
52 | * Use {@link #isReady()} to determine whether or not this should be called.
53 | * @throws BufferUnderflowException if insufficient audio data has been buffered.
54 | */
55 | public void getEncodedData(PacketBuffer packetBuffer) throws BufferUnderflowException;
56 |
57 | /**
58 | * Informs the encoder that there are no more audio packets to be queued. Often, this will
59 | * trigger an encode operation, changing the result of {@link #isReady()}.
60 | */
61 | public void terminate() throws NativeAudioException;
62 |
63 | /**
64 | * Destroys the encoder, cleaning up natively allocated resources.
65 | */
66 | public void destroy();
67 | }
68 |
--------------------------------------------------------------------------------
/gradlew.bat:
--------------------------------------------------------------------------------
1 | @if "%DEBUG%" == "" @echo off
2 | @rem ##########################################################################
3 | @rem
4 | @rem Gradle startup script for Windows
5 | @rem
6 | @rem ##########################################################################
7 |
8 | @rem Set local scope for the variables with windows NT shell
9 | if "%OS%"=="Windows_NT" setlocal
10 |
11 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
12 | set DEFAULT_JVM_OPTS=
13 |
14 | set DIRNAME=%~dp0
15 | if "%DIRNAME%" == "" set DIRNAME=.
16 | set APP_BASE_NAME=%~n0
17 | set APP_HOME=%DIRNAME%
18 |
19 | @rem Find java.exe
20 | if defined JAVA_HOME goto findJavaFromJavaHome
21 |
22 | set JAVA_EXE=java.exe
23 | %JAVA_EXE% -version >NUL 2>&1
24 | if "%ERRORLEVEL%" == "0" goto init
25 |
26 | echo.
27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
28 | echo.
29 | echo Please set the JAVA_HOME variable in your environment to match the
30 | echo location of your Java installation.
31 |
32 | goto fail
33 |
34 | :findJavaFromJavaHome
35 | set JAVA_HOME=%JAVA_HOME:"=%
36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe
37 |
38 | if exist "%JAVA_EXE%" goto init
39 |
40 | echo.
41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
42 | echo.
43 | echo Please set the JAVA_HOME variable in your environment to match the
44 | echo location of your Java installation.
45 |
46 | goto fail
47 |
48 | :init
49 | @rem Get command-line arguments, handling Windowz variants
50 |
51 | if not "%OS%" == "Windows_NT" goto win9xME_args
52 | if "%@eval[2+2]" == "4" goto 4NT_args
53 |
54 | :win9xME_args
55 | @rem Slurp the command line arguments.
56 | set CMD_LINE_ARGS=
57 | set _SKIP=2
58 |
59 | :win9xME_args_slurp
60 | if "x%~1" == "x" goto execute
61 |
62 | set CMD_LINE_ARGS=%*
63 | goto execute
64 |
65 | :4NT_args
66 | @rem Get arguments from the 4NT Shell from JP Software
67 | set CMD_LINE_ARGS=%$
68 |
69 | :execute
70 | @rem Setup the command line
71 |
72 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
73 |
74 | @rem Execute Gradle
75 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
76 |
77 | :end
78 | @rem End local scope for the variables with windows NT shell
79 | if "%ERRORLEVEL%"=="0" goto mainEnd
80 |
81 | :fail
82 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
83 | rem the _cmd.exe /c_ return code!
84 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
85 | exit /b 1
86 |
87 | :mainEnd
88 | if "%OS%"=="Windows_NT" endlocal
89 |
90 | :omega
91 |
--------------------------------------------------------------------------------
/src/main/java/com/morlunk/jumble/audio/inputmode/ToggleInputMode.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2016 Andrew Comminos
3 | *
4 | * This program is free software: you can redistribute it and/or modify
5 | * it under the terms of the GNU General Public License as published by
6 | * the Free Software Foundation, either version 3 of the License, or
7 | * (at your option) any later version.
8 | *
9 | * This program is distributed in the hope that it will be useful,
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | * GNU General Public License for more details.
13 | *
14 | * You should have received a copy of the GNU General Public License
15 | * along with this program. If not, see .
16 | */
17 |
18 | package com.morlunk.jumble.audio.inputmode;
19 |
20 | import android.util.Log;
21 |
22 | import com.morlunk.jumble.Constants;
23 |
24 | import java.util.concurrent.locks.Condition;
25 | import java.util.concurrent.locks.Lock;
26 | import java.util.concurrent.locks.ReentrantLock;
27 |
28 | /**
29 | * An input mode that depends on a toggle, such as push to talk.
30 | * Created by andrew on 13/02/16.
31 | */
32 | public class ToggleInputMode implements IInputMode {
33 | private boolean mInputOn;
34 | private final Lock mToggleLock;
35 | private final Condition mToggleCondition;
36 |
37 | public ToggleInputMode() {
38 | mInputOn = false;
39 | mToggleLock = new ReentrantLock();
40 | mToggleCondition = mToggleLock.newCondition();
41 | }
42 |
43 | public void toggleTalkingOn() {
44 | setTalkingOn(!mInputOn);
45 | }
46 |
47 | public boolean isTalkingOn() {
48 | return mInputOn;
49 | }
50 |
51 | public void setTalkingOn(boolean talking) {
52 | mToggleLock.lock();
53 | mInputOn = talking;
54 | mToggleCondition.signalAll();
55 | mToggleLock.unlock();
56 | }
57 |
58 | @Override
59 | public boolean shouldTransmit(short[] pcm, int length) {
60 | return mInputOn;
61 | }
62 |
63 | @Override
64 | public void waitForInput() {
65 | mToggleLock.lock();
66 | if (!mInputOn) {
67 | Log.v(Constants.TAG, "PTT: Suspending audio input.");
68 | long startTime = System.currentTimeMillis();
69 | try {
70 | mToggleCondition.await();
71 | } catch (InterruptedException e) {
72 | Log.w(Constants.TAG, "Blocking for PTT interrupted, likely due to input thread shutdown.");
73 | }
74 | Log.v(Constants.TAG, "PTT: Suspended audio input for " + (System.currentTimeMillis() - startTime) + "ms.");
75 | }
76 | mToggleLock.unlock();
77 | }
78 | }
79 |
--------------------------------------------------------------------------------
/src/main/java/com/morlunk/jumble/model/WhisperTargetList.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2016 Andrew Comminos
3 | *
4 | * This program is free software: you can redistribute it and/or modify
5 | * it under the terms of the GNU General Public License as published by
6 | * the Free Software Foundation, either version 3 of the License, or
7 | * (at your option) any later version.
8 | *
9 | * This program is distributed in the hope that it will be useful,
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | * GNU General Public License for more details.
13 | *
14 | * You should have received a copy of the GNU General Public License
15 | * along with this program. If not, see .
16 | */
17 |
18 | package com.morlunk.jumble.model;
19 |
20 | import java.util.List;
21 |
22 | /**
23 | * A simple implementation of a fixed-size whisper target list using a bit vector.
24 | * Created by andrew on 29/04/16.
25 | */
26 | public class WhisperTargetList {
27 | public static final byte TARGET_MIN = 1;
28 | public static final byte TARGET_MAX = 30;
29 |
30 | private final WhisperTarget[] mActiveTargets;
31 | // Mumble stores voice targets using a 5-bit identifier.
32 | // Use a bit vector to represent this 32-element range.
33 | private int mTakenIds;
34 |
35 | public WhisperTargetList() {
36 | mActiveTargets = new WhisperTarget[TARGET_MAX - TARGET_MIN + 1];
37 | clear();
38 | }
39 |
40 | /**
41 | * Assigns the target to a slot.
42 | * @param target The whisper target to assign.
43 | * @return The slot number in range [1, 30].
44 | */
45 | public byte append(WhisperTarget target) {
46 | byte freeId = -1;
47 | for (byte i = TARGET_MIN; i < TARGET_MAX; i++) {
48 | if ((mTakenIds & (1 << i)) == 0) {
49 | freeId = i;
50 | break;
51 | }
52 | }
53 | if (freeId != -1) {
54 | mActiveTargets[freeId - TARGET_MIN] = target;
55 | }
56 |
57 | return freeId;
58 | }
59 |
60 | public WhisperTarget get(byte id) {
61 | if ((mTakenIds & (1 << id)) > 0)
62 | return null;
63 | return mActiveTargets[id - TARGET_MIN];
64 | }
65 |
66 | public void free(byte slot) {
67 | if (slot < TARGET_MIN || slot > TARGET_MAX)
68 | throw new IllegalArgumentException();
69 |
70 | mTakenIds &= ~(1 << slot);
71 | }
72 |
73 | public int spaceRemaining() {
74 | int counter = 0;
75 | for (byte i = TARGET_MIN; i < TARGET_MAX; i++) {
76 | if ((mTakenIds & (1 << i)) == 0) {
77 | counter++;
78 | }
79 | }
80 | return counter;
81 | }
82 |
83 | public void clear() {
84 | // Slots 0 and 31 are non-whisper targets.
85 | mTakenIds = 1 | (1 << 31);
86 | }
87 | }
88 |
--------------------------------------------------------------------------------
/src/main/java/com/morlunk/jumble/net/JumbleNetworkThread.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2014 Andrew Comminos
3 | *
4 | * This program is free software: you can redistribute it and/or modify
5 | * it under the terms of the GNU General Public License as published by
6 | * the Free Software Foundation, either version 3 of the License, or
7 | * (at your option) any later version.
8 | *
9 | * This program is distributed in the hope that it will be useful,
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | * GNU General Public License for more details.
13 | *
14 | * You should have received a copy of the GNU General Public License
15 | * along with this program. If not, see .
16 | */
17 |
18 | package com.morlunk.jumble.net;
19 |
20 | import android.os.Handler;
21 | import android.os.Looper;
22 |
23 | import java.util.concurrent.ExecutorService;
24 | import java.util.concurrent.Executors;
25 |
26 | /**
27 | * Base class for TCP/UDP protocol implementations.
28 | * Provides a common threading model (single threaded queue for write)
29 | * Created by andrew on 25/03/14.
30 | * @deprecated This shouldn't be needed. Redundant inheritance with limited shared code.
31 | */
32 | public abstract class JumbleNetworkThread implements Runnable {
33 |
34 | private ExecutorService mExecutor;
35 | private ExecutorService mSendExecutor;
36 | private ExecutorService mReceiveExecutor;
37 | private Handler mMainHandler;
38 | private boolean mInitialized;
39 |
40 | public JumbleNetworkThread() {
41 | mMainHandler = new Handler(Looper.getMainLooper());
42 | }
43 |
44 | protected void startThreads() {
45 | if (mInitialized) {
46 | throw new IllegalArgumentException("Threads already initialized.");
47 | }
48 | mExecutor = Executors.newSingleThreadExecutor();
49 | mSendExecutor = Executors.newSingleThreadExecutor();
50 | mReceiveExecutor = Executors.newSingleThreadExecutor();
51 | mExecutor.execute(this);
52 | mInitialized = true;
53 | }
54 |
55 | protected void stopThreads() {
56 | if (!mInitialized) {
57 | throw new IllegalArgumentException("Threads already shutdown.");
58 | }
59 | mSendExecutor.shutdown();
60 | mReceiveExecutor.shutdownNow();
61 | mExecutor.shutdownNow();
62 | mSendExecutor = null;
63 | mReceiveExecutor = null;
64 | mExecutor = null;
65 | mInitialized = false;
66 | }
67 |
68 | protected void executeOnSendThread(Runnable r) {
69 | mSendExecutor.execute(r);
70 | }
71 |
72 | protected void executeOnReceiveThread(Runnable r) {
73 | mSendExecutor.execute(r);
74 | }
75 |
76 | protected void executeOnMainThread(Runnable r) {
77 | mMainHandler.post(r);
78 | }
79 |
80 | protected Handler getMainHandler() {
81 | return mMainHandler;
82 | }
83 | }
84 |
--------------------------------------------------------------------------------
/src/main/java/com/morlunk/jumble/audio/BluetoothScoReceiver.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2015 Andrew Comminos
3 | *
4 | * This program is free software: you can redistribute it and/or modify
5 | * it under the terms of the GNU General Public License as published by
6 | * the Free Software Foundation, either version 3 of the License, or
7 | * (at your option) any later version.
8 | *
9 | * This program is distributed in the hope that it will be useful,
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | * GNU General Public License for more details.
13 | *
14 | * You should have received a copy of the GNU General Public License
15 | * along with this program. If not, see .
16 | */
17 |
18 | package com.morlunk.jumble.audio;
19 |
20 | import android.content.BroadcastReceiver;
21 | import android.content.Context;
22 | import android.content.Intent;
23 | import android.media.AudioManager;
24 | import android.widget.Toast;
25 |
26 | import com.morlunk.jumble.R;
27 | import com.morlunk.jumble.exception.AudioInitializationException;
28 |
29 | /**
30 | * Manages the state of Bluetooth SCO.
31 | * Created by andrew on 25/09/15.
32 | */
33 | public class BluetoothScoReceiver extends BroadcastReceiver {
34 | private final Listener mListener;
35 | private final AudioManager mAudioManager;
36 | private boolean mBluetoothScoOn;
37 |
38 | public BluetoothScoReceiver(Context context, Listener listener) {
39 | mListener = listener;
40 | mAudioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
41 | }
42 |
43 | @Override
44 | public void onReceive(Context context, Intent intent) {
45 | AudioManager am = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
46 | int audioState = intent.getIntExtra(AudioManager.EXTRA_SCO_AUDIO_STATE, AudioManager.SCO_AUDIO_STATE_ERROR);
47 | switch (audioState) {
48 | case AudioManager.SCO_AUDIO_STATE_CONNECTED:
49 | mBluetoothScoOn = true;
50 | mListener.onBluetoothScoConnected();
51 | break;
52 | case AudioManager.SCO_AUDIO_STATE_DISCONNECTED:
53 | case AudioManager.SCO_AUDIO_STATE_ERROR:
54 | am.stopBluetoothSco();
55 | mBluetoothScoOn = false;
56 | mListener.onBluetoothScoDisconnected();
57 | break;
58 | }
59 | }
60 |
61 | public void startBluetoothSco() {
62 | mAudioManager.startBluetoothSco();
63 | }
64 |
65 | public void stopBluetoothSco() {
66 | mAudioManager.stopBluetoothSco();
67 | mBluetoothScoOn = false;
68 | }
69 |
70 | public boolean isBluetoothScoOn() {
71 | return mBluetoothScoOn;
72 | }
73 |
74 | public interface Listener {
75 | void onBluetoothScoConnected();
76 | void onBluetoothScoDisconnected();
77 | }
78 | }
79 |
--------------------------------------------------------------------------------
/src/main/java/com/morlunk/jumble/util/JumbleObserver.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2014 Andrew Comminos
3 | *
4 | * This program is free software: you can redistribute it and/or modify
5 | * it under the terms of the GNU General Public License as published by
6 | * the Free Software Foundation, either version 3 of the License, or
7 | * (at your option) any later version.
8 | *
9 | * This program is distributed in the hope that it will be useful,
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | * GNU General Public License for more details.
13 | *
14 | * You should have received a copy of the GNU General Public License
15 | * along with this program. If not, see .
16 | */
17 |
18 | package com.morlunk.jumble.util;
19 |
20 | import com.morlunk.jumble.model.IChannel;
21 | import com.morlunk.jumble.model.IMessage;
22 | import com.morlunk.jumble.model.IUser;
23 |
24 | import java.security.cert.X509Certificate;
25 |
26 | /**
27 | * Stub class for Jumble service observation.
28 | * Created by andrew on 31/07/13.
29 | */
30 | public class JumbleObserver implements IJumbleObserver {
31 | @Override
32 | public void onConnected() {
33 |
34 | }
35 |
36 | @Override
37 | public void onConnecting() {
38 |
39 | }
40 |
41 | @Override
42 | public void onDisconnected(JumbleException e) {
43 |
44 | }
45 |
46 | @Override
47 | public void onTLSHandshakeFailed(X509Certificate[] chain) {
48 |
49 | }
50 |
51 | @Override
52 | public void onChannelAdded(IChannel channel) {
53 |
54 | }
55 |
56 | @Override
57 | public void onChannelStateUpdated(IChannel channel) {
58 |
59 | }
60 |
61 | @Override
62 | public void onChannelRemoved(IChannel channel) {
63 |
64 | }
65 |
66 | @Override
67 | public void onChannelPermissionsUpdated(IChannel channel) {
68 |
69 | }
70 |
71 | @Override
72 | public void onUserConnected(IUser user) {
73 |
74 | }
75 |
76 | @Override
77 | public void onUserStateUpdated(IUser user) {
78 |
79 | }
80 |
81 | @Override
82 | public void onUserTalkStateUpdated(IUser user) {
83 |
84 | }
85 |
86 | @Override
87 | public void onUserJoinedChannel(IUser user, IChannel newChannel, IChannel oldChannel) {
88 |
89 | }
90 |
91 | @Override
92 | public void onUserRemoved(IUser user, String reason) {
93 |
94 | }
95 |
96 | @Override
97 | public void onPermissionDenied(String reason) {
98 |
99 | }
100 |
101 | @Override
102 | public void onMessageLogged(IMessage message) {
103 |
104 | }
105 |
106 | @Override
107 | public void onVoiceTargetChanged(VoiceTargetMode mode) {
108 |
109 | }
110 |
111 | @Override
112 | public void onLogInfo(String message) {
113 |
114 | }
115 |
116 | @Override
117 | public void onLogWarning(String message) {
118 |
119 | }
120 |
121 | @Override
122 | public void onLogError(String message) {
123 |
124 | }
125 | }
126 |
--------------------------------------------------------------------------------
/src/main/java/com/morlunk/jumble/audio/encoder/ResamplingEncoder.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2014 Andrew Comminos
3 | *
4 | * This program is free software: you can redistribute it and/or modify
5 | * it under the terms of the GNU General Public License as published by
6 | * the Free Software Foundation, either version 3 of the License, or
7 | * (at your option) any later version.
8 | *
9 | * This program is distributed in the hope that it will be useful,
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | * GNU General Public License for more details.
13 | *
14 | * You should have received a copy of the GNU General Public License
15 | * along with this program. If not, see .
16 | */
17 |
18 | package com.morlunk.jumble.audio.encoder;
19 |
20 | import com.morlunk.jumble.audio.javacpp.Speex;
21 | import com.morlunk.jumble.exception.NativeAudioException;
22 | import com.morlunk.jumble.net.PacketBuffer;
23 |
24 | import java.nio.BufferUnderflowException;
25 |
26 | /**
27 | * Wraps around another encoder, resampling up/down all input using the Speex resampler.
28 | * Created by andrew on 16/04/14.
29 | */
30 | public class ResamplingEncoder implements IEncoder {
31 | private static final int SPEEX_RESAMPLE_QUALITY = 3;
32 |
33 | private IEncoder mEncoder;
34 | private Speex.SpeexResampler mResampler;
35 | private final int mInputSampleRate;
36 | private final int mTargetSampleRate;
37 | private final int mTargetFrameSize;
38 | private final short[] mResampleBuffer;
39 |
40 | public ResamplingEncoder(IEncoder encoder, int channels, int inputSampleRate, int targetFrameSize, int targetSampleRate) {
41 | mEncoder = encoder;
42 | mInputSampleRate = inputSampleRate;
43 | mTargetSampleRate = targetSampleRate;
44 | mTargetFrameSize = targetFrameSize;
45 | mResampleBuffer = new short[mTargetFrameSize];
46 | mResampler = new Speex.SpeexResampler(channels, inputSampleRate, targetSampleRate, SPEEX_RESAMPLE_QUALITY);
47 | }
48 |
49 | @Override
50 | public int encode(short[] input, int inputSize) throws NativeAudioException {
51 | mResampler.resample(input, mResampleBuffer);
52 | return mEncoder.encode(mResampleBuffer, mTargetFrameSize);
53 | }
54 |
55 | @Override
56 | public int getBufferedFrames() {
57 | return mEncoder.getBufferedFrames();
58 | }
59 |
60 | @Override
61 | public boolean isReady() {
62 | return mEncoder.isReady();
63 | }
64 |
65 | @Override
66 | public void getEncodedData(PacketBuffer packetBuffer) throws BufferUnderflowException {
67 | mEncoder.getEncodedData(packetBuffer);
68 | }
69 |
70 | @Override
71 | public void terminate() throws NativeAudioException {
72 | mEncoder.terminate();
73 | }
74 |
75 | public void setEncoder(IEncoder encoder) {
76 | if(mEncoder != null) mEncoder.destroy();
77 | mEncoder = encoder;
78 | }
79 |
80 | @Override
81 | public void destroy() {
82 | mResampler.destroy();
83 | mEncoder.destroy();
84 | mResampler = null;
85 | mEncoder = null;
86 | }
87 | }
88 |
--------------------------------------------------------------------------------
/src/androidTest/java/com/morlunk/jumble/test/EncoderTest.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2014 Andrew Comminos
3 | *
4 | * This program is free software: you can redistribute it and/or modify
5 | * it under the terms of the GNU General Public License as published by
6 | * the Free Software Foundation, either version 3 of the License, or
7 | * (at your option) any later version.
8 | *
9 | * This program is distributed in the hope that it will be useful,
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | * GNU General Public License for more details.
13 | *
14 | * You should have received a copy of the GNU General Public License
15 | * along with this program. If not, see .
16 | */
17 |
18 | package com.morlunk.jumble.test;
19 |
20 | import android.test.AndroidTestCase;
21 |
22 | import com.googlecode.javacpp.Loader;
23 | import com.morlunk.jumble.audio.encoder.CELT7Encoder;
24 | import com.morlunk.jumble.audio.encoder.IEncoder;
25 | import com.morlunk.jumble.audio.encoder.OpusEncoder;
26 | import com.morlunk.jumble.audio.javacpp.Opus;
27 | import com.morlunk.jumble.exception.NativeAudioException;
28 | import com.morlunk.jumble.net.PacketBuffer;
29 |
30 | /**
31 | * This class tests the Opus and CELT encoders with blank PCM data.
32 | * The bitrate is set to 40000bps. TODO: add test for varying bitrates.
33 | * If any of these methods throw a NativeAudioException, then the test will fail.
34 | * Created by andrew on 13/10/13.
35 | */
36 | public class EncoderTest extends AndroidTestCase {
37 | private static final int MAX_BUFFER_SIZE = 960;
38 | private static final int SAMPLE_RATE = 48000;
39 | private static final int BITRATE = 40000;
40 | private static final int FRAME_SIZE = 480;
41 | private static final int FRAMES_PER_PACKET = 4;
42 |
43 | static {
44 | Loader.load(Opus.class);
45 | }
46 |
47 | public void testOpusEncode() throws NativeAudioException {
48 | IEncoder encoder = new OpusEncoder(SAMPLE_RATE, 1, FRAME_SIZE, FRAMES_PER_PACKET, BITRATE, MAX_BUFFER_SIZE);
49 | testEncoder(encoder);
50 | encoder.destroy();
51 | }
52 |
53 | public void testCELT7Encode() throws NativeAudioException {
54 | CELT7Encoder encoder = new CELT7Encoder(SAMPLE_RATE, FRAME_SIZE, 1, FRAMES_PER_PACKET,
55 | BITRATE, MAX_BUFFER_SIZE);
56 | testEncoder(encoder);
57 | encoder.destroy();
58 | }
59 |
60 | public void testEncoder(IEncoder encoder) throws NativeAudioException {
61 | assertFalse(encoder.isReady());
62 | assertEquals(0, encoder.getBufferedFrames());
63 |
64 | //
65 | final short[] dummyFrame = new short[FRAME_SIZE];
66 | for (int i = 0; i < FRAMES_PER_PACKET; i++) {
67 | assertFalse(encoder.isReady());
68 | encoder.encode(dummyFrame, FRAME_SIZE);
69 | }
70 | assertTrue(encoder.isReady());
71 | assertEquals(FRAMES_PER_PACKET, encoder.getBufferedFrames());
72 |
73 | // Flushing
74 | PacketBuffer buffer = PacketBuffer.allocate(MAX_BUFFER_SIZE);
75 | encoder.getEncodedData(buffer);
76 | assertFalse(encoder.isReady());
77 | assertEquals(0, encoder.getBufferedFrames());
78 |
79 | // Termination (for frames per packet > 1)
80 | encoder.encode(dummyFrame, FRAME_SIZE);
81 | assertFalse(encoder.isReady());
82 | encoder.terminate();
83 | assertTrue(encoder.isReady());
84 |
85 | }
86 | }
87 |
--------------------------------------------------------------------------------
/src/main/res/values-ja/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | サーバーの最大ネットワーク帯域幅は %1$d kbit/s のみです。オーディオ品質は %2$d kbit/s (%3$d ms) に自動調整されました
4 | %1$s は %2$s から %3$s で移動しました。
5 | ミュートおよび防音
6 | ミュートしました。
7 | ミュートを解除しました。
8 | ミュート解除および防音解除しました。
9 | %s がミュートおよび防音されました。
10 | %s がミュートされました。
11 | %s がミュート解除されました。
12 | %s がミュート解除および防音解除されました。
13 | あなたは %s によってミュートおよび防音されました。
14 | あなたは %s によってミュート解除および防音解除されました。
15 | あなたは %s によってミュートされました。
16 | あなたは %s によってミュート解除されました。
17 | あなたは %s によって防音解除されました。
18 | あなたはサプレスされました。
19 | あなたはサプレス解除されました。
20 | あなたは %s によってサプレス解除されました。
21 | %s が接続しました。
22 | %s が切断しました。
23 | あなたは %1$s によって、サーバーからキックおよび禁止されました: %2$s.
24 | あなたは %1$s によって、サーバーからキックされました: %2$s.
25 | %3$s は %1$s によって、サーバーからキックおよび禁止されました: %2$s.
26 | %3$s は %1$s によって、サーバーからキックされました: %2$s.
27 | 録音が開始しました
28 | 録音が停止しました
29 | %s が録音を開始しました。
30 | %s が録音を停止しました。
31 | %s がチャンネルに入りました。
32 | %1$s が %2$s に移動しました。
33 | %1$s は %2$s から %3$s で移動しました。
34 | %1$s が %3$s によって %2$s に移動しました。
35 | Bluetooth が接続しました
36 | Bluetooth が切断しました
37 | 拒否されました: チャンネル名が正しくありません。
38 | 拒否されました: テキストメッセージが長すぎます。
39 | 拒否されました: 一時チャンネルで操作が許可されていません。
40 | この操作を実行するには証明書が必要です。
41 | ユーザー名が正しくありません。
42 | チャンネルが一杯です。
43 | チャンネルがネストの上限に達しました。
44 | 理由: %s
45 | 権限が拒否されました。
46 | サーバー
47 | サーバー
48 |
49 |
--------------------------------------------------------------------------------
/src/main/java/com/morlunk/jumble/audio/encoder/PreprocessingEncoder.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2014 Andrew Comminos
3 | *
4 | * This program is free software: you can redistribute it and/or modify
5 | * it under the terms of the GNU General Public License as published by
6 | * the Free Software Foundation, either version 3 of the License, or
7 | * (at your option) any later version.
8 | *
9 | * This program is distributed in the hope that it will be useful,
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | * GNU General Public License for more details.
13 | *
14 | * You should have received a copy of the GNU General Public License
15 | * along with this program. If not, see .
16 | */
17 |
18 | package com.morlunk.jumble.audio.encoder;
19 |
20 | import com.googlecode.javacpp.IntPointer;
21 | import com.morlunk.jumble.audio.javacpp.Speex;
22 | import com.morlunk.jumble.exception.NativeAudioException;
23 | import com.morlunk.jumble.net.PacketBuffer;
24 |
25 | import java.nio.BufferUnderflowException;
26 |
27 | /**
28 | * Wrapper performing preprocessing options on the nested encoder.
29 | * Uses Speex preprocessor.
30 | * Created by andrew on 17/04/14.
31 | */
32 | public class PreprocessingEncoder implements IEncoder {
33 | private IEncoder mEncoder;
34 | private Speex.SpeexPreprocessState mPreprocessor;
35 |
36 | public PreprocessingEncoder(IEncoder encoder, int frameSize, int sampleRate) {
37 | mEncoder = encoder;
38 | mPreprocessor = new Speex.SpeexPreprocessState(frameSize, sampleRate);
39 |
40 | IntPointer arg = new IntPointer(1);
41 |
42 | arg.put(0);
43 | mPreprocessor.control(Speex.SpeexPreprocessState.SPEEX_PREPROCESS_SET_VAD, arg);
44 | arg.put(1);
45 | mPreprocessor.control(Speex.SpeexPreprocessState.SPEEX_PREPROCESS_SET_AGC, arg);
46 | mPreprocessor.control(Speex.SpeexPreprocessState.SPEEX_PREPROCESS_SET_DENOISE, arg);
47 | mPreprocessor.control(Speex.SpeexPreprocessState.SPEEX_PREPROCESS_SET_DEREVERB, arg);
48 |
49 | arg.put(30000);
50 | mPreprocessor.control(Speex.SpeexPreprocessState.SPEEX_PREPROCESS_SET_AGC_TARGET, arg);
51 |
52 | // TODO AGC max gain, decrement, noise suppress, echo
53 |
54 | // Increase VAD difficulty
55 | arg.put(99);
56 | mPreprocessor.control(Speex.SpeexPreprocessState.SPEEX_PREPROCESS_GET_PROB_START, arg);
57 | }
58 |
59 | @Override
60 | public int encode(short[] input, int inputSize) throws NativeAudioException {
61 | mPreprocessor.preprocess(input);
62 | return mEncoder.encode(input, inputSize);
63 | }
64 |
65 | @Override
66 | public int getBufferedFrames() {
67 | return mEncoder.getBufferedFrames();
68 | }
69 |
70 | @Override
71 | public boolean isReady() {
72 | return mEncoder.isReady();
73 | }
74 |
75 | @Override
76 | public void getEncodedData(PacketBuffer packetBuffer) throws BufferUnderflowException {
77 | mEncoder.getEncodedData(packetBuffer);
78 | }
79 |
80 | @Override
81 | public void terminate() throws NativeAudioException {
82 | mEncoder.terminate();
83 | }
84 |
85 | public void setEncoder(IEncoder encoder) {
86 | if(mEncoder != null) mEncoder.destroy();
87 | mEncoder = encoder;
88 | }
89 |
90 | @Override
91 | public void destroy() {
92 | mPreprocessor.destroy();
93 | mEncoder.destroy();
94 | mPreprocessor = null;
95 | mEncoder = null;
96 | }
97 | }
98 |
--------------------------------------------------------------------------------
/src/main/res/values-ru/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | %1$s перемещен(а) %3$s из %2$s.
4 | Звук и микрофон отключен.
5 | Микрофон отключен.
6 | Микрофон включен.
7 | Микрофон и звук включен.
8 | %s отключил(а) звук и микрофон.
9 | %s выключил(а) микрофон.
10 | %s включил(а) микрофон.
11 | %s включил(а) звук и микрофон.
12 | %s выключил(а) вам звук и микрофон.
13 | %s включил(а) вам звук и микрофон.
14 | %s выключил(а) вам микрофон.
15 | %s включил(а) вам микрофон.
16 | %s включил(а) вам звук.
17 | Вы были заглушены.
18 | Оглушение снято.
19 | %s снял оглушение с вас.
20 | %s соеденен(а).
21 | %s отсоединен(а).
22 | Вы были исключены и заблокированы на сервера, %1$s: %2$s.
23 | Вы были исключены с сервера, %1$s: %2$s.
24 | %3$s заблокирован(а) и исключен(а) с сервера, %1$s: %2$s.
25 | %3$s исключен(а) с сервера, %1$s: %2$s.
26 | Запись начата
27 | Запись остановлена
28 | %s начал(а) запись.
29 | %s остановил(а) запись.
30 | %s вошел(а) в канал
31 | %1$s перемещен(а) в %2$s.
32 | %1$s перемещен(а) %3$s из %2$s.
33 | %1$s перемещен(а) %3$s в %2$s.
34 | Bluetooth соединен
35 | Bluetooth отсоединен
36 | Отказано: Неверное имя канала.
37 | Отказано: Текстовое сообщение слишком длинное.
38 | Отказано: Операция не разрешена во временном канале.
39 | Вам нужен сертификат для выполнения данной операции.
40 | Неверное имя пользователя.
41 | Канал переполнен.
42 | Достигнул предел вложенности канала.
43 | Причина: %s
44 | Доступ запрещен.
45 | Сервер
46 | сервер
47 |
48 |
--------------------------------------------------------------------------------
/src/main/java/com/morlunk/jumble/net/JumbleCertificateGenerator.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2014 Andrew Comminos
3 | *
4 | * This program is free software: you can redistribute it and/or modify
5 | * it under the terms of the GNU General Public License as published by
6 | * the Free Software Foundation, either version 3 of the License, or
7 | * (at your option) any later version.
8 | *
9 | * This program is distributed in the hope that it will be useful,
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | * GNU General Public License for more details.
13 | *
14 | * You should have received a copy of the GNU General Public License
15 | * along with this program. If not, see .
16 | */
17 |
18 | package com.morlunk.jumble.net;
19 |
20 | import org.spongycastle.asn1.x500.X500Name;
21 | import org.spongycastle.asn1.x509.SubjectPublicKeyInfo;
22 | import org.spongycastle.cert.X509CertificateHolder;
23 | import org.spongycastle.cert.X509v3CertificateBuilder;
24 | import org.spongycastle.cert.jcajce.JcaX509CertificateConverter;
25 | import org.spongycastle.jce.provider.BouncyCastleProvider;
26 | import org.spongycastle.operator.ContentSigner;
27 | import org.spongycastle.operator.OperatorCreationException;
28 | import org.spongycastle.operator.jcajce.JcaContentSignerBuilder;
29 |
30 | import java.io.IOException;
31 | import java.io.OutputStream;
32 | import java.math.BigInteger;
33 | import java.security.KeyPair;
34 | import java.security.KeyPairGenerator;
35 | import java.security.KeyStore;
36 | import java.security.KeyStoreException;
37 | import java.security.NoSuchAlgorithmException;
38 | import java.security.NoSuchProviderException;
39 | import java.security.SecureRandom;
40 | import java.security.cert.CertificateException;
41 | import java.security.cert.X509Certificate;
42 | import java.util.Calendar;
43 | import java.util.Date;
44 |
45 | public class JumbleCertificateGenerator {
46 | private static final String ISSUER = "CN=Jumble Client";
47 | private static final Integer YEARS_VALID = 20;
48 |
49 | public static X509Certificate generateCertificate(OutputStream output) throws NoSuchAlgorithmException, OperatorCreationException, CertificateException, KeyStoreException, NoSuchProviderException, IOException {
50 | BouncyCastleProvider provider = new BouncyCastleProvider(); // Use SpongyCastle provider, supports creating X509 certs
51 | KeyPairGenerator generator = KeyPairGenerator.getInstance("RSA");
52 | generator.initialize(2048, new SecureRandom());
53 |
54 | KeyPair keyPair = generator.generateKeyPair();
55 |
56 | SubjectPublicKeyInfo publicKeyInfo = SubjectPublicKeyInfo.getInstance(keyPair.getPublic().getEncoded());
57 | ContentSigner signer = new JcaContentSignerBuilder("SHA1withRSA").setProvider(provider).build(keyPair.getPrivate());
58 |
59 | Date startDate = new Date();
60 | Calendar calendar = Calendar.getInstance();
61 | calendar.setTime(startDate);
62 | calendar.add(Calendar.YEAR, YEARS_VALID);
63 | Date endDate = calendar.getTime();
64 |
65 | X509v3CertificateBuilder certBuilder = new X509v3CertificateBuilder(new X500Name(ISSUER),
66 | BigInteger.ONE,
67 | startDate, endDate, new X500Name(ISSUER),
68 | publicKeyInfo);
69 |
70 | X509CertificateHolder certificateHolder = certBuilder.build(signer);
71 |
72 | X509Certificate certificate = new JcaX509CertificateConverter().setProvider(provider).getCertificate(certificateHolder);
73 |
74 | KeyStore keyStore = KeyStore.getInstance("PKCS12", provider);
75 | keyStore.load(null, null);
76 | keyStore.setKeyEntry("Jumble Key", keyPair.getPrivate(), null, new X509Certificate[] { certificate });
77 |
78 | keyStore.store(output, "".toCharArray());
79 |
80 | return certificate;
81 | }
82 | }
83 |
--------------------------------------------------------------------------------
/src/main/res/values-nl/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | %1$s verplaatst van %2$s door %3$s.
4 | Gedempt en doof gemaakt.
5 | Gedempt.
6 | Dempen opgeheven.
7 | Dempen opgeheven en horend gemaakt.
8 | %s is nu gedempt en doof gemaakt.
9 | %s is nu gedempt.
10 | %s is niet meer gedempt.
11 | %s is niet meer gedempt of doof.
12 | U bent gedempt en doof gemaakt door %s.
13 | U bent niet meer gedempt en horend gemaakt door %s.
14 | U bent gedempt door %s.
15 | U bent niet meer gedempt door %s.
16 | U bent horend gemaakt door %s.
17 | U werd onderdrukt
18 | U bent niet meer onderdrukt
19 | U bent niet meer onderdrukt door %s.
20 | %s verbonden.
21 | %s verbinding verbroken.
22 | U bent verbannnen van de server door %1$s: %2$s.
23 | U bent van de server geschopt door %1$s: %2$s.
24 | %3$s is van de server verbannen door %1$s: %2$s.
25 | %3$s is van de server geschopt door %1$s: %2$s.
26 | Opname gestart
27 | Opname gestopt
28 | %s heeft opname gestart.
29 | %s heeft opname gestopt
30 | %s kanaal binnengekomen
31 | %1$s verplaatst naar %2$s.
32 | %1$s verplaatst van %2$s door %3$s.
33 | %1$s verplaatst van %2$s door %3$s.
34 | Bluetooth verbonden
35 | Bluetooth verbroken
36 | Geweigerd: Ongeldige kanaal naam.
37 | Geweigerd: Tekst boodschap te lang.
38 | Geweigerd: Handeling niet toegestaan in tijdelijk kanaal.
39 | U hebt een certificaat nodig om deze handeling te voltooien.
40 | Ongeldige gebruikersnaam.
41 | Kanaal is vol
42 | Ingesloten kanaal limiet bereikt
43 | Reden: %s
44 | Geen toelating
45 | Server
46 | de server
47 |
48 |
--------------------------------------------------------------------------------
/src/main/jni/Android.mk:
--------------------------------------------------------------------------------
1 | #
2 | # Copyright (C) 2013 Andrew Comminos
3 | #
4 | # Licensed under the Apache License, Version 2.0 (the "License");
5 | # you may not use this file except in compliance with the License.
6 | # You may obtain a copy of the License at
7 | #
8 | # http://www.apache.org/licenses/LICENSE-2.0
9 | #
10 | # Unless required by applicable law or agreed to in writing, software
11 | # distributed under the License is distributed on an "AS IS" BASIS,
12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | # See the License for the specific language governing permissions and
14 | # limitations under the License.
15 | #
16 |
17 | ROOT := $(call my-dir)
18 |
19 | include $(CLEAR_VARS)
20 |
21 | LOCAL_PATH := $(ROOT)/speex/libspeex
22 | LOCAL_MODULE := jnispeex
23 | LOCAL_C_INCLUDES := $(ROOT)/speex/include/
24 | LOCAL_SRC_FILES := cb_search.c exc_10_32_table.c exc_8_128_table.c filters.c \
25 | gain_table.c hexc_table.c high_lsp_tables.c lsp.c \
26 | ltp.c speex.c stereo.c vbr.c \
27 | vq.c bits.c exc_10_16_table.c exc_20_32_table.c exc_5_256_table.c \
28 | exc_5_64_table.c gain_table_lbr.c hexc_10_32_table.c lpc.c \
29 | lsp_tables_nb.c modes.c modes_wb.c nb_celp.c \
30 | quant_lsp.c sb_celp.c speex_callbacks.c speex_header.c \
31 | window.c resample.c jitter.c preprocess.c \
32 | mdf.c kiss_fft.c kiss_fftr.c fftwrap.c \
33 | filterbank.c scal.c \
34 | $(ROOT)/jnispeex.cpp
35 | LOCAL_CFLAGS := -D__EMX__ -DUSE_KISS_FFT -DFIXED_POINT -DEXPORT=''
36 | LOCAL_CPP_FEATURES := exceptions
37 | LOCAL_LDLIBS := -llog
38 | include $(BUILD_SHARED_LIBRARY)
39 |
40 | include $(CLEAR_VARS)
41 | LOCAL_PATH := $(ROOT)/celt-0.11.0-src/libcelt
42 | LOCAL_MODULE := jnicelt11
43 | LOCAL_SRC_FILES := bands.c celt.c cwrs.c entcode.c entdec.c entenc.c header.c kiss_fft.c \
44 | laplace.c mathops.c mdct.c modes.c pitch.c plc.c quant_bands.c rate.c vq.c \
45 | $(ROOT)/jnicelt11.cpp
46 | LOCAL_C_INCLUDES := $(ROOT)/celt-0.11.0-src/libcelt/
47 | LOCAL_CFLAGS := -I$(ROOT)/celt-0.11.0-build -DHAVE_CONFIG_H -fvisibility=hidden
48 | LOCAL_CPP_FEATURES := exceptions
49 | LOCAL_LDLIBS := -llog
50 | include $(BUILD_SHARED_LIBRARY)
51 |
52 | include $(CLEAR_VARS)
53 | LOCAL_PATH := $(ROOT)/celt-0.7.0-src/libcelt
54 | LOCAL_MODULE := jnicelt7
55 | LOCAL_SRC_FILES := bands.c celt.c cwrs.c entcode.c entdec.c entenc.c header.c kiss_fft.c \
56 | kiss_fftr.c laplace.c mdct.c modes.c pitch.c psy.c quant_bands.c rangedec.c \
57 | rangeenc.c rate.c vq.c $(ROOT)/jnicelt7.cpp
58 | LOCAL_C_INCLUDES := $(ROOT)/celt-0.7.0-src/libcelt/
59 | LOCAL_CFLAGS := -I$(ROOT)/celt-0.7.0-build -DHAVE_CONFIG_H -fvisibility=hidden
60 | LOCAL_CPP_FEATURES := exceptions
61 | LOCAL_LDLIBS := -llog
62 | include $(BUILD_SHARED_LIBRARY)
63 |
64 | include $(CLEAR_VARS)
65 | LOCAL_PATH := $(ROOT)/opus
66 | LOCAL_MODULE := jniopus
67 |
68 | include $(LOCAL_PATH)/celt_sources.mk
69 | include $(LOCAL_PATH)/silk_sources.mk
70 | include $(LOCAL_PATH)/opus_sources.mk
71 |
72 | ifeq ($(TARGET_ARCH), arm)
73 | CELT_SOURCES += $(CELT_SOURCES_ARM)
74 | SILK_SOURCES += $(SILK_SOURCES_ARM)
75 | endif
76 |
77 | # TODO: add support for floating-point?
78 | SILK_SOURCES += $(SILK_SOURCES_FIXED)
79 | OPUS_SOURCES += $(OPUS_SOURCES_FLOAT)
80 | # end fixed point
81 |
82 | LOCAL_C_INCLUDES := $(LOCAL_PATH)/include $(LOCAL_PATH)/celt $(LOCAL_PATH)/silk \
83 | $(LOCAL_PATH)/silk/float $(LOCAL_PATH)/silk/fixed
84 | LOCAL_SRC_FILES := $(CELT_SOURCES) $(SILK_SOURCES) $(OPUS_SOURCES) $(ROOT)/jniopus.cpp
85 | LOCAL_CFLAGS := -DOPUS_BUILD -DVAR_ARRAYS -Wno-traditional -DFIXED_POINT
86 | LOCAL_CPP_FEATURES := exceptions
87 | LOCAL_LDLIBS := -llog
88 | include $(BUILD_SHARED_LIBRARY)
89 |
--------------------------------------------------------------------------------
/src/main/res/values-es/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | El ancho de banda máximo del servidor es solo de %1$d kbit/s. Calidad de audio ajustada a %2$d kbit/s (%3$d ms)
4 | %1$s fue movido a este canal desde %2$s por %3$s.
5 | Mudo y sordo.
6 | Mudo.
7 | Con voz
8 | Con voz y escucha.
9 | %s está ahora enmudecido y ensordecido
10 | %s está ahora enmudecido.
11 | %s ahora tiene voz.
12 | %s ahora tiene voz y escucha.
13 | Has sido enmudecido y ensordecido por %s
14 | %s te ha desenmudecido y dado escucha
15 | Has sido enmudecido por %s
16 | Has sido desenmudecido por %s
17 | %s te ha dado escucha
18 | Has sido suprimido.
19 | Ya no estás suprimido.
20 | %s ha cesado tu supresión.
21 | %s se ha conectado.
22 | %s se ha desconectado.
23 | Has sido expulsado y prohibido del servidor por %1$s: %2$s.
24 | Has sido expulsado del servidor por %1$s: %2$s.
25 | %3$s fue expulsado y prohibido del servidor por %1$s: %2$s.
26 | %3$s ha sido expulsado del servidor por %1$s: %2$s.
27 | Grabación iniciada
28 | Grabación parada
29 | %s ha empezado a grabar.
30 | %s ha parado de grabar.
31 | %s entró al canal.
32 | %1$s fue movido a %2$s.
33 | %1$s fue movido a este canal desde %2$s por %3$s.
34 | %1$s fue movido a %2$s por %3$s.
35 | Bluetooth conectado
36 | Bluetooth desconectado
37 | Denegado: Nombre de canal inválido.
38 | Denegado: Mensaje de texto demasiado largo.
39 | Denegado: Acción no permitida en un canal temporal.
40 | Necesitas un certificado para realizar esta operación.
41 | Nombre de usuario inválido.
42 | El canal está lleno.
43 | Límite de canales anidados alcanzado.
44 | Razón: %s
45 | Permiso denegado.
46 | Servidor
47 | el servidor
48 |
49 |
--------------------------------------------------------------------------------
/src/main/res/values-fr/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | La bande passante réseau maximale du serveur est seulement de %1$d kbit/s. La qualité audio est ajustée à %2$d kbit/s (%3$d ms)
4 | %1$s a été déplacé de %2$s par %3$s.
5 | Muet et sourd.
6 | Muet.
7 | Non muet.
8 | N\'est plus muet et sourd.
9 | %s et maintenant muet et sourd.
10 | %s est maintenant muet.
11 | %s n\'est maintenant plus muet.
12 | %s n\'est plus muet et sourd.
13 | Vous avez été rendu muet et sourd par %s.
14 | Vous n\'êtes plus muet et sourd par %s.
15 | Vous avez été rendu muet par %s.
16 | Vous n\'êtes plus muet par %s.
17 | Vous n\'êtes plus sourd par %s.
18 | Vous avez été supprimé.
19 | Vous avez été rétabli.
20 | Vous avez été rétabli par %s.
21 | %s connecté.
22 | %s déconnecté.
23 | Vous avez été éjecté et banni du serveur par %1$s: %2$s.
24 | Vous avez été éjecté du serveur par %1$s: %2$s.
25 | %3$s a été éjecté et banni du serveur par %1$s: %2$s.
26 | %3$s a été éjecté du serveur par %1$s: %2$s.
27 | Enregistrement démarré
28 | Enregistrement interrompu
29 | %s a commencé à enregistrer.
30 | %s a arrêté d’enregistrer.
31 | %s est entré dans le canal.
32 | %1$s s\'est déplacé dans %2$s.
33 | %1$s s\'est déplacé de %2$s par %3$s.
34 | %1$s a été déplacé dans %2$s par %3$s.
35 | Bluetooth connecté
36 | Bluetooth déconnecté
37 | Refusé: Nom de canal invalide.
38 | Refusé : message texte trop long.
39 | Refusé: Opération non permise dans un canal temporaire.
40 | Vous avez besoin d\'un certificat pour effectuer cette opération.
41 | Nom d\'utilisateur invalide.
42 | Le canal est plein.
43 | Limite du nombre de canal enfant atteint.
44 | Raison : %s
45 | Permission non accordée.
46 | Serveur
47 | le serveur
48 |
49 |
--------------------------------------------------------------------------------
/src/main/java/com/morlunk/jumble/util/JumbleException.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2014 Andrew Comminos
3 | *
4 | * This program is free software: you can redistribute it and/or modify
5 | * it under the terms of the GNU General Public License as published by
6 | * the Free Software Foundation, either version 3 of the License, or
7 | * (at your option) any later version.
8 | *
9 | * This program is distributed in the hope that it will be useful,
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | * GNU General Public License for more details.
13 | *
14 | * You should have received a copy of the GNU General Public License
15 | * along with this program. If not, see .
16 | */
17 |
18 | package com.morlunk.jumble.util;
19 |
20 | import android.os.Parcel;
21 | import android.os.Parcelable;
22 |
23 | import com.morlunk.jumble.protobuf.Mumble;
24 |
25 | /**
26 | * Created by andrew on 14/07/13.
27 | */
28 | public class JumbleException extends Exception implements Parcelable {
29 |
30 | public static final Creator CREATOR = new Creator() {
31 | @Override
32 | public JumbleException createFromParcel(Parcel source) {
33 | return new JumbleException(source);
34 | }
35 |
36 | @Override
37 | public JumbleException[] newArray(int size) {
38 | return new JumbleException[size];
39 | }
40 | };
41 |
42 | private JumbleDisconnectReason mReason;
43 | /** Indicates that this exception was caused by a reject from the server. */
44 | private Mumble.Reject mReject;
45 | /** Indicates that this exception was caused by being kicked/banned from the server. */
46 | private Mumble.UserRemove mUserRemove;
47 |
48 | public JumbleException(String message, Throwable e, JumbleDisconnectReason reason) {
49 | super(message, e);
50 | mReason = reason;
51 | }
52 |
53 | public JumbleException(String message, JumbleDisconnectReason reason) {
54 | super(message);
55 | mReason = reason;
56 | }
57 |
58 | public JumbleException(Throwable e, JumbleDisconnectReason reason) {
59 | super(e);
60 | mReason = reason;
61 | }
62 |
63 | public JumbleException(Mumble.Reject reject) {
64 | super("Reject: "+reject.getReason());
65 | mReject = reject;
66 | mReason = JumbleDisconnectReason.REJECT;
67 | }
68 |
69 | public JumbleException(Mumble.UserRemove userRemove) {
70 | super((userRemove.getBan() ? "Banned: " : "Kicked: ")+userRemove.getReason());
71 | mUserRemove = userRemove;
72 | mReason = JumbleDisconnectReason.USER_REMOVE;
73 | }
74 |
75 | private JumbleException(Parcel in) {
76 | super(in.readString(), (Throwable) in.readSerializable());
77 | mReason = JumbleDisconnectReason.values()[in.readInt()];
78 | mReject = (Mumble.Reject) in.readSerializable();
79 | mUserRemove = (Mumble.UserRemove) in.readSerializable();
80 | }
81 |
82 | public JumbleDisconnectReason getReason() {
83 | return mReason;
84 | }
85 |
86 | public Mumble.Reject getReject() {
87 | return mReject;
88 | }
89 |
90 | public Mumble.UserRemove getUserRemove() {
91 | return mUserRemove;
92 | }
93 | @Override
94 | public int describeContents() {
95 | return 0;
96 | }
97 |
98 | @Override
99 | public void writeToParcel(Parcel dest, int flags) {
100 | dest.writeString(getMessage());
101 | dest.writeSerializable(getCause());
102 | dest.writeInt(mReason.ordinal());
103 | dest.writeSerializable(mReject);
104 | dest.writeSerializable(mUserRemove);
105 | }
106 |
107 | public enum JumbleDisconnectReason {
108 | REJECT,
109 | USER_REMOVE,
110 | CONNECTION_ERROR,
111 | OTHER_ERROR
112 | }
113 | }
114 |
--------------------------------------------------------------------------------
/src/androidTest/java/com/morlunk/jumble/test/URLParserTest.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2014 Andrew Comminos
3 | *
4 | * This program is free software: you can redistribute it and/or modify
5 | * it under the terms of the GNU General Public License as published by
6 | * the Free Software Foundation, either version 3 of the License, or
7 | * (at your option) any later version.
8 | *
9 | * This program is distributed in the hope that it will be useful,
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | * GNU General Public License for more details.
13 | *
14 | * You should have received a copy of the GNU General Public License
15 | * along with this program. If not, see .
16 | */
17 |
18 | package com.morlunk.jumble.test;
19 |
20 | import com.morlunk.jumble.Constants;
21 | import com.morlunk.jumble.model.Server;
22 | import com.morlunk.jumble.util.MumbleURLParser;
23 |
24 | import junit.framework.TestCase;
25 |
26 | import java.net.MalformedURLException;
27 |
28 | /**
29 | * Tests the Mumble URL parser.
30 | * Created by andrew on 03/03/14.
31 | */
32 | public class URLParserTest extends TestCase {
33 |
34 | public void testURL() {
35 | String url = "mumble://server.com/";
36 | try {
37 | Server server = MumbleURLParser.parseURL(url);
38 | assertEquals(server.getHost(), "server.com");
39 | assertEquals(server.getPort(), Constants.DEFAULT_PORT);
40 | } catch (MalformedURLException e) {
41 | fail("Failed to parse URL.");
42 | }
43 | }
44 |
45 | public void testURLWithPort() {
46 | String url = "mumble://server.com:5000/";
47 | try {
48 | Server server = MumbleURLParser.parseURL(url);
49 | assertEquals(server.getHost(), "server.com");
50 | assertEquals(server.getPort(), 5000);
51 | } catch (MalformedURLException e) {
52 | fail("Failed to parse URL.");
53 | }
54 | }
55 |
56 | public void testURLWithUsername() {
57 | String url = "mumble://TestUser@server.com/";
58 | try {
59 | Server server = MumbleURLParser.parseURL(url);
60 | assertEquals(server.getHost(), "server.com");
61 | assertEquals(server.getUsername(), "TestUser");
62 | assertEquals(server.getPort(), Constants.DEFAULT_PORT);
63 | } catch (MalformedURLException e) {
64 | fail("Failed to parse URL.");
65 | }
66 | }
67 |
68 | public void testURLWithCredentials() {
69 | String url = "mumble://TestUser:mypassword@server.com:5000/";
70 | try {
71 | Server server = MumbleURLParser.parseURL(url);
72 | assertEquals(server.getHost(), "server.com");
73 | assertEquals(server.getUsername(), "TestUser");
74 | assertEquals(server.getPassword(), "mypassword");
75 | assertEquals(server.getPort(), 5000);
76 | } catch (MalformedURLException e) {
77 | fail("Failed to parse URL.");
78 | }
79 | }
80 |
81 | public void testURLWithPassword() {
82 | String url = "mumble://:mypassword@server.com/";
83 | try {
84 | Server server = MumbleURLParser.parseURL(url);
85 | assertEquals(server.getHost(), "server.com");
86 | assertEquals(server.getPassword(), "mypassword");
87 | assertEquals(server.getPort(), Constants.DEFAULT_PORT);
88 | } catch (MalformedURLException e) {
89 | fail("Failed to parse URL.");
90 | }
91 | }
92 |
93 | public void testInvalidScheme() {
94 | String url = "grumble://server.com/";
95 | try {
96 | MumbleURLParser.parseURL(url);
97 | fail("Successfully parsed bad scheme!");
98 | } catch (MalformedURLException e) {
99 | e.printStackTrace();
100 | }
101 | }
102 |
103 | }
104 |
--------------------------------------------------------------------------------
/src/main/java/com/morlunk/jumble/IJumbleService.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2015 Andrew Comminos
3 | *
4 | * This program is free software: you can redistribute it and/or modify
5 | * it under the terms of the GNU General Public License as published by
6 | * the Free Software Foundation, either version 3 of the License, or
7 | * (at your option) any later version.
8 | *
9 | * This program is distributed in the hope that it will be useful,
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | * GNU General Public License for more details.
13 | *
14 | * You should have received a copy of the GNU General Public License
15 | * along with this program. If not, see .
16 | */
17 |
18 | package com.morlunk.jumble;
19 |
20 | import com.morlunk.jumble.model.IChannel;
21 | import com.morlunk.jumble.model.IUser;
22 | import com.morlunk.jumble.model.Message;
23 | import com.morlunk.jumble.model.Server;
24 | import com.morlunk.jumble.model.WhisperTarget;
25 | import com.morlunk.jumble.net.JumbleUDPMessageType;
26 | import com.morlunk.jumble.util.IJumbleObserver;
27 | import com.morlunk.jumble.util.JumbleDisconnectedException;
28 | import com.morlunk.jumble.util.JumbleException;
29 | import com.morlunk.jumble.util.VoiceTargetMode;
30 |
31 | import java.util.List;
32 |
33 | /**
34 | * A public interface for clients to communicate with a {@link JumbleService}.
35 | * The long-term goal for this class is to migrate of the complexity out of this class into a
36 | * JumbleProtocol class that is owned by a {@link com.morlunk.jumble.net.JumbleConnection}.
37 | *
38 | * Calls are not guaranteed to be thread-safe, so only call the binder from the main thread.
39 | * Service state changes related to connection state are only guaranteed to work if isConnected()
40 | * is checked to be true.
41 | *
42 | * If not explicitly stated in the method documentation, any call that depends on connection state
43 | * will throw IllegalStateException if disconnected or not synchronized.
44 | */
45 | public interface IJumbleService {
46 | void registerObserver(IJumbleObserver observer);
47 |
48 | void unregisterObserver(IJumbleObserver observer);
49 |
50 | /**
51 | * @return true if handshaking with the server has completed.
52 | */
53 | boolean isConnected();
54 |
55 | /**
56 | * Disconnects from the active connection, or does nothing if no connection is active.
57 | */
58 | void disconnect();
59 |
60 | /**
61 | * Returns the current connection state of the service.
62 | * @return one of {@link JumbleService.ConnectionState}.
63 | */
64 | JumbleService.ConnectionState getConnectionState();
65 |
66 | /**
67 | * If the {@link JumbleService} disconnected due to an error, returns that error.
68 | * @return The error causing disconnection. If the last disconnection was successful or a
69 | * connection has yet to be established, returns null.
70 | */
71 | JumbleException getConnectionError();
72 |
73 | /**
74 | * Returns the reconnection state of the {@link JumbleService}.
75 | * @return true if the service will attempt to automatically reconnect in the future.
76 | */
77 | boolean isReconnecting();
78 |
79 | /**
80 | * Cancels any future reconnection attempts. Does nothing if reconnection is not in progress.
81 | */
82 | void cancelReconnect();
83 |
84 | /**
85 | * @return the server that Jumble is currently connected to, was connected to, or will attempt connection to.
86 | */
87 | Server getTargetServer();
88 |
89 | /**
90 | * Returns the active session with the remote, or throws an exception if no session is currently
91 | * active. This can be checked using {@link IJumbleService#isConnected()}.
92 | * @return the active session.
93 | * @throws JumbleDisconnectedException if the connection state is not CONNECTED.
94 | */
95 | IJumbleSession getSession() throws JumbleDisconnectedException;
96 | }
97 |
--------------------------------------------------------------------------------
/src/main/java/com/morlunk/jumble/audio/encoder/CELT11Encoder.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2014 Andrew Comminos
3 | *
4 | * This program is free software: you can redistribute it and/or modify
5 | * it under the terms of the GNU General Public License as published by
6 | * the Free Software Foundation, either version 3 of the License, or
7 | * (at your option) any later version.
8 | *
9 | * This program is distributed in the hope that it will be useful,
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | * GNU General Public License for more details.
13 | *
14 | * You should have received a copy of the GNU General Public License
15 | * along with this program. If not, see .
16 | */
17 |
18 | package com.morlunk.jumble.audio.encoder;
19 |
20 | import com.googlecode.javacpp.IntPointer;
21 | import com.googlecode.javacpp.Pointer;
22 | import com.morlunk.jumble.audio.javacpp.CELT11;
23 | import com.morlunk.jumble.exception.NativeAudioException;
24 | import com.morlunk.jumble.net.PacketBuffer;
25 | import com.morlunk.jumble.protocol.AudioHandler;
26 |
27 | import java.nio.BufferOverflowException;
28 | import java.nio.BufferUnderflowException;
29 |
30 | /**
31 | * Created by andrew on 08/12/14.
32 | */
33 | public class CELT11Encoder implements IEncoder {
34 | private final byte[][] mBuffer;
35 | private final int mBufferSize;
36 | private final int mFramesPerPacket;
37 | private int mBufferedFrames;
38 |
39 | private Pointer mState;
40 |
41 | public CELT11Encoder(int sampleRate, int channels, int framesPerPacket) throws
42 | NativeAudioException {
43 | mFramesPerPacket = framesPerPacket;
44 | mBufferSize = sampleRate / 800;
45 | mBuffer = new byte[framesPerPacket][mBufferSize];
46 | mBufferedFrames = 0;
47 |
48 | IntPointer error = new IntPointer(1);
49 | error.put(0);
50 | mState = CELT11.celt_encoder_create(sampleRate, channels, error);
51 | if(error.get() < 0) throw new NativeAudioException("CELT 0.11.0 encoder initialization " +
52 | "failed with error: "+error.get());
53 | }
54 |
55 | @Override
56 | public int encode(short[] input, int frameSize) throws NativeAudioException {
57 | if (mBufferedFrames >= mFramesPerPacket) {
58 | throw new BufferOverflowException();
59 | }
60 |
61 | int result = CELT11.celt_encode(mState, input, frameSize, mBuffer[mBufferedFrames],
62 | mBufferSize);
63 | if(result < 0) throw new NativeAudioException("CELT 0.11.0 encoding failed with error: "
64 | + result);
65 | mBufferedFrames++;
66 | return result;
67 | }
68 |
69 | @Override
70 | public int getBufferedFrames() {
71 | return mBufferedFrames;
72 | }
73 |
74 | @Override
75 | public boolean isReady() {
76 | return mBufferedFrames == mFramesPerPacket;
77 | }
78 |
79 | @Override
80 | public void getEncodedData(PacketBuffer packetBuffer) throws BufferUnderflowException {
81 | if (mBufferedFrames < mFramesPerPacket) {
82 | throw new BufferUnderflowException();
83 | }
84 |
85 | for (int x = 0; x < mBufferedFrames; x++) {
86 | byte[] frame = mBuffer[x];
87 | int head = frame.length;
88 | if(x < mBufferedFrames - 1)
89 | head |= 0x80;
90 | packetBuffer.append(head);
91 | packetBuffer.append(frame, frame.length);
92 | }
93 |
94 | mBufferedFrames = 0;
95 | }
96 |
97 | @Override
98 | public void terminate() throws NativeAudioException {
99 | // TODO
100 | }
101 |
102 | @Override
103 | public void destroy() {
104 | CELT11.celt_encoder_destroy(mState);
105 | }
106 | }
107 |
--------------------------------------------------------------------------------
/src/main/res/values-de/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | Die maximale Netzwerk-Bandbreite des Servers beträgt nur %1$d kbit/s.
4 | Die Audioqualität wird automatisch angepasst auf %2$d kbit/s (%3$d ms)
5 | %1$s hinein verschoben von %2$s durch %3$s.
6 | Stumm und taub.
7 | Stumm.
8 | Nicht stumm.
9 | Nicht mehr stumm und nicht taub.
10 | %s ist nun stumm und taub.
11 | %s ist jetzt stumm gestellt.
12 | %s ist nicht mehr stumm.
13 | %s ist nicht mehr stumm und nicht mehr taub.
14 | Sie wurden stumm und taub gestellt durch %s.
15 | Sie wurden entstummt und enttaubt durch %s.
16 | Sie wurden stumm gestellt durch %s.
17 | Stummstellung wurde deaktiviert durch %s.
18 | Sie wurden enttaubt durch %s.
19 | Ihre Sprachunterdrückung wurde aktiviert.
20 | Ihre Sprachunterdrückung wurde entfernt.
21 | Ihre Sprachunterdrückung wurde entfernt durch %s.
22 | %s hat den Server betreten.
23 | %s hat den Server verlassen.
24 | Sie wurden vom Server gekickt und gebannt von %1$s: %2$s.
25 | Sie wurden vom Server gekickt durch %1$s: %2$s.
26 | %3$s wurde vom Server gekickt und gebannt durch %1$s: %2$s.
27 | %3$s wurde vom Server gekickt durch %1$s: %2$s.
28 | Aufnahme gestartet
29 | Aufnahme beendet
30 | %s nimmt jetzt auf.
31 | %s hat die Aufnahme beendet.
32 | %s betrat den Kanal.
33 | %1$s verschoben nach %2$s.
34 | %1$s wurde aus %2$s hinein verschoben durch %3$s.
35 | %1$s wurde verschoben nach %2$s durch %3$s.
36 | Bluetooth verbunden
37 | Bluetooth wurde getrennt
38 | Verweigert: Ungültiger Kanalname.
39 | Verweigert: Textnachricht zu lang.
40 | Verweigert: Operation nicht erlaubt in einem temporären Kanal.
41 | Sie benötigten ein Zertifikat, um diese Operation auszuführen.
42 | Ungültiger Benutzername.
43 | Kanal ist voll.
44 | Channel Nesting Limit erreicht.
45 | Grund: %s
46 | Zugriff verweigert.
47 | Server
48 | der Server
49 |
50 |
--------------------------------------------------------------------------------
/src/main/java/com/morlunk/jumble/model/Server.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2014 Andrew Comminos
3 | *
4 | * This program is free software: you can redistribute it and/or modify
5 | * it under the terms of the GNU General Public License as published by
6 | * the Free Software Foundation, either version 3 of the License, or
7 | * (at your option) any later version.
8 | *
9 | * This program is distributed in the hope that it will be useful,
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | * GNU General Public License for more details.
13 | *
14 | * You should have received a copy of the GNU General Public License
15 | * along with this program. If not, see .
16 | */
17 |
18 | package com.morlunk.jumble.model;
19 |
20 | import android.os.Parcel;
21 | import android.os.Parcelable;
22 |
23 | public class Server implements Parcelable {
24 |
25 | private long mId;
26 | private String mName;
27 | private String mHost;
28 | private int mPort;
29 | private String mUsername;
30 | private String mPassword;
31 |
32 | public static final Parcelable.Creator CREATOR = new Parcelable.Creator() {
33 |
34 | @Override
35 | public Server createFromParcel(Parcel parcel) {
36 | return new Server(parcel);
37 | }
38 |
39 | @Override
40 | public Server[] newArray(int i) {
41 | return new Server[i];
42 | }
43 | };
44 |
45 | public Server(long id, String name, String host, int port, String username, String password) {
46 | mId = id;
47 | mName = name;
48 | mHost = host;
49 | mPort = port;
50 | mUsername = username;
51 | mPassword = password;
52 | }
53 |
54 | private Server(Parcel in) {
55 | readFromParcel(in);
56 |
57 | }
58 |
59 | @Override
60 | public void writeToParcel(Parcel parcel, int i) {
61 | parcel.writeLong(mId);
62 | parcel.writeString(mName);
63 | parcel.writeString(mHost);
64 | parcel.writeInt(mPort);
65 | parcel.writeString(mUsername);
66 | parcel.writeString(mPassword);
67 | }
68 |
69 | public void readFromParcel(Parcel in) {
70 | mId = in.readLong();
71 | mName = in.readString();
72 | mHost = in.readString();
73 | mPort = in.readInt();
74 | mUsername = in.readString();
75 | mPassword = in.readString();
76 | }
77 |
78 | @Override
79 | public int describeContents() {
80 | return 0;
81 | }
82 |
83 | public long getId() {
84 | return mId;
85 | }
86 |
87 | public void setId(long id) {
88 | mId = id;
89 | }
90 |
91 | /**
92 | * Returns a user-defined name for the server, or the host if the user-defined name is not set.
93 | * @return A user readable name for the server.
94 | */
95 | public String getName() {
96 | return (mName != null && mName.length() > 0) ? mName : mHost;
97 | }
98 |
99 | public void setName(String mName) {
100 | this.mName = mName;
101 | }
102 |
103 | public String getHost() {
104 | return mHost;
105 | }
106 |
107 | public void setHost(String mHost) {
108 | this.mHost = mHost;
109 | }
110 |
111 | public int getPort() {
112 | return mPort;
113 | }
114 |
115 | public void setPort(int mPort) {
116 | this.mPort = mPort;
117 | }
118 |
119 | public String getUsername() {
120 | return mUsername;
121 | }
122 |
123 | public void setUsername(String mUsername) {
124 | this.mUsername = mUsername;
125 | }
126 |
127 | public String getPassword() {
128 | return mPassword;
129 | }
130 |
131 | public void setPassword(String mPassword) {
132 | this.mPassword = mPassword;
133 | }
134 |
135 | /**
136 | * Returns whether or not the server is stored in a database.
137 | * @return true if the server's ID is in the database.
138 | */
139 | public boolean isSaved() {
140 | return mId != -1;
141 | }
142 | }
143 |
--------------------------------------------------------------------------------
/src/main/java/com/morlunk/jumble/util/JumbleNetworkListener.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2014 Andrew Comminos
3 | *
4 | * This program is free software: you can redistribute it and/or modify
5 | * it under the terms of the GNU General Public License as published by
6 | * the Free Software Foundation, either version 3 of the License, or
7 | * (at your option) any later version.
8 | *
9 | * This program is distributed in the hope that it will be useful,
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | * GNU General Public License for more details.
13 | *
14 | * You should have received a copy of the GNU General Public License
15 | * along with this program. If not, see .
16 | */
17 |
18 | package com.morlunk.jumble.util;
19 |
20 | import com.morlunk.jumble.net.JumbleUDPMessageType;
21 | import com.morlunk.jumble.protobuf.Mumble;
22 | import com.morlunk.jumble.protocol.JumbleTCPMessageListener;
23 | import com.morlunk.jumble.protocol.JumbleUDPMessageListener;
24 |
25 | /**
26 | * Created by andrew on 23/04/14.
27 | */
28 | public class JumbleNetworkListener implements JumbleTCPMessageListener, JumbleUDPMessageListener {
29 | @Override
30 | public void messageAuthenticate(Mumble.Authenticate msg) {
31 |
32 | }
33 |
34 | @Override
35 | public void messageBanList(Mumble.BanList msg) {
36 |
37 | }
38 |
39 | @Override
40 | public void messageReject(Mumble.Reject msg) {
41 |
42 | }
43 |
44 | @Override
45 | public void messageServerSync(Mumble.ServerSync msg) {
46 |
47 | }
48 |
49 | @Override
50 | public void messageServerConfig(Mumble.ServerConfig msg) {
51 |
52 | }
53 |
54 | @Override
55 | public void messagePermissionDenied(Mumble.PermissionDenied msg) {
56 |
57 | }
58 |
59 | @Override
60 | public void messageUDPTunnel(Mumble.UDPTunnel msg) {
61 |
62 | }
63 |
64 | @Override
65 | public void messageUserState(Mumble.UserState msg) {
66 |
67 | }
68 |
69 | @Override
70 | public void messageUserRemove(Mumble.UserRemove msg) {
71 |
72 | }
73 |
74 | @Override
75 | public void messageChannelState(Mumble.ChannelState msg) {
76 |
77 | }
78 |
79 | @Override
80 | public void messageChannelRemove(Mumble.ChannelRemove msg) {
81 |
82 | }
83 |
84 | @Override
85 | public void messageTextMessage(Mumble.TextMessage msg) {
86 |
87 | }
88 |
89 | @Override
90 | public void messageACL(Mumble.ACL msg) {
91 |
92 | }
93 |
94 | @Override
95 | public void messageQueryUsers(Mumble.QueryUsers msg) {
96 |
97 | }
98 |
99 | @Override
100 | public void messagePing(Mumble.Ping msg) {
101 |
102 | }
103 |
104 | @Override
105 | public void messageCryptSetup(Mumble.CryptSetup msg) {
106 |
107 | }
108 |
109 | @Override
110 | public void messageContextAction(Mumble.ContextAction msg) {
111 |
112 | }
113 |
114 | @Override
115 | public void messageContextActionModify(Mumble.ContextActionModify msg) {
116 |
117 | }
118 |
119 | @Override
120 | public void messageRemoveContextAction(Mumble.ContextActionModify msg) {
121 |
122 | }
123 |
124 | @Override
125 | public void messageVersion(Mumble.Version msg) {
126 |
127 | }
128 |
129 | @Override
130 | public void messageUserList(Mumble.UserList msg) {
131 |
132 | }
133 |
134 | @Override
135 | public void messagePermissionQuery(Mumble.PermissionQuery msg) {
136 |
137 | }
138 |
139 | @Override
140 | public void messageCodecVersion(Mumble.CodecVersion msg) {
141 |
142 | }
143 |
144 | @Override
145 | public void messageUserStats(Mumble.UserStats msg) {
146 |
147 | }
148 |
149 | @Override
150 | public void messageRequestBlob(Mumble.RequestBlob msg) {
151 |
152 | }
153 |
154 | @Override
155 | public void messageSuggestConfig(Mumble.SuggestConfig msg) {
156 |
157 | }
158 |
159 | @Override
160 | public void messageVoiceTarget(Mumble.VoiceTarget msg) {
161 |
162 | }
163 |
164 | @Override
165 | public void messageUDPPing(byte[] data) {
166 |
167 | }
168 |
169 | @Override
170 | public void messageVoiceData(byte[] data, JumbleUDPMessageType messageType) {
171 |
172 | }
173 | }
174 |
--------------------------------------------------------------------------------
/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
18 |
19 |
20 | Server maximum network bandwidth is only %1$d kbit/s. Audio quality auto-adjusted to %2$d kbit/s (%3$d ms)
21 | %1$s moved in from %2$s by %3$s.
22 | Muted and deafened.
23 | Muted.
24 | Unmuted.
25 | Unmuted and undeafened.
26 | %s is now muted and deafened.
27 | %s is now muted.
28 | %s is now unmuted.
29 | %s is now unmuted and undeafened.
30 | You were muted and deafened by %s.
31 | You were unmuted and undeafened by %s.
32 | You were muted by %s.
33 | You were unmuted by %s.
34 | You were undeafened by %s.
35 | You were suppressed.
36 | You were unsuppressed.
37 | You were unsuppressed by %s.
38 | %s connected.
39 | %s disconnected.
40 | You were kicked and banned from the server by %1$s: %2$s.
41 | You were kicked from the server by %1$s: %2$s.
42 | %3$s was kicked and banned from the server by %1$s: %2$s.
43 | %3$s was kicked from the server by %1$s: %2$s.
44 | Recording started
45 | Recording stopped
46 | %s started recording.
47 | %s stopped recording.
48 | %s entered channel.
49 | %1$s moved to %2$s.
50 | %1$s moved in from %2$s by %3$s.
51 | %1$s moved to %2$s by %3$s.
52 | Bluetooth connected
53 | Bluetooth disconnected
54 | Denied: Invalid channel name.
55 | Denied: Text message too long.
56 | Denied: Operation not permitted in temporary channel.
57 | You need a certificate to perform this operation.
58 | Invalid username.
59 | Channel is full.
60 | Channel nesting limit reached.
61 | Reason: %s
62 | Permission denied.
63 | Server
64 | the server
65 |
66 |
--------------------------------------------------------------------------------
/src/main/java/com/morlunk/jumble/audio/encoder/CELT7Encoder.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2014 Andrew Comminos
3 | *
4 | * This program is free software: you can redistribute it and/or modify
5 | * it under the terms of the GNU General Public License as published by
6 | * the Free Software Foundation, either version 3 of the License, or
7 | * (at your option) any later version.
8 | *
9 | * This program is distributed in the hope that it will be useful,
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | * GNU General Public License for more details.
13 | *
14 | * You should have received a copy of the GNU General Public License
15 | * along with this program. If not, see .
16 | */
17 |
18 | package com.morlunk.jumble.audio.encoder;
19 |
20 | import com.googlecode.javacpp.IntPointer;
21 | import com.googlecode.javacpp.Pointer;
22 | import com.morlunk.jumble.audio.javacpp.CELT7;
23 | import com.morlunk.jumble.exception.NativeAudioException;
24 | import com.morlunk.jumble.net.PacketBuffer;
25 | import com.morlunk.jumble.protocol.AudioHandler;
26 |
27 | import java.nio.BufferOverflowException;
28 | import java.nio.BufferUnderflowException;
29 |
30 | /**
31 | * Created by andrew on 08/12/14.
32 | */
33 | public class CELT7Encoder implements IEncoder {
34 | private final byte[][] mBuffer;
35 | private final int[] mPacketLengths;
36 | private final int mBufferSize;
37 | private final int mFramesPerPacket;
38 | private int mBufferedFrames;
39 | private boolean mReady;
40 |
41 | private Pointer mMode;
42 | private Pointer mState;
43 |
44 | public CELT7Encoder(int sampleRate, int frameSize, int channels,
45 | int framesPerPacket, int bitrate, int maxBufferSize)
46 | throws NativeAudioException {
47 | mFramesPerPacket = framesPerPacket;
48 | mBufferSize = Math.min(maxBufferSize, bitrate / 800);
49 | mBuffer = new byte[framesPerPacket][mBufferSize];
50 | mPacketLengths = new int[framesPerPacket];
51 | mBufferedFrames = 0;
52 |
53 | IntPointer error = new IntPointer(1);
54 | error.put(0);
55 | mMode = CELT7.celt_mode_create(sampleRate, frameSize, error);
56 | if(error.get() < 0) throw new NativeAudioException("CELT 0.7.0 encoder initialization failed with error: "+error.get());
57 | mState = CELT7.celt_encoder_create(mMode, channels, error);
58 | if(error.get() < 0) throw new NativeAudioException("CELT 0.7.0 encoder initialization failed with error: "+error.get());
59 | CELT7.celt_encoder_ctl(mState, CELT7.CELT_SET_PREDICTION_REQUEST, 0);
60 | CELT7.celt_encoder_ctl(mState, CELT7.CELT_SET_VBR_RATE_REQUEST, bitrate);
61 | }
62 |
63 | @Override
64 | public int encode(short[] input, int inputSize) throws NativeAudioException {
65 | if (mBufferedFrames >= mFramesPerPacket) {
66 | throw new BufferOverflowException();
67 | }
68 |
69 | int result = CELT7.celt_encode(mState, input, null, mBuffer[mBufferedFrames], mBufferSize);
70 | if(result < 0) throw new NativeAudioException("CELT 0.7.0 encoding failed with error: "
71 | + result);
72 | mPacketLengths[mBufferedFrames] = result;
73 | mBufferedFrames++;
74 |
75 | if (mBufferedFrames >= mFramesPerPacket)
76 | mReady = true;
77 |
78 | return result;
79 | }
80 |
81 | @Override
82 | public int getBufferedFrames() {
83 | return mBufferedFrames;
84 | }
85 |
86 | @Override
87 | public boolean isReady() {
88 | return mReady && mBufferedFrames > 0;
89 | }
90 |
91 | @Override
92 | public void getEncodedData(PacketBuffer packetBuffer) throws BufferUnderflowException {
93 | if (!mReady)
94 | throw new BufferUnderflowException();
95 |
96 | for (int x = 0; x < mBufferedFrames; x++) {
97 | byte[] frame = mBuffer[x];
98 | int length = mPacketLengths[x];
99 | int head = length;
100 | if(x < mBufferedFrames - 1)
101 | head |= 0x80;
102 | packetBuffer.append(head);
103 | packetBuffer.append(frame, length);
104 | }
105 |
106 | mBufferedFrames = 0;
107 | mReady = false;
108 | }
109 |
110 | @Override
111 | public void terminate() throws NativeAudioException {
112 | mReady = true;
113 | }
114 |
115 | @Override
116 | public void destroy() {
117 | CELT7.celt_encoder_destroy(mState);
118 | CELT7.celt_mode_destroy(mMode);
119 | }
120 | }
121 |
--------------------------------------------------------------------------------
/src/main/java/com/morlunk/jumble/protocol/JumbleTCPMessageListener.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2014 Andrew Comminos
3 | *
4 | * This program is free software: you can redistribute it and/or modify
5 | * it under the terms of the GNU General Public License as published by
6 | * the Free Software Foundation, either version 3 of the License, or
7 | * (at your option) any later version.
8 | *
9 | * This program is distributed in the hope that it will be useful,
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | * GNU General Public License for more details.
13 | *
14 | * You should have received a copy of the GNU General Public License
15 | * along with this program. If not, see .
16 | */
17 |
18 | package com.morlunk.jumble.protocol;
19 |
20 | import com.morlunk.jumble.protobuf.Mumble;
21 |
22 | public interface JumbleTCPMessageListener {
23 | public void messageAuthenticate(Mumble.Authenticate msg);
24 | public void messageBanList(Mumble.BanList msg);
25 | public void messageReject(Mumble.Reject msg);
26 | public void messageServerSync(Mumble.ServerSync msg);
27 | public void messageServerConfig(Mumble.ServerConfig msg);
28 | public void messagePermissionDenied(Mumble.PermissionDenied msg);
29 | public void messageUDPTunnel(Mumble.UDPTunnel msg);
30 | public void messageUserState(Mumble.UserState msg);
31 | public void messageUserRemove(Mumble.UserRemove msg);
32 | public void messageChannelState(Mumble.ChannelState msg);
33 | public void messageChannelRemove(Mumble.ChannelRemove msg);
34 | public void messageTextMessage(Mumble.TextMessage msg);
35 | public void messageACL(Mumble.ACL msg);
36 | public void messageQueryUsers(Mumble.QueryUsers msg);
37 | public void messagePing(Mumble.Ping msg);
38 | public void messageCryptSetup(Mumble.CryptSetup msg);
39 | public void messageContextAction(Mumble.ContextAction msg);
40 | public void messageContextActionModify(Mumble.ContextActionModify msg);
41 | public void messageRemoveContextAction(Mumble.ContextActionModify msg);
42 | public void messageVersion(Mumble.Version msg);
43 | public void messageUserList(Mumble.UserList msg);
44 | public void messagePermissionQuery(Mumble.PermissionQuery msg);
45 | public void messageCodecVersion(Mumble.CodecVersion msg);
46 | public void messageUserStats(Mumble.UserStats msg);
47 | public void messageRequestBlob(Mumble.RequestBlob msg);
48 | public void messageSuggestConfig(Mumble.SuggestConfig msg);
49 | public void messageVoiceTarget(Mumble.VoiceTarget msg);
50 |
51 | /**
52 | * Reads incoming protobuf TCP messages and performs the necessary action(s).
53 | * Designed to be subclassed at any level of the library, the default implementations do nothing.
54 | * Created by andrew on 24/06/13.
55 | */
56 | public static class Stub implements JumbleTCPMessageListener {
57 |
58 | public void messageAuthenticate(Mumble.Authenticate msg) {}
59 | public void messageBanList(Mumble.BanList msg) {}
60 | public void messageReject(Mumble.Reject msg) {}
61 | public void messageServerSync(Mumble.ServerSync msg) {}
62 | public void messageServerConfig(Mumble.ServerConfig msg) {}
63 | public void messagePermissionDenied(Mumble.PermissionDenied msg) {}
64 | public void messageUDPTunnel(Mumble.UDPTunnel msg) {}
65 | public void messageUserState(Mumble.UserState msg) {}
66 | public void messageUserRemove(Mumble.UserRemove msg) {}
67 | public void messageChannelState(Mumble.ChannelState msg) {}
68 | public void messageChannelRemove(Mumble.ChannelRemove msg) {}
69 | public void messageTextMessage(Mumble.TextMessage msg) {}
70 | public void messageACL(Mumble.ACL msg) {}
71 | public void messageQueryUsers(Mumble.QueryUsers msg) {}
72 | public void messagePing(Mumble.Ping msg) {}
73 | public void messageCryptSetup(Mumble.CryptSetup msg) {}
74 | public void messageContextAction(Mumble.ContextAction msg) {}
75 | public void messageContextActionModify(Mumble.ContextActionModify msg) {}
76 | public void messageRemoveContextAction(Mumble.ContextActionModify msg) {}
77 | public void messageVersion(Mumble.Version msg) {}
78 | public void messageUserList(Mumble.UserList msg) {}
79 | public void messagePermissionQuery(Mumble.PermissionQuery msg) {}
80 | public void messageCodecVersion(Mumble.CodecVersion msg) {}
81 | public void messageUserStats(Mumble.UserStats msg) {}
82 | public void messageRequestBlob(Mumble.RequestBlob msg) {}
83 | public void messageSuggestConfig(Mumble.SuggestConfig msg) {}
84 | public void messageVoiceTarget(Mumble.VoiceTarget msg) {}
85 | }
86 | }
--------------------------------------------------------------------------------
/src/main/java/com/morlunk/jumble/model/Message.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2014 Andrew Comminos
3 | *
4 | * This program is free software: you can redistribute it and/or modify
5 | * it under the terms of the GNU General Public License as published by
6 | * the Free Software Foundation, either version 3 of the License, or
7 | * (at your option) any later version.
8 | *
9 | * This program is distributed in the hope that it will be useful,
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | * GNU General Public License for more details.
13 | *
14 | * You should have received a copy of the GNU General Public License
15 | * along with this program. If not, see .
16 | */
17 |
18 | package com.morlunk.jumble.model;
19 |
20 | import android.os.Parcel;
21 | import android.os.Parcelable;
22 | import android.text.format.Time;
23 |
24 | import java.util.ArrayList;
25 | import java.util.Collections;
26 | import java.util.Date;
27 | import java.util.List;
28 |
29 | /**
30 | * A class encapsulating a text message from a Mumble server.
31 | * NOTE: Always prefer using getActorName(). You CANNOT rely on getActor() to provide this info,
32 | * as the actor may no longer be on the server.
33 | * Created by andrew on 03/12/13.
34 | */
35 | public class Message implements IMessage {
36 | private int mActor;
37 | private String mActorName;
38 | private List mChannels;
39 | private List mTrees;
40 | private List mUsers;
41 | private String mMessage;
42 | private long mReceivedTime;
43 |
44 | public Message(String message) {
45 | mMessage = message;
46 | mActor = -1;
47 | mReceivedTime = new Date().getTime();
48 | mChannels = new ArrayList();
49 | mTrees = new ArrayList();
50 | mUsers = new ArrayList();
51 | }
52 |
53 | public Message(int actor, String actorName, List channels, List trees, List users, String message) {
54 | this(message);
55 | mActor = actor;
56 | mActorName = actorName;
57 | mChannels = channels;
58 | mTrees = trees;
59 | mUsers = users;
60 | }
61 | @Override
62 | public int getActor() {
63 | return mActor;
64 | }
65 |
66 | @Override
67 | public String getActorName() {
68 | return mActorName;
69 | }
70 |
71 | @Override
72 | public List getTargetChannels() {
73 | return Collections.unmodifiableList(mChannels);
74 | }
75 |
76 | @Override
77 | public List getTargetTrees() {
78 | return Collections.unmodifiableList(mTrees);
79 | }
80 |
81 | @Override
82 | public List getTargetUsers() {
83 | return Collections.unmodifiableList(mUsers);
84 | }
85 |
86 | @Override
87 | public String getMessage() {
88 | return mMessage;
89 | }
90 |
91 | @Override
92 | public long getReceivedTime() {
93 | return mReceivedTime;
94 | }
95 |
96 | @Override
97 | public boolean equals(Object o) {
98 | if (this == o) return true;
99 | if (o == null || getClass() != o.getClass()) return false;
100 |
101 | Message message = (Message) o;
102 |
103 | if (mActor != message.mActor) return false;
104 | if (mReceivedTime != message.mReceivedTime) return false;
105 | if (mActorName != null ? !mActorName.equals(message.mActorName) : message.mActorName != null)
106 | return false;
107 | if (mChannels != null ? !mChannels.equals(message.mChannels) : message.mChannels != null)
108 | return false;
109 | if (mMessage != null ? !mMessage.equals(message.mMessage) : message.mMessage != null)
110 | return false;
111 | if (mTrees != null ? !mTrees.equals(message.mTrees) : message.mTrees != null) return false;
112 | if (mUsers != null ? !mUsers.equals(message.mUsers) : message.mUsers != null) return false;
113 |
114 | return true;
115 | }
116 |
117 | @Override
118 | public int hashCode() {
119 | int result = mActor;
120 | result = 31 * result + (mActorName != null ? mActorName.hashCode() : 0);
121 | result = 31 * result + (mChannels != null ? mChannels.hashCode() : 0);
122 | result = 31 * result + (mTrees != null ? mTrees.hashCode() : 0);
123 | result = 31 * result + (mUsers != null ? mUsers.hashCode() : 0);
124 | result = 31 * result + (mMessage != null ? mMessage.hashCode() : 0);
125 | result = 31 * result + (int) (mReceivedTime ^ (mReceivedTime >>> 32));
126 | return result;
127 | }
128 |
129 | /**
130 | * The type of message this object represents.
131 | * @deprecated
132 | */
133 | public enum Type {
134 | INFO,
135 | WARNING,
136 | TEXT_MESSAGE
137 | }
138 | }
139 |
--------------------------------------------------------------------------------
/src/main/java/com/morlunk/jumble/audio/javacpp/CELT11.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2014 Andrew Comminos
3 | *
4 | * This program is free software: you can redistribute it and/or modify
5 | * it under the terms of the GNU General Public License as published by
6 | * the Free Software Foundation, either version 3 of the License, or
7 | * (at your option) any later version.
8 | *
9 | * This program is distributed in the hope that it will be useful,
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | * GNU General Public License for more details.
13 | *
14 | * You should have received a copy of the GNU General Public License
15 | * along with this program. If not, see .
16 | */
17 |
18 | package com.morlunk.jumble.audio.javacpp;
19 |
20 | import com.googlecode.javacpp.IntPointer;
21 | import com.googlecode.javacpp.Loader;
22 | import com.googlecode.javacpp.Pointer;
23 | import com.googlecode.javacpp.annotation.Cast;
24 | import com.googlecode.javacpp.annotation.Platform;
25 | import com.morlunk.jumble.audio.IDecoder;
26 | import com.morlunk.jumble.exception.NativeAudioException;
27 | import com.morlunk.jumble.protocol.AudioHandler;
28 |
29 | import java.nio.ByteBuffer;
30 |
31 | /**
32 | * Created by andrew on 20/10/13.
33 | */
34 | @Platform(library="jnicelt11", cinclude={"",""})
35 | public class CELT11 {
36 | public static final int CELT_GET_BITSTREAM_VERSION = 2000;
37 | public static final int CELT_SET_BITRATE_REQUEST = 6;
38 | public static final int CELT_SET_PREDICTION_REQUEST = 4;
39 |
40 | static {
41 | Loader.load();
42 | }
43 |
44 | public static native Pointer celt_mode_create(int sampleRate, int frameSize, IntPointer error);
45 | public static native int celt_mode_info(@Cast("const CELTMode*") Pointer mode, int request, IntPointer value);
46 | public static native void celt_mode_destroy(@Cast("CELTMode*") Pointer mode);
47 |
48 | public static native Pointer celt_decoder_create(int sampleRate, int channels, IntPointer error);
49 | public static native int celt_decode(@Cast("CELTDecoder*") Pointer st, @Cast("const unsigned char*") ByteBuffer data, int len, short[] pcm, int frameSize);
50 | public static native int celt_decode_float(@Cast("CELTDecoder*") Pointer st, @Cast("const unsigned char*") ByteBuffer data, int len, float[] pcm, int frameSize);
51 | public static native int celt_decoder_ctl(@Cast("CELTDecoder*") Pointer st, int request, Pointer val);
52 | public static native void celt_decoder_destroy(@Cast("CELTDecoder*") Pointer st);
53 |
54 | public static native Pointer celt_encoder_create(int sampleRate, int channels, IntPointer error);
55 | public static native int celt_encoder_ctl(@Cast("CELTEncoder*")Pointer state, int request, Pointer val);
56 | public static native int celt_encoder_ctl(@Cast("CELTEncoder*")Pointer state, int request, int val);
57 | public static native int celt_encode(@Cast("CELTEncoder*") Pointer state, @Cast("const short*") short[] pcm, int frameSize, @Cast("unsigned char*") byte[] compressed, int maxCompressedBytes);
58 | public static native void celt_encoder_destroy(@Cast("CELTEncoder*") Pointer state);
59 |
60 | /**
61 | * @return an integer describing the CELT bitstream version.
62 | */
63 | public static int getBitstreamVersion() {
64 | IntPointer versionPtr = new IntPointer();
65 | Pointer modePtr = celt_mode_create(AudioHandler.SAMPLE_RATE, AudioHandler.FRAME_SIZE, null);
66 | celt_mode_info(modePtr, CELT_GET_BITSTREAM_VERSION, versionPtr);
67 | celt_mode_destroy(modePtr);
68 | return versionPtr.get();
69 | }
70 |
71 | public static class CELT11Decoder implements IDecoder {
72 |
73 | private Pointer mState;
74 |
75 | public CELT11Decoder(int sampleRate, int channels) throws NativeAudioException {
76 | IntPointer error = new IntPointer(1);
77 | error.put(0);
78 | mState = celt_decoder_create(sampleRate, channels, error);
79 | if(error.get() < 0) throw new NativeAudioException("CELT 0.11.0 decoder initialization failed with error: "+error.get());
80 | }
81 |
82 | @Override
83 | public int decodeFloat(ByteBuffer input, int inputSize, float[] output, int frameSize) throws NativeAudioException {
84 | int result = celt_decode_float(mState, input, inputSize, output, frameSize);
85 | if(result < 0) throw new NativeAudioException("CELT 0.11.0 decoding failed with error: "+result);
86 | return frameSize;
87 | }
88 |
89 | @Override
90 | public int decodeShort(ByteBuffer input, int inputSize, short[] output, int frameSize) throws NativeAudioException {
91 | int result = celt_decode(mState, input, inputSize, output, frameSize);
92 | if(result < 0) throw new NativeAudioException("CELT 0.11.0 decoding failed with error: "+result);
93 | return frameSize;
94 | }
95 |
96 | @Override
97 | public void destroy() {
98 | celt_decoder_destroy(mState);
99 | }
100 | }
101 | }
--------------------------------------------------------------------------------
/src/main/java/com/morlunk/jumble/audio/javacpp/CELT7.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2014 Andrew Comminos
3 | *
4 | * This program is free software: you can redistribute it and/or modify
5 | * it under the terms of the GNU General Public License as published by
6 | * the Free Software Foundation, either version 3 of the License, or
7 | * (at your option) any later version.
8 | *
9 | * This program is distributed in the hope that it will be useful,
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | * GNU General Public License for more details.
13 | *
14 | * You should have received a copy of the GNU General Public License
15 | * along with this program. If not, see .
16 | */
17 |
18 | package com.morlunk.jumble.audio.javacpp;
19 |
20 | import com.googlecode.javacpp.IntPointer;
21 | import com.googlecode.javacpp.Loader;
22 | import com.googlecode.javacpp.Pointer;
23 | import com.googlecode.javacpp.annotation.Cast;
24 | import com.googlecode.javacpp.annotation.Platform;
25 | import com.morlunk.jumble.audio.IDecoder;
26 | import com.morlunk.jumble.exception.NativeAudioException;
27 | import com.morlunk.jumble.protocol.AudioHandler;
28 |
29 | import java.nio.ByteBuffer;
30 |
31 | /**
32 | * Created by andrew on 20/10/13.
33 | */
34 | @Platform(library="jnicelt7", cinclude={"",""})
35 | public class CELT7 {
36 | public static final int CELT_GET_BITSTREAM_VERSION = 2000;
37 | public static final int CELT_SET_VBR_RATE_REQUEST = 6;
38 | public static final int CELT_SET_PREDICTION_REQUEST = 4;
39 |
40 | static {
41 | Loader.load();
42 | }
43 |
44 | public static native Pointer celt_mode_create(int sampleRate, int frameSize, IntPointer error);
45 | public static native int celt_mode_info(@Cast("const CELTMode*") Pointer mode, int request, IntPointer value);
46 | public static native void celt_mode_destroy(@Cast("CELTMode*") Pointer mode);
47 |
48 | public static native Pointer celt_decoder_create(@Cast("CELTMode*") Pointer mode, int channels, IntPointer error);
49 | public static native int celt_decode(@Cast("CELTDecoder*") Pointer st, @Cast("const unsigned char*") ByteBuffer data, int len, short[] pcm);
50 | public static native int celt_decode_float(@Cast("CELTDecoder*") Pointer st, @Cast("const unsigned char*") ByteBuffer data, int len, float[] pcm);
51 | public static native int celt_decoder_ctl(@Cast("CELTDecoder*") Pointer st, int request, Pointer val);
52 | public static native void celt_decoder_destroy(@Cast("CELTDecoder*") Pointer st);
53 |
54 | public static native Pointer celt_encoder_create(@Cast("const CELTMode *") Pointer mode, int channels, IntPointer error);
55 | public static native int celt_encoder_ctl(@Cast("CELTEncoder*")Pointer state, int request, Pointer val);
56 | public static native int celt_encoder_ctl(@Cast("CELTEncoder*")Pointer state, int request, int val);
57 | public static native int celt_encode(@Cast("CELTEncoder *") Pointer state, @Cast("const short *") short[] pcm, @Cast("short *") short[] optionalSynthesis, @Cast("unsigned char *") byte[] compressed, int nbCompressedBytes);
58 | public static native void celt_encoder_destroy(@Cast("CELTEncoder *") Pointer state);
59 |
60 | /**
61 | * @return an integer describing the CELT bitstream version.
62 | */
63 | public static int getBitstreamVersion() {
64 | IntPointer versionPtr = new IntPointer();
65 | Pointer modePtr = celt_mode_create(AudioHandler.SAMPLE_RATE, AudioHandler.FRAME_SIZE, null);
66 | celt_mode_info(modePtr, CELT_GET_BITSTREAM_VERSION, versionPtr);
67 | celt_mode_destroy(modePtr);
68 | return versionPtr.get();
69 | }
70 |
71 | public static class CELT7Decoder implements IDecoder {
72 |
73 | private Pointer mMode;
74 | private Pointer mState;
75 |
76 | public CELT7Decoder(int sampleRate, int frameSize, int channels) throws NativeAudioException {
77 | IntPointer error = new IntPointer(1);
78 | error.put(0);
79 | mMode = celt_mode_create(sampleRate, frameSize, error);
80 | if(error.get() < 0) throw new NativeAudioException("CELT 0.7.0 decoder initialization failed with error: "+error.get());
81 | mState = celt_decoder_create(mMode, channels, error);
82 | if(error.get() < 0) throw new NativeAudioException("CELT 0.7.0 decoder initialization failed with error: "+error.get());
83 | }
84 |
85 | @Override
86 | public int decodeFloat(ByteBuffer input, int inputSize, float[] output, int frameSize) throws NativeAudioException {
87 | int result = celt_decode_float(mState, input, inputSize, output);
88 | if(result < 0) throw new NativeAudioException("CELT 0.7.0 decoding failed with error: "+result);
89 | return frameSize;
90 | }
91 |
92 | @Override
93 | public int decodeShort(ByteBuffer input, int inputSize, short[] output, int frameSize) throws NativeAudioException {
94 | int result = celt_decode(mState, input, inputSize, output);
95 | if(result < 0) throw new NativeAudioException("CELT 0.7.0 decoding failed with error: "+result);
96 | return frameSize;
97 | }
98 |
99 | @Override
100 | public void destroy() {
101 | celt_decoder_destroy(mState);
102 | celt_mode_destroy(mMode);
103 | }
104 | }
105 | }
106 |
--------------------------------------------------------------------------------
/src/main/jni/celt-0.7.0-build/config.h:
--------------------------------------------------------------------------------
1 | /* config.h. Generated from config.h.in by configure. */
2 | /* config.h.in. Generated from configure.ac by autoheader. */
3 |
4 | /* Define if building universal (internal helper macro) */
5 | /* #undef AC_APPLE_UNIVERSAL_BUILD */
6 |
7 | /* This is a build of CELT */
8 | #define CELT_BUILD /**/
9 |
10 | /* Version extra */
11 | #define CELT_EXTRA_VERSION ""
12 |
13 | /* Version major */
14 | #define CELT_MAJOR_VERSION 0
15 |
16 | /* Version micro */
17 | #define CELT_MICRO_VERSION 0
18 |
19 | /* Version minor */
20 | #define CELT_MINOR_VERSION 7
21 |
22 | /* Complete version string */
23 | #define CELT_VERSION "0.7.0"
24 |
25 | /* Compile as fixed-point */
26 | #define DOUBLE_PRECISION
27 |
28 | /* Assertions */
29 | /* #undef ENABLE_ASSERTIONS */
30 |
31 | /* Debug fixed-point implementation */
32 | /* #undef FIXED_DEBUG */
33 |
34 | /* Compile as fixed-point */
35 | #define FIXED_POINT
36 |
37 | /* Compile as floating-point */
38 | /* #define FLOATING_POINT */
39 |
40 | /* Define to 1 if you have the header file. */
41 | #define HAVE_ALLOCA_H 1
42 |
43 | /* Define to 1 if you have the header file. */
44 | #define HAVE_DLFCN_H 1
45 |
46 | /* Define to 1 if you have the header file. */
47 | #define HAVE_GETOPT_H 1
48 |
49 | /* Define to 1 if you have the `getopt_long' function. */
50 | #define HAVE_GETOPT_LONG 1
51 |
52 | /* Define to 1 if you have the header file. */
53 | #define HAVE_INTTYPES_H 1
54 |
55 | /* Define to 1 if you have the `m' library (-lm). */
56 | #define HAVE_LIBM 1
57 |
58 | /* Define to 1 if you have the `winmm' library (-lwinmm). */
59 | /* #undef HAVE_LIBWINMM */
60 |
61 | /* Define if you have C99's lrint function. */
62 | #define HAVE_LRINT 1
63 |
64 | /* Define if you have C99's lrintf function. */
65 | #define HAVE_LRINTF 1
66 |
67 | /* Define to 1 if you have the header file. */
68 | #define HAVE_MEMORY_H 1
69 |
70 | /* Define to 1 if you have the header file. */
71 | #define HAVE_STDINT_H 1
72 |
73 | /* Define to 1 if you have the header file. */
74 | #define HAVE_STDLIB_H 1
75 |
76 | /* Define to 1 if you have the header file. */
77 | #define HAVE_STRINGS_H 1
78 |
79 | /* Define to 1 if you have the header file. */
80 | #define HAVE_STRING_H 1
81 |
82 | /* Define to 1 if you have the header file. */
83 | /* #undef HAVE_SYS_AUDIOIO_H */
84 |
85 | /* Define to 1 if you have the header file. */
86 | #define HAVE_SYS_SOUNDCARD_H 1
87 |
88 | /* Define to 1 if you have the header file. */
89 | #define HAVE_SYS_STAT_H 1
90 |
91 | /* Define to 1 if you have the header file. */
92 | #define HAVE_SYS_TYPES_H 1
93 |
94 | /* Define to 1 if you have the header file. */
95 | #define HAVE_UNISTD_H 1
96 |
97 | /* Define to the sub-directory in which libtool stores uninstalled
98 | libraries.
99 | */
100 | #define LT_OBJDIR ".libs/"
101 |
102 | /* Compile as fixed-point */
103 | /* #undef MIXED_PRECISION */
104 |
105 | /* Define to the address where bug reports for this package should be
106 | sent. */
107 | #define PACKAGE_BUGREPORT ""
108 |
109 | /* Define to the full name of this package. */
110 | #define PACKAGE_NAME ""
111 |
112 | /* Define to the full name and version of this package. */
113 | #define PACKAGE_STRING ""
114 |
115 | /* Define to the one symbol short name of this package. */
116 | #define PACKAGE_TARNAME ""
117 |
118 | /* Define to the version of this package. */
119 | #define PACKAGE_VERSION ""
120 |
121 | /* The size of `int', as computed by sizeof. */
122 | #define SIZEOF_INT 4
123 |
124 | /* The size of `long', as computed by sizeof. */
125 | #define SIZEOF_LONG 8
126 |
127 | /* The size of `long long', as computed by sizeof. */
128 | #define SIZEOF_LONG_LONG 8
129 |
130 | /* The size of `short', as computed by sizeof. */
131 | #define SIZEOF_SHORT 2
132 |
133 | /* Static modes */
134 | /* #undef STATIC_MODES */
135 |
136 | /* Define to 1 if you have the ANSI C header files. */
137 | #define STDC_HEADERS 1
138 |
139 | /* Make use of alloca */
140 | /* #undef USE_ALLOCA */
141 |
142 | /* Use C99 variable-size arrays */
143 | #define VAR_ARRAYS /**/
144 |
145 | /* Define WORDS_BIGENDIAN to 1 if your processor stores words with the
146 | most
147 | significant byte first (like Motorola and SPARC, unlike Intel). */
148 | #if defined AC_APPLE_UNIVERSAL_BUILD
149 | # if defined __BIG_ENDIAN__
150 | # define WORDS_BIGENDIAN 1
151 | # endif
152 | #else
153 | # ifndef WORDS_BIGENDIAN
154 | /* # undef WORDS_BIGENDIAN */
155 | # endif
156 | #endif
157 |
158 | /* Define to empty if `const' does not conform to ANSI C. */
159 | /* #undef const */
160 |
161 | /* Define to `__inline__' or `__inline' if that's what the C compiler
162 | calls it, or to nothing if 'inline' is not supported under any name.
163 | */
164 | #ifndef __cplusplus
165 | /* #undef inline */
166 | #endif
167 |
168 | /* Define to the equivalent of the C99 'restrict' keyword, or to
169 | nothing if this is not supported. Do not define if restrict is
170 | supported directly. */
171 | #define restrict __restrict
172 | /* Work around a bug in Sun C++: it does not support _Restrict, even
173 | though the corresponding Sun C compiler does, which causes
174 | "#define restrict _Restrict" in the previous line. Perhaps some
175 | future
176 | version of Sun C++ will work with _Restrict; if so, it'll probably
177 | define __RESTRICT, just as Sun C does. */
178 | #if defined __SUNPRO_CC && !defined __RESTRICT
179 | # define _Restrict
180 | #endif
181 |
--------------------------------------------------------------------------------
/src/main/java/com/morlunk/jumble/audio/encoder/OpusEncoder.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2014 Andrew Comminos
3 | *
4 | * This program is free software: you can redistribute it and/or modify
5 | * it under the terms of the GNU General Public License as published by
6 | * the Free Software Foundation, either version 3 of the License, or
7 | * (at your option) any later version.
8 | *
9 | * This program is distributed in the hope that it will be useful,
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | * GNU General Public License for more details.
13 | *
14 | * You should have received a copy of the GNU General Public License
15 | * along with this program. If not, see .
16 | */
17 |
18 | package com.morlunk.jumble.audio.encoder;
19 |
20 | import com.googlecode.javacpp.IntPointer;
21 | import com.googlecode.javacpp.Pointer;
22 | import com.morlunk.jumble.audio.javacpp.Opus;
23 | import com.morlunk.jumble.exception.NativeAudioException;
24 | import com.morlunk.jumble.net.PacketBuffer;
25 |
26 | import java.nio.BufferOverflowException;
27 | import java.nio.BufferUnderflowException;
28 | import java.util.Arrays;
29 |
30 | /**
31 | * Created by andrew on 08/12/14.
32 | */
33 | public class OpusEncoder implements IEncoder {
34 | private final byte[] mBuffer;
35 | private final short[] mAudioBuffer;
36 | private final int mFramesPerPacket;
37 | private final int mFrameSize;
38 |
39 | // Stateful
40 | private int mBufferedFrames;
41 | private int mEncodedLength;
42 | private boolean mTerminated;
43 |
44 | private Pointer mState;
45 |
46 | public OpusEncoder(int sampleRate, int channels, int frameSize, int framesPerPacket,
47 | int bitrate, int maxBufferSize) throws NativeAudioException {
48 | mBuffer = new byte[maxBufferSize];
49 | mAudioBuffer = new short[framesPerPacket * frameSize];
50 | mFramesPerPacket = framesPerPacket;
51 | mFrameSize = frameSize;
52 | mBufferedFrames = 0;
53 | mEncodedLength = 0;
54 | mTerminated = false;
55 |
56 | IntPointer error = new IntPointer(1);
57 | error.put(0);
58 | mState = Opus.opus_encoder_create(sampleRate, channels, Opus.OPUS_APPLICATION_VOIP, error);
59 | if(error.get() < 0) throw new NativeAudioException("Opus encoder initialization failed with error: "+error.get());
60 | Opus.opus_encoder_ctl(mState, Opus.OPUS_SET_VBR_REQUEST, 0);
61 | Opus.opus_encoder_ctl(mState, Opus.OPUS_SET_BITRATE_REQUEST, bitrate);
62 | }
63 |
64 | @Override
65 | public int encode(short[] input, int inputSize) throws NativeAudioException {
66 | if (mBufferedFrames >= mFramesPerPacket) {
67 | throw new BufferOverflowException();
68 | }
69 |
70 | if (inputSize != mFrameSize) {
71 | throw new IllegalArgumentException("This Opus encoder implementation requires a " +
72 | "constant frame size.");
73 | }
74 |
75 | mTerminated = false;
76 | System.arraycopy(input, 0, mAudioBuffer, mFrameSize * mBufferedFrames, mFrameSize);
77 | mBufferedFrames++;
78 |
79 | if (mBufferedFrames == mFramesPerPacket) {
80 | return encode();
81 | }
82 | return 0;
83 | }
84 |
85 | private int encode() throws NativeAudioException {
86 | if (mBufferedFrames < mFramesPerPacket) {
87 | // If encoding is done before enough frames are buffered, fill rest of packet.
88 | Arrays.fill(mAudioBuffer, mFrameSize * mBufferedFrames, mAudioBuffer.length, (short)0);
89 | mBufferedFrames = mFramesPerPacket;
90 | }
91 | int result = Opus.opus_encode(mState, mAudioBuffer, mFrameSize * mBufferedFrames,
92 | mBuffer, mBuffer.length);
93 | if(result < 0) throw new NativeAudioException("Opus encoding failed with error: "
94 | + result);
95 | mEncodedLength = result;
96 | return result;
97 | }
98 |
99 | @Override
100 | public int getBufferedFrames() {
101 | return mBufferedFrames;
102 | }
103 |
104 | @Override
105 | public boolean isReady() {
106 | return mEncodedLength > 0;
107 | }
108 |
109 | @Override
110 | public void getEncodedData(PacketBuffer packetBuffer) throws BufferUnderflowException {
111 | if (!isReady()) {
112 | throw new BufferUnderflowException();
113 | }
114 |
115 | int size = mEncodedLength;
116 | if(mTerminated)
117 | size |= 1 << 13;
118 | packetBuffer.writeLong(size);
119 | packetBuffer.append(mBuffer, mEncodedLength);
120 |
121 | mBufferedFrames = 0;
122 | mEncodedLength = 0;
123 | mTerminated = false;
124 | }
125 |
126 | @Override
127 | public void terminate() throws NativeAudioException {
128 | mTerminated = true;
129 | if (mBufferedFrames > 0 && !isReady()) {
130 | // Perform encode operation on remaining audio if available.
131 | encode();
132 | }
133 | }
134 |
135 | public int getBitrate() {
136 | IntPointer ptr = new IntPointer(1);
137 | Opus.opus_encoder_ctl(mState, Opus.OPUS_GET_BITRATE_REQUEST, ptr);
138 | return ptr.get();
139 | }
140 |
141 | @Override
142 | public void destroy() {
143 | Opus.opus_encoder_destroy(mState);
144 | }
145 | }
146 |
--------------------------------------------------------------------------------
/src/main/java/com/morlunk/jumble/audio/javacpp/Opus.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2014 Andrew Comminos
3 | *
4 | * This program is free software: you can redistribute it and/or modify
5 | * it under the terms of the GNU General Public License as published by
6 | * the Free Software Foundation, either version 3 of the License, or
7 | * (at your option) any later version.
8 | *
9 | * This program is distributed in the hope that it will be useful,
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | * GNU General Public License for more details.
13 | *
14 | * You should have received a copy of the GNU General Public License
15 | * along with this program. If not, see .
16 | */
17 |
18 | package com.morlunk.jumble.audio.javacpp;
19 |
20 | import com.googlecode.javacpp.IntPointer;
21 | import com.googlecode.javacpp.Loader;
22 | import com.googlecode.javacpp.Pointer;
23 | import com.googlecode.javacpp.annotation.Cast;
24 | import com.googlecode.javacpp.annotation.Platform;
25 | import com.morlunk.jumble.audio.IDecoder;
26 | import com.morlunk.jumble.exception.NativeAudioException;
27 |
28 | import java.nio.ByteBuffer;
29 |
30 | /**
31 | * Created by andrew on 18/10/13.
32 | */
33 |
34 | @Platform(library= "jniopus", cinclude={"",""})
35 | public class Opus {
36 | public static final int OPUS_APPLICATION_VOIP = 2048;
37 |
38 | public static final int OPUS_SET_BITRATE_REQUEST = 4002;
39 | public static final int OPUS_GET_BITRATE_REQUEST = 4003;
40 | public static final int OPUS_SET_VBR_REQUEST = 4006;
41 |
42 | public static native int opus_decoder_get_size(int channels);
43 | public static native Pointer opus_decoder_create(int fs, int channels, IntPointer error);
44 | public static native int opus_decoder_init(@Cast("OpusDecoder*") Pointer st, int fs, int channels);
45 | public static native int opus_decode(@Cast("OpusDecoder*") Pointer st, @Cast("const unsigned char*") ByteBuffer data, int len, short[] out, int frameSize, int decodeFec);
46 | public static native int opus_decode_float(@Cast("OpusDecoder*") Pointer st, @Cast("const unsigned char*") ByteBuffer data, int len, float[] out, int frameSize, int decodeFec);
47 | //public static native int opus_decoder_ctl(@Cast("OpusDecoder*") Pointer st, int request);
48 | public static native void opus_decoder_destroy(@Cast("OpusDecoder*") Pointer st);
49 | //public static native int opus_packet_parse(@Cast("const unsigned char*") BytePointer data, int len, ...
50 | public static native int opus_packet_get_bandwidth(@Cast("const unsigned char*") byte[] data);
51 | public static native int opus_packet_get_samples_per_frame(@Cast("const unsigned char*") byte[] data, int fs);
52 | public static native int opus_packet_get_nb_channels(@Cast("const unsigned char*") byte[] data);
53 | public static native int opus_packet_get_nb_frames(@Cast("const unsigned char*") byte[] packet, int len);
54 | public static native int opus_packet_get_nb_samples(@Cast("const unsigned char*") byte[] packet, int len, int fs);
55 |
56 |
57 | public static native int opus_encoder_get_size(int channels);
58 | public static native Pointer opus_encoder_create(int fs, int channels, int application, IntPointer error);
59 | public static native int opus_encoder_init(@Cast("OpusEncoder*") Pointer st, int fs, int channels, int application);
60 | public static native int opus_encode(@Cast("OpusEncoder*") Pointer st, @Cast("const short*") short[] pcm, int frameSize, @Cast("unsigned char*") byte[] data, int maxDataBytes);
61 | public static native int opus_encode_float(@Cast("OpusEncoder*") Pointer st, @Cast("const float*") float[] pcm, int frameSize, @Cast("unsigned char*") byte[] data, int maxDataBytes);
62 | public static native void opus_encoder_destroy(@Cast("OpusEncoder*") Pointer st);
63 | public static native int opus_encoder_ctl(@Cast("OpusEncoder*") Pointer st, int request, Pointer value);
64 | public static native int opus_encoder_ctl(@Cast("OpusEncoder*") Pointer st, int request, @Cast("opus_int32") int value);
65 |
66 | static {
67 | Loader.load();
68 | }
69 |
70 | public static class OpusDecoder implements IDecoder {
71 |
72 | private Pointer mState;
73 |
74 | public OpusDecoder(int sampleRate, int channels) throws NativeAudioException {
75 | IntPointer error = new IntPointer(1);
76 | error.put(0);
77 | mState = opus_decoder_create(sampleRate, channels, error);
78 | if(error.get() < 0) throw new NativeAudioException("Opus decoder initialization failed with error: "+error.get());
79 | }
80 |
81 | @Override
82 | public int decodeFloat(ByteBuffer input, int inputSize, float[] output, int frameSize) throws NativeAudioException {
83 | int result = opus_decode_float(mState, input, inputSize, output, frameSize, 0);
84 | if(result < 0) throw new NativeAudioException("Opus decoding failed with error: "+result);
85 | return result;
86 | }
87 |
88 | @Override
89 | public int decodeShort(ByteBuffer input, int inputSize, short[] output, int frameSize) throws NativeAudioException {
90 | int result = opus_decode(mState, input, inputSize, output, frameSize, 0);
91 | if(result < 0) throw new NativeAudioException("Opus decoding failed with error: "+result);
92 | return result;
93 | }
94 |
95 | @Override
96 | public void destroy() {
97 | opus_decoder_destroy(mState);
98 | }
99 | }
100 | }
101 |
--------------------------------------------------------------------------------
/src/main/jni/celt-0.11.0-build/config.h:
--------------------------------------------------------------------------------
1 | /* config.h. Generated from config.h.in by configure. */
2 | /* config.h.in. Generated from configure.ac by autoheader. */
3 |
4 | /* Define if building universal (internal helper macro) */
5 | /* #undef AC_APPLE_UNIVERSAL_BUILD */
6 |
7 | /* This is a build of CELT */
8 | #define CELT_BUILD /**/
9 |
10 | /* Version extra */
11 | #define CELT_EXTRA_VERSION ""
12 |
13 | /* Version major */
14 | #define CELT_MAJOR_VERSION 0
15 |
16 | /* Version micro */
17 | #define CELT_MICRO_VERSION 0
18 |
19 | /* Version minor */
20 | #define CELT_MINOR_VERSION 11
21 |
22 | /* Complete version string */
23 | #define CELT_VERSION "0.11.0"
24 |
25 | /* Compile as fixed-point */
26 | #define DOUBLE_PRECISION
27 |
28 | /* Assertions */
29 | /* #undef ENABLE_ASSERTIONS */
30 |
31 | /* Postfilter */
32 | /* #undef ENABLE_POSTFILTER */
33 |
34 | /* Debug fixed-point implementation */
35 | /* #undef FIXED_DEBUG */
36 |
37 | /* Compile as fixed-point */
38 | #define FIXED_POINT
39 |
40 | /* Compile as floating-point */
41 | /* #define FLOATING_POINT */
42 |
43 | /* Float approximations */
44 | /* #undef FLOAT_APPROX */
45 |
46 | /* Define to 1 if you have the header file. */
47 | #define HAVE_ALLOCA_H 1
48 |
49 | /* Define to 1 if you have the header file. */
50 | #define HAVE_DLFCN_H 1
51 |
52 | /* Define to 1 if you have the header file. */
53 | #define HAVE_GETOPT_H 1
54 |
55 | /* Define to 1 if you have the `getopt_long' function. */
56 | #define HAVE_GETOPT_LONG 1
57 |
58 | /* Define to 1 if you have the header file. */
59 | #define HAVE_INTTYPES_H 1
60 |
61 | /* Define to 1 if you have the `m' library (-lm). */
62 | #define HAVE_LIBM 1
63 |
64 | /* Define to 1 if you have the `winmm' library (-lwinmm). */
65 | /* #undef HAVE_LIBWINMM */
66 |
67 | /* Define if you have C99's lrint function. */
68 | #define HAVE_LRINT 1
69 |
70 | /* Define if you have C99's lrintf function. */
71 | #define HAVE_LRINTF 1
72 |
73 | /* Define to 1 if you have the header file. */
74 | #define HAVE_MEMORY_H 1
75 |
76 | /* Define to 1 if you have the header file. */
77 | #define HAVE_STDINT_H 1
78 |
79 | /* Define to 1 if you have the header file. */
80 | #define HAVE_STDLIB_H 1
81 |
82 | /* Define to 1 if you have the header file. */
83 | #define HAVE_STRINGS_H 1
84 |
85 | /* Define to 1 if you have the header file. */
86 | #define HAVE_STRING_H 1
87 |
88 | /* Define to 1 if you have the header file. */
89 | /* #undef HAVE_SYS_AUDIOIO_H */
90 |
91 | /* Define to 1 if you have the header file. */
92 | #define HAVE_SYS_SOUNDCARD_H 1
93 |
94 | /* Define to 1 if you have the header file. */
95 | #define HAVE_SYS_STAT_H 1
96 |
97 | /* Define to 1 if you have the header file. */
98 | #define HAVE_SYS_TYPES_H 1
99 |
100 | /* Define to 1 if you have the header file. */
101 | #define HAVE_UNISTD_H 1
102 |
103 | /* Define to the sub-directory in which libtool stores uninstalled libraries.
104 | * */
105 | #define LT_OBJDIR ".libs/"
106 |
107 | /* Compile as fixed-point */
108 | /* #undef MIXED_PRECISION */
109 |
110 | /* Define to the address where bug reports for this package should be sent. */
111 | #define PACKAGE_BUGREPORT ""
112 |
113 | /* Define to the full name of this package. */
114 | #define PACKAGE_NAME ""
115 |
116 | /* Define to the full name and version of this package. */
117 | #define PACKAGE_STRING ""
118 |
119 | /* Define to the one symbol short name of this package. */
120 | #define PACKAGE_TARNAME ""
121 |
122 | /* Define to the version of this package. */
123 | #define PACKAGE_VERSION ""
124 |
125 | /* The size of `int', as computed by sizeof. */
126 | #define SIZEOF_INT 4
127 |
128 | /* The size of `long', as computed by sizeof. */
129 | #define SIZEOF_LONG 8
130 |
131 | /* The size of `long long', as computed by sizeof. */
132 | #define SIZEOF_LONG_LONG 8
133 |
134 | /* The size of `short', as computed by sizeof. */
135 | #define SIZEOF_SHORT 2
136 |
137 | /* Custom modes */
138 | /* #undef CUSTOM_MODES */
139 |
140 | /* Define to 1 if you have the ANSI C header files. */
141 | #define STDC_HEADERS 1
142 |
143 | /* Make use of alloca */
144 | /* #undef USE_ALLOCA */
145 |
146 | /* Use C99 variable-size arrays */
147 | #define VAR_ARRAYS /**/
148 |
149 | /* Define WORDS_BIGENDIAN to 1 if your processor stores words with the most
150 | * significant byte first (like Motorola and SPARC, unlike Intel). */
151 | #if defined AC_APPLE_UNIVERSAL_BUILD
152 | # if defined __BIG_ENDIAN__
153 | # define WORDS_BIGENDIAN 1
154 | # endif
155 | #else
156 | # ifndef WORDS_BIGENDIAN
157 | /* # undef WORDS_BIGENDIAN */
158 | # endif
159 | #endif
160 |
161 | /* Define to empty if `const' does not conform to ANSI C. */
162 | /* #undef const */
163 |
164 | /* Define to `__inline__' or `__inline' if that's what the C compiler
165 | * calls it, or to nothing if 'inline' is not supported under any name. */
166 | #ifndef __cplusplus
167 | /* #undef inline */
168 | #endif
169 |
170 | /* Define to the equivalent of the C99 'restrict' keyword, or to
171 | * nothing if this is not supported. Do not define if restrict is
172 | * supported directly. */
173 | #define restrict __restrict
174 | /* Work around a bug in Sun C++: it does not support _Restrict, even
175 | * though the corresponding Sun C compiler does, which causes
176 | * "#define restrict _Restrict" in the previous line. Perhaps some future
177 | * version of Sun C++ will work with _Restrict; if so, it'll probably
178 | * define __RESTRICT, just as Sun C does. */
179 | #if defined __SUNPRO_CC && !defined __RESTRICT
180 | # define _Restrict
181 | #endif
182 |
--------------------------------------------------------------------------------
/gradlew:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | ##############################################################################
4 | ##
5 | ## Gradle start up script for UN*X
6 | ##
7 | ##############################################################################
8 |
9 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
10 | DEFAULT_JVM_OPTS=""
11 |
12 | APP_NAME="Gradle"
13 | APP_BASE_NAME=`basename "$0"`
14 |
15 | # Use the maximum available, or set MAX_FD != -1 to use that value.
16 | MAX_FD="maximum"
17 |
18 | warn ( ) {
19 | echo "$*"
20 | }
21 |
22 | die ( ) {
23 | echo
24 | echo "$*"
25 | echo
26 | exit 1
27 | }
28 |
29 | # OS specific support (must be 'true' or 'false').
30 | cygwin=false
31 | msys=false
32 | darwin=false
33 | case "`uname`" in
34 | CYGWIN* )
35 | cygwin=true
36 | ;;
37 | Darwin* )
38 | darwin=true
39 | ;;
40 | MINGW* )
41 | msys=true
42 | ;;
43 | esac
44 |
45 | # For Cygwin, ensure paths are in UNIX format before anything is touched.
46 | if $cygwin ; then
47 | [ -n "$JAVA_HOME" ] && JAVA_HOME=`cygpath --unix "$JAVA_HOME"`
48 | fi
49 |
50 | # Attempt to set APP_HOME
51 | # Resolve links: $0 may be a link
52 | PRG="$0"
53 | # Need this for relative symlinks.
54 | while [ -h "$PRG" ] ; do
55 | ls=`ls -ld "$PRG"`
56 | link=`expr "$ls" : '.*-> \(.*\)$'`
57 | if expr "$link" : '/.*' > /dev/null; then
58 | PRG="$link"
59 | else
60 | PRG=`dirname "$PRG"`"/$link"
61 | fi
62 | done
63 | SAVED="`pwd`"
64 | cd "`dirname \"$PRG\"`/" >&-
65 | APP_HOME="`pwd -P`"
66 | cd "$SAVED" >&-
67 |
68 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
69 |
70 | # Determine the Java command to use to start the JVM.
71 | if [ -n "$JAVA_HOME" ] ; then
72 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
73 | # IBM's JDK on AIX uses strange locations for the executables
74 | JAVACMD="$JAVA_HOME/jre/sh/java"
75 | else
76 | JAVACMD="$JAVA_HOME/bin/java"
77 | fi
78 | if [ ! -x "$JAVACMD" ] ; then
79 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
80 |
81 | Please set the JAVA_HOME variable in your environment to match the
82 | location of your Java installation."
83 | fi
84 | else
85 | JAVACMD="java"
86 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
87 |
88 | Please set the JAVA_HOME variable in your environment to match the
89 | location of your Java installation."
90 | fi
91 |
92 | # Increase the maximum file descriptors if we can.
93 | if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then
94 | MAX_FD_LIMIT=`ulimit -H -n`
95 | if [ $? -eq 0 ] ; then
96 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
97 | MAX_FD="$MAX_FD_LIMIT"
98 | fi
99 | ulimit -n $MAX_FD
100 | if [ $? -ne 0 ] ; then
101 | warn "Could not set maximum file descriptor limit: $MAX_FD"
102 | fi
103 | else
104 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
105 | fi
106 | fi
107 |
108 | # For Darwin, add options to specify how the application appears in the dock
109 | if $darwin; then
110 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
111 | fi
112 |
113 | # For Cygwin, switch paths to Windows format before running java
114 | if $cygwin ; then
115 | APP_HOME=`cygpath --path --mixed "$APP_HOME"`
116 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
117 |
118 | # We build the pattern for arguments to be converted via cygpath
119 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
120 | SEP=""
121 | for dir in $ROOTDIRSRAW ; do
122 | ROOTDIRS="$ROOTDIRS$SEP$dir"
123 | SEP="|"
124 | done
125 | OURCYGPATTERN="(^($ROOTDIRS))"
126 | # Add a user-defined pattern to the cygpath arguments
127 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then
128 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
129 | fi
130 | # Now convert the arguments - kludge to limit ourselves to /bin/sh
131 | i=0
132 | for arg in "$@" ; do
133 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
134 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
135 |
136 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
137 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
138 | else
139 | eval `echo args$i`="\"$arg\""
140 | fi
141 | i=$((i+1))
142 | done
143 | case $i in
144 | (0) set -- ;;
145 | (1) set -- "$args0" ;;
146 | (2) set -- "$args0" "$args1" ;;
147 | (3) set -- "$args0" "$args1" "$args2" ;;
148 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
149 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
150 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
151 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
152 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
153 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
154 | esac
155 | fi
156 |
157 | # Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules
158 | function splitJvmOpts() {
159 | JVM_OPTS=("$@")
160 | }
161 | eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS
162 | JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME"
163 |
164 | exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@"
165 |
--------------------------------------------------------------------------------
/src/main/java/com/morlunk/jumble/util/JumbleCallbacks.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2014 Andrew Comminos
3 | *
4 | * This program is free software: you can redistribute it and/or modify
5 | * it under the terms of the GNU General Public License as published by
6 | * the Free Software Foundation, either version 3 of the License, or
7 | * (at your option) any later version.
8 | *
9 | * This program is distributed in the hope that it will be useful,
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | * GNU General Public License for more details.
13 | *
14 | * You should have received a copy of the GNU General Public License
15 | * along with this program. If not, see .
16 | */
17 |
18 | package com.morlunk.jumble.util;
19 |
20 | import com.morlunk.jumble.model.IChannel;
21 | import com.morlunk.jumble.model.IMessage;
22 | import com.morlunk.jumble.model.IUser;
23 |
24 | import org.spongycastle.jcajce.provider.asymmetric.X509;
25 |
26 | import java.security.cert.X509Certificate;
27 | import java.util.Collections;
28 | import java.util.HashSet;
29 | import java.util.Set;
30 | import java.util.concurrent.ConcurrentHashMap;
31 |
32 | /**
33 | * A composite wrapper around Jumble observers to easily broadcast to each observer.
34 | * Created by andrew on 12/07/14.
35 | */
36 | public class JumbleCallbacks implements IJumbleObserver {
37 | private final Set mCallbacks;
38 |
39 | public JumbleCallbacks() {
40 | mCallbacks = Collections.newSetFromMap(new ConcurrentHashMap());
41 | }
42 |
43 | public void registerObserver(IJumbleObserver observer) {
44 | mCallbacks.add(observer);
45 | }
46 |
47 | public void unregisterObserver(IJumbleObserver observer) {
48 | mCallbacks.remove(observer);
49 | }
50 |
51 | @Override
52 | public void onConnected() {
53 | for (IJumbleObserver observer : mCallbacks) {
54 | observer.onConnected();
55 | }
56 | }
57 |
58 | @Override
59 | public void onConnecting() {
60 | for (IJumbleObserver observer : mCallbacks) {
61 | observer.onConnecting();
62 | }
63 | }
64 |
65 | @Override
66 | public void onDisconnected(JumbleException e) {
67 | for (IJumbleObserver observer : mCallbacks) {
68 | observer.onDisconnected(e);
69 | }
70 | }
71 |
72 | @Override
73 | public void onTLSHandshakeFailed(X509Certificate[] chain) {
74 | for (IJumbleObserver observer : mCallbacks) {
75 | observer.onTLSHandshakeFailed(chain);
76 | }
77 | }
78 |
79 | @Override
80 | public void onChannelAdded(IChannel channel) {
81 | for (IJumbleObserver observer : mCallbacks) {
82 | observer.onChannelAdded(channel);
83 | }
84 | }
85 |
86 | @Override
87 | public void onChannelStateUpdated(IChannel channel) {
88 | for (IJumbleObserver observer : mCallbacks) {
89 | observer.onChannelStateUpdated(channel);
90 | }
91 | }
92 |
93 | @Override
94 | public void onChannelRemoved(IChannel channel) {
95 | for (IJumbleObserver observer : mCallbacks) {
96 | observer.onChannelRemoved(channel);
97 | }
98 | }
99 |
100 | @Override
101 | public void onChannelPermissionsUpdated(IChannel channel) {
102 | for (IJumbleObserver observer : mCallbacks) {
103 | observer.onChannelPermissionsUpdated(channel);
104 | }
105 | }
106 |
107 | @Override
108 | public void onUserConnected(IUser user) {
109 | for (IJumbleObserver observer : mCallbacks) {
110 | observer.onUserConnected(user);
111 | }
112 | }
113 |
114 | @Override
115 | public void onUserStateUpdated(IUser user) {
116 | for (IJumbleObserver observer : mCallbacks) {
117 | observer.onUserStateUpdated(user);
118 | }
119 | }
120 |
121 | @Override
122 | public void onUserTalkStateUpdated(IUser user) {
123 | for (IJumbleObserver observer : mCallbacks) {
124 | observer.onUserTalkStateUpdated(user);
125 | }
126 | }
127 |
128 | @Override
129 | public void onUserJoinedChannel(IUser user, IChannel newChannel, IChannel oldChannel) {
130 | for (IJumbleObserver observer : mCallbacks) {
131 | observer.onUserJoinedChannel(user, newChannel, oldChannel);
132 | }
133 | }
134 |
135 | @Override
136 | public void onUserRemoved(IUser user, String reason) {
137 | for (IJumbleObserver observer : mCallbacks) {
138 | observer.onUserRemoved(user, reason);
139 | }
140 | }
141 |
142 | @Override
143 | public void onPermissionDenied(String reason) {
144 | for (IJumbleObserver observer : mCallbacks) {
145 | observer.onPermissionDenied(reason);
146 | }
147 | }
148 |
149 | @Override
150 | public void onMessageLogged(IMessage message) {
151 | for (IJumbleObserver observer : mCallbacks) {
152 | observer.onMessageLogged(message);
153 | }
154 | }
155 |
156 | @Override
157 | public void onVoiceTargetChanged(VoiceTargetMode mode) {
158 | for (IJumbleObserver observer : mCallbacks) {
159 | observer.onVoiceTargetChanged(mode);
160 | }
161 | }
162 |
163 | @Override
164 | public void onLogInfo(String message) {
165 | for (IJumbleObserver observer : mCallbacks) {
166 | observer.onLogInfo(message);
167 | }
168 | }
169 |
170 | @Override
171 | public void onLogWarning(String message) {
172 | for (IJumbleObserver observer : mCallbacks) {
173 | observer.onLogWarning(message);
174 | }
175 | }
176 |
177 | @Override
178 | public void onLogError(String message) {
179 | for (IJumbleObserver observer : mCallbacks) {
180 | observer.onLogError(message);
181 | }
182 | }
183 | }
184 |
--------------------------------------------------------------------------------
/src/main/java/com/morlunk/jumble/net/JumbleSSLSocketFactory.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2014 Andrew Comminos
3 | *
4 | * This program is free software: you can redistribute it and/or modify
5 | * it under the terms of the GNU General Public License as published by
6 | * the Free Software Foundation, either version 3 of the License, or
7 | * (at your option) any later version.
8 | *
9 | * This program is distributed in the hope that it will be useful,
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | * GNU General Public License for more details.
13 | *
14 | * You should have received a copy of the GNU General Public License
15 | * along with this program. If not, see .
16 | */
17 |
18 | package com.morlunk.jumble.net;
19 |
20 | import android.util.Log;
21 |
22 | import com.morlunk.jumble.Constants;
23 |
24 | import java.io.FileInputStream;
25 | import java.io.IOException;
26 | import java.net.InetAddress;
27 | import java.net.InetSocketAddress;
28 | import java.net.Proxy;
29 | import java.net.Socket;
30 | import java.security.KeyManagementException;
31 | import java.security.KeyStore;
32 | import java.security.KeyStoreException;
33 | import java.security.NoSuchAlgorithmException;
34 | import java.security.NoSuchProviderException;
35 | import java.security.UnrecoverableKeyException;
36 | import java.security.cert.CertificateException;
37 | import java.security.cert.X509Certificate;
38 |
39 | import javax.net.ssl.KeyManagerFactory;
40 | import javax.net.ssl.SSLContext;
41 | import javax.net.ssl.SSLSocket;
42 | import javax.net.ssl.TrustManager;
43 | import javax.net.ssl.TrustManagerFactory;
44 | import javax.net.ssl.X509TrustManager;
45 |
46 | public class JumbleSSLSocketFactory {
47 | private SSLContext mContext;
48 | private JumbleTrustManagerWrapper mTrustWrapper;
49 |
50 | public JumbleSSLSocketFactory(KeyStore keystore, String keystorePassword, String trustStorePath, String trustStorePassword, String trustStoreFormat) throws NoSuchAlgorithmException, KeyManagementException, KeyStoreException, UnrecoverableKeyException, NoSuchProviderException, IOException, CertificateException {
51 | mContext = SSLContext.getInstance("TLS");
52 |
53 | KeyManagerFactory kmf = KeyManagerFactory.getInstance("X509");
54 | kmf.init(keystore, keystorePassword != null ? keystorePassword.toCharArray() : new char[0]);
55 |
56 | if(trustStorePath != null) {
57 | KeyStore trustStore = KeyStore.getInstance(trustStoreFormat);
58 | FileInputStream fis = new FileInputStream(trustStorePath);
59 | trustStore.load(fis, trustStorePassword.toCharArray());
60 |
61 | TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
62 | tmf.init(trustStore);
63 | mTrustWrapper = new JumbleTrustManagerWrapper((X509TrustManager) tmf.getTrustManagers()[0]);
64 | Log.i(Constants.TAG, "Using custom trust store " + trustStorePath + " with system trust store");
65 | } else {
66 | mTrustWrapper = new JumbleTrustManagerWrapper(null);
67 | Log.i(Constants.TAG, "Using system trust store");
68 | }
69 |
70 | mContext.init(kmf.getKeyManagers(), new TrustManager[] { mTrustWrapper }, null);
71 | }
72 |
73 | /**
74 | * Creates a new SSLSocket that runs through a SOCKS5 proxy to reach its destination.
75 | */
76 | public SSLSocket createTorSocket(InetAddress host, int port, String proxyHost, int proxyPort) throws IOException {
77 | Proxy proxy = new Proxy(Proxy.Type.SOCKS, new InetSocketAddress(proxyHost, proxyPort));
78 | Socket socket = new Socket(proxy);
79 | socket.connect(new InetSocketAddress(host, port));
80 | return (SSLSocket) mContext.getSocketFactory().createSocket(socket, host.getHostName(), port, true);
81 | }
82 |
83 | public SSLSocket createSocket(InetAddress host, int port) throws IOException {
84 | return (SSLSocket) mContext.getSocketFactory().createSocket(host, port);
85 | }
86 |
87 | /**
88 | * Gets the certificate chain of the remote host.
89 | * @return The remote server's certificate chain, or null if a connection has not reached handshake yet.
90 | */
91 | public X509Certificate[] getServerChain() {
92 | return mTrustWrapper.getServerChain();
93 | }
94 |
95 | /**
96 | * Wraps around a custom trust manager and stores the certificate chains that did not validate.
97 | * We can then send the chain to the user for manual validation.
98 | */
99 | private static class JumbleTrustManagerWrapper implements X509TrustManager {
100 |
101 | private X509TrustManager mDefaultTrustManager;
102 | private X509TrustManager mTrustManager;
103 | private X509Certificate[] mServerChain;
104 |
105 | public JumbleTrustManagerWrapper(X509TrustManager trustManager) throws NoSuchAlgorithmException, KeyStoreException {
106 | TrustManagerFactory dmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
107 | dmf.init((KeyStore) null);
108 | mDefaultTrustManager = (X509TrustManager) dmf.getTrustManagers()[0];
109 | mTrustManager = trustManager;
110 | }
111 |
112 | @Override
113 | public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException {
114 | try {
115 | mDefaultTrustManager.checkClientTrusted(chain, authType);
116 | } catch (CertificateException e) {
117 | if(mTrustManager != null) mTrustManager.checkClientTrusted(chain, authType);
118 | else throw e;
119 | }
120 | }
121 |
122 | @Override
123 | public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException {
124 | mServerChain = chain;
125 | try {
126 | mDefaultTrustManager.checkServerTrusted(chain, authType);
127 | } catch (CertificateException e) {
128 | if(mTrustManager != null) mTrustManager.checkServerTrusted(chain, authType);
129 | else throw e;
130 | }
131 | }
132 |
133 | @Override
134 | public X509Certificate[] getAcceptedIssuers() {
135 | return mDefaultTrustManager.getAcceptedIssuers();
136 | }
137 |
138 | public X509Certificate[] getServerChain() {
139 | return mServerChain;
140 | }
141 | }
142 | }
--------------------------------------------------------------------------------