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

gitlab.com/quite/humla.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndrew Comminos <andrew@comminos.com>2016-04-29 23:22:09 +0300
committerAndrew Comminos <andrew@comminos.com>2016-04-30 00:30:29 +0300
commitd2989367e745ca39362bc68a5502adebcaee6499 (patch)
tree3ef25896a04e40ebf1cac8ed987c2bbb9bc4db61
parent169ee0abb9755efd907c237c49c0cdaa7b191107 (diff)
Work on whisper target management.
-rw-r--r--src/main/java/com/morlunk/jumble/IJumbleService.java21
-rw-r--r--src/main/java/com/morlunk/jumble/JumbleService.java59
-rw-r--r--src/main/java/com/morlunk/jumble/model/WhisperTarget.java6
-rw-r--r--src/main/java/com/morlunk/jumble/model/WhisperTargetChannel.java26
-rw-r--r--src/main/java/com/morlunk/jumble/model/WhisperTargetList.java87
-rw-r--r--src/main/java/com/morlunk/jumble/model/WhisperTargetUsers.java5
-rw-r--r--src/main/java/com/morlunk/jumble/protocol/AudioHandler.java8
-rw-r--r--src/main/java/com/morlunk/jumble/util/IJumbleObserver.java2
-rw-r--r--src/main/java/com/morlunk/jumble/util/JumbleCallbacks.java7
-rw-r--r--src/main/java/com/morlunk/jumble/util/JumbleObserver.java5
-rw-r--r--src/main/java/com/morlunk/jumble/util/VoiceTargetMode.java39
11 files changed, 223 insertions, 42 deletions
diff --git a/src/main/java/com/morlunk/jumble/IJumbleService.java b/src/main/java/com/morlunk/jumble/IJumbleService.java
index 529e7e6..90b5d23 100644
--- a/src/main/java/com/morlunk/jumble/IJumbleService.java
+++ b/src/main/java/com/morlunk/jumble/IJumbleService.java
@@ -25,6 +25,7 @@ import com.morlunk.jumble.model.WhisperTarget;
import com.morlunk.jumble.net.JumbleUDPMessageType;
import com.morlunk.jumble.util.IJumbleObserver;
import com.morlunk.jumble.util.JumbleException;
+import com.morlunk.jumble.util.VoiceTargetMode;
import java.util.List;
@@ -244,16 +245,16 @@ public interface IJumbleService {
* Registers a whisper target to be used as a voice target on the server.
* Note that Mumble only supports a maximum of 30 active voice targets at once.
* @param target The target to register.
- * @return A voice target ID in the range [1, 30].
+ * @return A voice target ID in the range [1, 30], or a negative value if all slots are full.
*/
byte registerWhisperTarget(final WhisperTarget target);
/**
* Unregisters a whisper target from the server.
* Note that Mumble only supports a maximum of 30 active voice targets at once.
- * @param target The target to unregister.
+ * @param target The target ID to unregister.
*/
- void unregisterWhisperTarget(final WhisperTarget target);
+ void unregisterWhisperTarget(byte targetId);
/**
* Sets the active voice target to the provided ID.<br>
@@ -262,7 +263,19 @@ public interface IJumbleService {
* 31: Server loopback
* @param targetId A voice target ID in the range [0, 31].
*/
- void setVoiceTarget(byte targetId);
+ void setVoiceTargetId(byte targetId);
+
+ /**
+ * Gets the current voice target ID in use, in the range [0, 31].
+ * @return The active voice target ID.
+ */
+ byte getVoiceTargetId();
+
+ /**
+ * Gets the current voice target mode.
+ * @return The active voice target mode.
+ */
+ VoiceTargetMode getVoiceTargetMode();
/**
* Returns the current whisper target.
diff --git a/src/main/java/com/morlunk/jumble/JumbleService.java b/src/main/java/com/morlunk/jumble/JumbleService.java
index f510ff1..65b5fd5 100644
--- a/src/main/java/com/morlunk/jumble/JumbleService.java
+++ b/src/main/java/com/morlunk/jumble/JumbleService.java
@@ -51,6 +51,7 @@ import com.morlunk.jumble.model.Server;
import com.morlunk.jumble.model.TalkState;
import com.morlunk.jumble.model.User;
import com.morlunk.jumble.model.WhisperTarget;
+import com.morlunk.jumble.model.WhisperTargetList;
import com.morlunk.jumble.net.JumbleConnection;
import com.morlunk.jumble.net.JumbleUDPMessageType;
import com.morlunk.jumble.util.IJumbleObserver;
@@ -61,11 +62,14 @@ import com.morlunk.jumble.protocol.AudioHandler;
import com.morlunk.jumble.protocol.ModelHandler;
import com.morlunk.jumble.util.JumbleCallbacks;
import com.morlunk.jumble.util.JumbleLogger;
+import com.morlunk.jumble.util.VoiceTargetMode;
import java.security.Security;
import java.security.cert.X509Certificate;
import java.util.ArrayList;
+import java.util.Hashtable;
import java.util.List;
+import java.util.Queue;
public class JumbleService extends Service implements IJumbleService, JumbleConnection.JumbleConnectionListener, JumbleLogger, BluetoothScoReceiver.Listener {
@@ -131,6 +135,9 @@ public class JumbleService extends Service implements IJumbleService, JumbleConn
private AudioHandler.Builder mAudioBuilder;
private int mTransmitMode;
+ private byte mVoiceTargetId;
+ private WhisperTargetList mWhisperTargetList;
+
private PowerManager.WakeLock mWakeLock;
private Handler mHandler;
private JumbleCallbacks mCallbacks;
@@ -254,6 +261,7 @@ public class JumbleService extends Service implements IJumbleService, JumbleConn
mToggleInputMode = new ToggleInputMode();
mActivityInputMode = new ActivityInputMode(0); // FIXME: reasonable default
mContinuousInputMode = new ContinuousInputMode();
+ mWhisperTargetList = new WhisperTargetList();
}
@Override
@@ -270,6 +278,8 @@ public class JumbleService extends Service implements IJumbleService, JumbleConn
try {
setReconnecting(false);
mConnectionState = ConnectionState.DISCONNECTED;
+ mVoiceTargetId = 0;
+ mWhisperTargetList.clear();
mConnection = new JumbleConnection(this);
mConnection.setForceTCP(mForceTcp);
@@ -340,7 +350,8 @@ public class JumbleService extends Service implements IJumbleService, JumbleConn
try {
mAudioHandler = mAudioBuilder.initialize(
mModelHandler.getUser(mConnection.getSession()),
- mConnection.getMaxBandwidth(), mConnection.getCodec());
+ mConnection.getMaxBandwidth(), mConnection.getCodec(),
+ mVoiceTargetId);
mConnection.addTCPMessageHandlers(mAudioHandler);
mConnection.addUDPMessageHandlers(mAudioHandler);
} catch (AudioException e) {
@@ -382,6 +393,8 @@ public class JumbleService extends Service implements IJumbleService, JumbleConn
mModelHandler = null;
mAudioHandler = null;
+ mVoiceTargetId = 0;
+ mWhisperTargetList.clear();
// Halt SCO connection on shutdown.
mBluetoothReceiver.stopBluetoothSco();
@@ -467,7 +480,8 @@ public class JumbleService extends Service implements IJumbleService, JumbleConn
try {
mAudioHandler = mAudioBuilder.initialize(
mModelHandler.getUser(mConnection.getSession()),
- mConnection.getMaxBandwidth(), mConnection.getCodec());
+ mConnection.getMaxBandwidth(), mConnection.getCodec(),
+ mVoiceTargetId);
mConnection.addTCPMessageHandlers(mAudioHandler);
mConnection.addUDPMessageHandlers(mAudioHandler);
} catch (NotSynchronizedException e) {
@@ -1082,33 +1096,52 @@ public class JumbleService extends Service implements IJumbleService, JumbleConn
getConnection().sendTCPMessage(csb.build(), JumbleTCPMessageType.ChannelState);
}
- /**
- * Registers a whisper target to an unassigned ID on the server.
- * @param target The whisper target to register.
- * @return A free voice target ID in the range [1, 30].
- */
@Override
public byte registerWhisperTarget(final WhisperTarget target) {
+ byte id = mWhisperTargetList.append(target);
+ if (id < 0) {
+ return -1;
+ }
+
Mumble.VoiceTarget.Target voiceTarget = target.createTarget();
Mumble.VoiceTarget.Builder vtb = Mumble.VoiceTarget.newBuilder();
- vtb.setId(1); // TODO: assign free ID.
+ vtb.setId(id);
vtb.addTargets(voiceTarget);
getConnection().sendTCPMessage(vtb.build(), JumbleTCPMessageType.VoiceTarget);
- return 1; // FIXME
+ return id;
}
@Override
- public void unregisterWhisperTarget(final WhisperTarget target) {
- // TODO
+ public void unregisterWhisperTarget(byte targetId) {
+ mWhisperTargetList.free(targetId);
}
@Override
- public void setVoiceTarget(byte targetId) {
+ public void setVoiceTargetId(byte targetId) {
if ((targetId & ~0x1F) > 0) {
throw new IllegalArgumentException("Target ID must be at most 5 bits.");
}
- // TODO: persist over handler recreation
+ mVoiceTargetId = targetId;
mAudioHandler.setVoiceTargetId(targetId);
+ mCallbacks.onVoiceTargetChanged(VoiceTargetMode.fromId(targetId));
+ }
+
+ @Override
+ public byte getVoiceTargetId() {
+ return mVoiceTargetId;
+ }
+
+ @Override
+ public VoiceTargetMode getVoiceTargetMode() {
+ return VoiceTargetMode.fromId(mVoiceTargetId);
+ }
+
+ @Override
+ public WhisperTarget getWhisperTarget() {
+ if (VoiceTargetMode.fromId(mVoiceTargetId) == VoiceTargetMode.WHISPER) {
+ return mWhisperTargetList.get(mVoiceTargetId);
+ }
+ return null;
}
/**
diff --git a/src/main/java/com/morlunk/jumble/model/WhisperTarget.java b/src/main/java/com/morlunk/jumble/model/WhisperTarget.java
index 508c2a0..91039b3 100644
--- a/src/main/java/com/morlunk/jumble/model/WhisperTarget.java
+++ b/src/main/java/com/morlunk/jumble/model/WhisperTarget.java
@@ -24,4 +24,10 @@ import com.morlunk.jumble.protobuf.Mumble;
*/
public interface WhisperTarget {
Mumble.VoiceTarget.Target createTarget();
+
+ /**
+ * Returns a user-readable name for the whisper target, to display in the UI.
+ * @return A channel name or list of users, depending on the implementation.
+ */
+ String getName();
} \ No newline at end of file
diff --git a/src/main/java/com/morlunk/jumble/model/WhisperTargetChannel.java b/src/main/java/com/morlunk/jumble/model/WhisperTargetChannel.java
index 56b805a..abe41b5 100644
--- a/src/main/java/com/morlunk/jumble/model/WhisperTargetChannel.java
+++ b/src/main/java/com/morlunk/jumble/model/WhisperTargetChannel.java
@@ -28,19 +28,7 @@ import java.util.List;
* An abstraction around a channel whisper target.
* Created by andrew on 28/04/16.
*/
-public class WhisperTargetChannel implements WhisperTarget, Parcelable {
- public static final Parcelable.Creator<WhisperTargetChannel> CREATOR = new Creator<WhisperTargetChannel>() {
- @Override
- public WhisperTargetChannel createFromParcel(Parcel source) {
- return null;
- }
-
- @Override
- public WhisperTargetChannel[] newArray(int size) {
- return new WhisperTargetChannel[size];
- }
- };
-
+public class WhisperTargetChannel implements WhisperTarget {
private final IChannel mChannel;
private final boolean mIncludeLinked;
private final boolean mIncludeSubchannels;
@@ -59,18 +47,14 @@ public class WhisperTargetChannel implements WhisperTarget, Parcelable {
Mumble.VoiceTarget.Target.Builder vtb = Mumble.VoiceTarget.Target.newBuilder();
vtb.setLinks(mIncludeLinked);
vtb.setChildren(mIncludeSubchannels);
- vtb.setGroup(mGroupRestriction);
+ if (mGroupRestriction != null)
+ vtb.setGroup(mGroupRestriction);
vtb.setChannelId(mChannel.getId());
return vtb.build();
}
@Override
- public int describeContents() {
- return 0;
- }
-
- @Override
- public void writeToParcel(Parcel dest, int flags) {
-
+ public String getName() {
+ return mChannel.getName();
}
}
diff --git a/src/main/java/com/morlunk/jumble/model/WhisperTargetList.java b/src/main/java/com/morlunk/jumble/model/WhisperTargetList.java
new file mode 100644
index 0000000..32f5761
--- /dev/null
+++ b/src/main/java/com/morlunk/jumble/model/WhisperTargetList.java
@@ -0,0 +1,87 @@
+/*
+ * Copyright (C) 2016 Andrew Comminos <andrew@comminos.com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package com.morlunk.jumble.model;
+
+import java.util.List;
+
+/**
+ * A simple implementation of a fixed-size whisper target list using a bit vector.
+ * Created by andrew on 29/04/16.
+ */
+public class WhisperTargetList {
+ public static final byte TARGET_MIN = 1;
+ public static final byte TARGET_MAX = 30;
+
+ private final WhisperTarget[] mActiveTargets;
+ // Mumble stores voice targets using a 5-bit identifier.
+ // Use a bit vector to represent this 32-element range.
+ private int mTakenIds;
+
+ public WhisperTargetList() {
+ mActiveTargets = new WhisperTarget[TARGET_MAX - TARGET_MIN + 1];
+ clear();
+ }
+
+ /**
+ * Assigns the target to a slot.
+ * @param target The whisper target to assign.
+ * @return The slot number in range [1, 30].
+ */
+ public byte append(WhisperTarget target) {
+ byte freeId = -1;
+ for (byte i = TARGET_MIN; i < TARGET_MAX; i++) {
+ if ((mTakenIds & (1 << i)) == 0) {
+ freeId = i;
+ break;
+ }
+ }
+ if (freeId != -1) {
+ mActiveTargets[freeId - TARGET_MIN] = target;
+ }
+
+ return freeId;
+ }
+
+ public WhisperTarget get(byte id) {
+ if ((mTakenIds & (1 << id)) > 0)
+ return null;
+ return mActiveTargets[id - TARGET_MIN];
+ }
+
+ public void free(byte slot) {
+ if (slot < TARGET_MIN || slot > TARGET_MAX)
+ throw new IllegalArgumentException();
+
+ mTakenIds &= ~(1 << slot);
+ }
+
+ public int spaceRemaining() {
+ int counter = 0;
+ for (byte i = TARGET_MIN; i < TARGET_MAX; i++) {
+ if ((mTakenIds & (1 << i)) == 0) {
+ counter++;
+ }
+ }
+ return counter;
+ }
+
+ public void clear() {
+ // Slots 0 and 31 are non-whisper targets.
+ mTakenIds = 1 | (1 << 31);
+ }
+}
diff --git a/src/main/java/com/morlunk/jumble/model/WhisperTargetUsers.java b/src/main/java/com/morlunk/jumble/model/WhisperTargetUsers.java
index 5bb26a8..29537c7 100644
--- a/src/main/java/com/morlunk/jumble/model/WhisperTargetUsers.java
+++ b/src/main/java/com/morlunk/jumble/model/WhisperTargetUsers.java
@@ -27,4 +27,9 @@ public class WhisperTargetUsers implements WhisperTarget {
public Mumble.VoiceTarget.Target createTarget() {
throw new UnsupportedOperationException(); // TODO
}
+
+ @Override
+ public String getName() {
+ throw new UnsupportedOperationException(); // TODO
+ }
}
diff --git a/src/main/java/com/morlunk/jumble/protocol/AudioHandler.java b/src/main/java/com/morlunk/jumble/protocol/AudioHandler.java
index 4bd4e79..357d613 100644
--- a/src/main/java/com/morlunk/jumble/protocol/AudioHandler.java
+++ b/src/main/java/com/morlunk/jumble/protocol/AudioHandler.java
@@ -92,7 +92,7 @@ public class AudioHandler extends JumbleNetworkListener implements AudioInput.Au
public AudioHandler(Context context, JumbleLogger logger, int audioStream, int audioSource,
int sampleRate, int targetBitrate, int targetFramesPerPacket,
- IInputMode inputMode, float amplitudeBoost,
+ IInputMode inputMode, byte targetId, float amplitudeBoost,
boolean bluetoothEnabled, boolean halfDuplexEnabled,
boolean preprocessorEnabled, AudioEncodeListener encodeListener,
AudioOutput.AudioOutputListener outputListener) throws AudioInitializationException, NativeAudioException {
@@ -111,7 +111,7 @@ public class AudioHandler extends JumbleNetworkListener implements AudioInput.Au
mEncodeListener = encodeListener;
mOutputListener = outputListener;
mTalking = false;
- mTargetId = 0;
+ mTargetId = targetId;
mAudioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
mEncoderLock = new Object();
@@ -581,9 +581,9 @@ public class AudioHandler extends JumbleNetworkListener implements AudioInput.Au
* Creates a new AudioHandler for the given session and begins managing input/output.
* @return An initialized audio handler.
*/
- public AudioHandler initialize(User self, int maxBandwidth, JumbleUDPMessageType codec) throws AudioException {
+ public AudioHandler initialize(User self, int maxBandwidth, JumbleUDPMessageType codec, byte targetId) throws AudioException {
AudioHandler handler = new AudioHandler(mContext, mLogger, mAudioStream, mAudioSource,
- mInputSampleRate, mTargetBitrate, mTargetFramesPerPacket, mInputMode,
+ mInputSampleRate, mTargetBitrate, mTargetFramesPerPacket, mInputMode, targetId,
mAmplitudeBoost, mBluetoothEnabled, mHalfDuplexEnabled,
mPreprocessorEnabled, mEncodeListener, mTalkingListener);
handler.initialize(self, maxBandwidth, codec);
diff --git a/src/main/java/com/morlunk/jumble/util/IJumbleObserver.java b/src/main/java/com/morlunk/jumble/util/IJumbleObserver.java
index d167da3..f037f16 100644
--- a/src/main/java/com/morlunk/jumble/util/IJumbleObserver.java
+++ b/src/main/java/com/morlunk/jumble/util/IJumbleObserver.java
@@ -57,6 +57,8 @@ public interface IJumbleObserver {
void onMessageLogged(IMessage message);
+ void onVoiceTargetChanged(VoiceTargetMode mode);
+
void onLogInfo(String message);
void onLogWarning(String message);
diff --git a/src/main/java/com/morlunk/jumble/util/JumbleCallbacks.java b/src/main/java/com/morlunk/jumble/util/JumbleCallbacks.java
index 192c98f..5d1aa71 100644
--- a/src/main/java/com/morlunk/jumble/util/JumbleCallbacks.java
+++ b/src/main/java/com/morlunk/jumble/util/JumbleCallbacks.java
@@ -154,6 +154,13 @@ public class JumbleCallbacks implements IJumbleObserver {
}
@Override
+ public void onVoiceTargetChanged(VoiceTargetMode mode) {
+ for (IJumbleObserver observer : mCallbacks) {
+ observer.onVoiceTargetChanged(mode);
+ }
+ }
+
+ @Override
public void onLogInfo(String message) {
for (IJumbleObserver observer : mCallbacks) {
observer.onLogInfo(message);
diff --git a/src/main/java/com/morlunk/jumble/util/JumbleObserver.java b/src/main/java/com/morlunk/jumble/util/JumbleObserver.java
index 91f2751..68c5faf 100644
--- a/src/main/java/com/morlunk/jumble/util/JumbleObserver.java
+++ b/src/main/java/com/morlunk/jumble/util/JumbleObserver.java
@@ -104,6 +104,11 @@ public class JumbleObserver implements IJumbleObserver {
}
@Override
+ public void onVoiceTargetChanged(VoiceTargetMode mode) {
+
+ }
+
+ @Override
public void onLogInfo(String message) {
}
diff --git a/src/main/java/com/morlunk/jumble/util/VoiceTargetMode.java b/src/main/java/com/morlunk/jumble/util/VoiceTargetMode.java
new file mode 100644
index 0000000..6d7eb65
--- /dev/null
+++ b/src/main/java/com/morlunk/jumble/util/VoiceTargetMode.java
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2016 Andrew Comminos <andrew@comminos.com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package com.morlunk.jumble.util;
+
+/**
+ * Created by andrew on 29/04/16.
+ */
+public enum VoiceTargetMode {
+ NORMAL,
+ WHISPER,
+ SERVER_LOOPBACK;
+
+ public static VoiceTargetMode fromId(byte targetId) {
+ if (targetId == 0) {
+ return VoiceTargetMode.NORMAL;
+ } else if (targetId > 0 && targetId < 31) {
+ return VoiceTargetMode.WHISPER;
+ } else if (targetId == 31) {
+ return VoiceTargetMode.SERVER_LOOPBACK;
+ } else {
+ throw new IllegalArgumentException();
+ }
+ }
+}