From 169ee0abb9755efd907c237c49c0cdaa7b191107 Mon Sep 17 00:00:00 2001 From: Andrew Comminos Date: Thu, 28 Apr 2016 19:03:08 -0700 Subject: Initial work on voice target support. --- .../java/com/morlunk/jumble/IJumbleService.java | 31 +++++++++ .../java/com/morlunk/jumble/JumbleService.java | 30 +++++++++ .../com/morlunk/jumble/model/WhisperTarget.java | 27 ++++++++ .../morlunk/jumble/model/WhisperTargetChannel.java | 76 ++++++++++++++++++++++ .../morlunk/jumble/model/WhisperTargetUsers.java | 30 +++++++++ .../com/morlunk/jumble/protocol/AudioHandler.java | 12 ++++ 6 files changed, 206 insertions(+) create mode 100644 src/main/java/com/morlunk/jumble/model/WhisperTarget.java create mode 100644 src/main/java/com/morlunk/jumble/model/WhisperTargetChannel.java create mode 100644 src/main/java/com/morlunk/jumble/model/WhisperTargetUsers.java diff --git a/src/main/java/com/morlunk/jumble/IJumbleService.java b/src/main/java/com/morlunk/jumble/IJumbleService.java index b7be8ed..529e7e6 100644 --- a/src/main/java/com/morlunk/jumble/IJumbleService.java +++ b/src/main/java/com/morlunk/jumble/IJumbleService.java @@ -21,6 +21,7 @@ import com.morlunk.jumble.model.IChannel; import com.morlunk.jumble.model.IUser; import com.morlunk.jumble.model.Message; import com.morlunk.jumble.model.Server; +import com.morlunk.jumble.model.WhisperTarget; import com.morlunk.jumble.net.JumbleUDPMessageType; import com.morlunk.jumble.util.IJumbleObserver; import com.morlunk.jumble.util.JumbleException; @@ -238,4 +239,34 @@ public interface IJumbleService { * @param channel The channel to be unlinked. */ void unlinkAllChannels(IChannel channel); + + /** + * Registers a whisper target to be used as a voice target on the server. + * Note that Mumble only supports a maximum of 30 active voice targets at once. + * @param target The target to register. + * @return A voice target ID in the range [1, 30]. + */ + 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. + */ + void unregisterWhisperTarget(final WhisperTarget target); + + /** + * Sets the active voice target to the provided ID.
+ * 0: Normal speech
+ * 1-30: Whisper targets
+ * 31: Server loopback + * @param targetId A voice target ID in the range [0, 31]. + */ + void setVoiceTarget(byte targetId); + + /** + * Returns the current whisper target. + * @return the set whisper target, or null if the user is not whispering. + */ + WhisperTarget getWhisperTarget(); } diff --git a/src/main/java/com/morlunk/jumble/JumbleService.java b/src/main/java/com/morlunk/jumble/JumbleService.java index cbeb45c..f510ff1 100644 --- a/src/main/java/com/morlunk/jumble/JumbleService.java +++ b/src/main/java/com/morlunk/jumble/JumbleService.java @@ -50,6 +50,7 @@ import com.morlunk.jumble.model.Message; 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.net.JumbleConnection; import com.morlunk.jumble.net.JumbleUDPMessageType; import com.morlunk.jumble.util.IJumbleObserver; @@ -1081,6 +1082,35 @@ 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) { + Mumble.VoiceTarget.Target voiceTarget = target.createTarget(); + Mumble.VoiceTarget.Builder vtb = Mumble.VoiceTarget.newBuilder(); + vtb.setId(1); // TODO: assign free ID. + vtb.addTargets(voiceTarget); + getConnection().sendTCPMessage(vtb.build(), JumbleTCPMessageType.VoiceTarget); + return 1; // FIXME + } + + @Override + public void unregisterWhisperTarget(final WhisperTarget target) { + // TODO + } + + @Override + public void setVoiceTarget(byte targetId) { + if ((targetId & ~0x1F) > 0) { + throw new IllegalArgumentException("Target ID must be at most 5 bits."); + } + // TODO: persist over handler recreation + mAudioHandler.setVoiceTargetId(targetId); + } + /** * The current connection state of the service. */ diff --git a/src/main/java/com/morlunk/jumble/model/WhisperTarget.java b/src/main/java/com/morlunk/jumble/model/WhisperTarget.java new file mode 100644 index 0000000..508c2a0 --- /dev/null +++ b/src/main/java/com/morlunk/jumble/model/WhisperTarget.java @@ -0,0 +1,27 @@ +/* + * Copyright (C) 2016 Andrew Comminos + * + * 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 . + */ + +package com.morlunk.jumble.model; + +import com.morlunk.jumble.protobuf.Mumble; + +/** + * Created by andrew on 28/04/16. + */ +public interface WhisperTarget { + Mumble.VoiceTarget.Target createTarget(); +} \ 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 new file mode 100644 index 0000000..56b805a --- /dev/null +++ b/src/main/java/com/morlunk/jumble/model/WhisperTargetChannel.java @@ -0,0 +1,76 @@ +/* + * Copyright (C) 2016 Andrew Comminos + * + * 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 . + */ + +package com.morlunk.jumble.model; + +import android.os.Parcel; +import android.os.Parcelable; + +import com.morlunk.jumble.protobuf.Mumble; + +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 CREATOR = new Creator() { + @Override + public WhisperTargetChannel createFromParcel(Parcel source) { + return null; + } + + @Override + public WhisperTargetChannel[] newArray(int size) { + return new WhisperTargetChannel[size]; + } + }; + + private final IChannel mChannel; + private final boolean mIncludeLinked; + private final boolean mIncludeSubchannels; + private final String mGroupRestriction; + + public WhisperTargetChannel(final IChannel channel, boolean includeLinked, + boolean includeSubchannels, String groupRestriction) { + mChannel = channel; + mIncludeLinked = includeLinked; + mIncludeSubchannels = includeSubchannels; + mGroupRestriction = groupRestriction; + } + + @Override + public Mumble.VoiceTarget.Target createTarget() { + Mumble.VoiceTarget.Target.Builder vtb = Mumble.VoiceTarget.Target.newBuilder(); + vtb.setLinks(mIncludeLinked); + vtb.setChildren(mIncludeSubchannels); + vtb.setGroup(mGroupRestriction); + vtb.setChannelId(mChannel.getId()); + return vtb.build(); + } + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(Parcel dest, int flags) { + + } +} diff --git a/src/main/java/com/morlunk/jumble/model/WhisperTargetUsers.java b/src/main/java/com/morlunk/jumble/model/WhisperTargetUsers.java new file mode 100644 index 0000000..5bb26a8 --- /dev/null +++ b/src/main/java/com/morlunk/jumble/model/WhisperTargetUsers.java @@ -0,0 +1,30 @@ +/* + * Copyright (C) 2016 Andrew Comminos + * + * 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 . + */ + +package com.morlunk.jumble.model; + +import com.morlunk.jumble.protobuf.Mumble; + +/** + * Created by andrew on 28/04/16. + */ +public class WhisperTargetUsers implements WhisperTarget { + @Override + public Mumble.VoiceTarget.Target createTarget() { + 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 9ec3995..4bd4e79 100644 --- a/src/main/java/com/morlunk/jumble/protocol/AudioHandler.java +++ b/src/main/java/com/morlunk/jumble/protocol/AudioHandler.java @@ -88,6 +88,7 @@ public class AudioHandler extends JumbleNetworkListener implements AudioInput.Au private boolean mTalking; private final Object mEncoderLock; + private byte mTargetId; public AudioHandler(Context context, JumbleLogger logger, int audioStream, int audioSource, int sampleRate, int targetBitrate, int targetFramesPerPacket, @@ -110,6 +111,7 @@ public class AudioHandler extends JumbleNetworkListener implements AudioInput.Au mEncodeListener = encodeListener; mOutputListener = outputListener; mTalking = false; + mTargetId = 0; mAudioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE); mEncoderLock = new Object(); @@ -448,6 +450,15 @@ public class AudioHandler extends JumbleNetworkListener implements AudioInput.Au mTalking = talking; } + public void setVoiceTargetId(byte id) { + mTargetId = id; + } + + public void clearVoiceTarget() { + // A target ID of 0 indicates normal talking. + mTargetId = 0; + } + /** * Fetches the buffered audio from the current encoder and sends it to the server. */ @@ -456,6 +467,7 @@ public class AudioHandler extends JumbleNetworkListener implements AudioInput.Au int flags = 0; flags |= mCodec.ordinal() << 5; + flags |= mTargetId & 0x1F; final byte[] packetBuffer = new byte[1024]; packetBuffer[0] = (byte) (flags & 0xFF); -- cgit v1.2.3