From 6138838d6098cd942c2c041bf8a3aac335d6a59e Mon Sep 17 00:00:00 2001 From: Denny Date: Wed, 14 Sep 2016 06:07:21 -0400 Subject: [PATCH] #30 - WIP on the shoutcast v2 protocol --- .idea/dictionaries/denny.xml | 1 + src/audio/broadcast/AudioBroadcastModel.java | 2 - .../BroadcastConfiguration.java | 2 +- .../BroadcastConfigurationFactory.java | 4 +- .../{configuration => }/BroadcastFormat.java | 2 +- .../{handler => }/BroadcastHandler.java | 3 +- .../BroadcastMetadata.java | 2 +- .../BroadcastServerType.java | 2 +- .../{handler => }/BroadcastState.java | 2 +- src/audio/broadcast/Broadcaster.java | 3 - src/audio/broadcast/BroadcasterFactory.java | 6 +- .../v1}/ShoutcastV1Configuration.java | 6 +- .../v1}/ShoutcastV1Handler.java | 9 +- .../v2}/ShoutcastV2Configuration.java | 6 +- .../shoutcast/v2/UltravoxMessage.java | 157 ++++++++++++++++++ .../shoutcast/v2/UltravoxMessageClass.java | 57 +++++++ .../shoutcast/v2/UltravoxMessageType.java} | 33 ++-- src/bits/BinaryMessage.java | 44 ++++- 18 files changed, 302 insertions(+), 39 deletions(-) rename src/audio/broadcast/{configuration => }/BroadcastConfiguration.java (98%) rename src/audio/broadcast/{configuration => }/BroadcastConfigurationFactory.java (93%) rename src/audio/broadcast/{configuration => }/BroadcastFormat.java (96%) rename src/audio/broadcast/{handler => }/BroadcastHandler.java (97%) rename src/audio/broadcast/{configuration => }/BroadcastMetadata.java (98%) rename src/audio/broadcast/{configuration => }/BroadcastServerType.java (96%) rename src/audio/broadcast/{handler => }/BroadcastState.java (98%) rename src/audio/broadcast/{configuration => shoutcast/v1}/ShoutcastV1Configuration.java (94%) rename src/audio/broadcast/{handler => shoutcast/v1}/ShoutcastV1Handler.java (98%) rename src/audio/broadcast/{configuration => shoutcast/v2}/ShoutcastV2Configuration.java (95%) create mode 100644 src/audio/broadcast/shoutcast/v2/UltravoxMessage.java create mode 100644 src/audio/broadcast/shoutcast/v2/UltravoxMessageClass.java rename src/audio/{stream/shout/channel/ShoutChannel.java => broadcast/shoutcast/v2/UltravoxMessageType.java} (63%) diff --git a/.idea/dictionaries/denny.xml b/.idea/dictionaries/denny.xml index 0df9f405..39329f5c 100644 --- a/.idea/dictionaries/denny.xml +++ b/.idea/dictionaries/denny.xml @@ -9,6 +9,7 @@ shoutcast talkgroup tgid + ultravox \ No newline at end of file diff --git a/src/audio/broadcast/AudioBroadcastModel.java b/src/audio/broadcast/AudioBroadcastModel.java index b5819cf7..292e7ba8 100644 --- a/src/audio/broadcast/AudioBroadcastModel.java +++ b/src/audio/broadcast/AudioBroadcastModel.java @@ -18,8 +18,6 @@ ******************************************************************************/ package audio.broadcast; -import audio.broadcast.configuration.BroadcastConfiguration; - import javax.swing.table.AbstractTableModel; import java.util.ArrayList; import java.util.List; diff --git a/src/audio/broadcast/configuration/BroadcastConfiguration.java b/src/audio/broadcast/BroadcastConfiguration.java similarity index 98% rename from src/audio/broadcast/configuration/BroadcastConfiguration.java rename to src/audio/broadcast/BroadcastConfiguration.java index 2044b727..bdcf5d23 100644 --- a/src/audio/broadcast/configuration/BroadcastConfiguration.java +++ b/src/audio/broadcast/BroadcastConfiguration.java @@ -16,7 +16,7 @@ * along with this program. If not, see * ******************************************************************************/ -package audio.broadcast.configuration; +package audio.broadcast; import java.net.InetSocketAddress; import java.net.SocketAddress; diff --git a/src/audio/broadcast/configuration/BroadcastConfigurationFactory.java b/src/audio/broadcast/BroadcastConfigurationFactory.java similarity index 93% rename from src/audio/broadcast/configuration/BroadcastConfigurationFactory.java rename to src/audio/broadcast/BroadcastConfigurationFactory.java index 91bec018..9578e000 100644 --- a/src/audio/broadcast/configuration/BroadcastConfigurationFactory.java +++ b/src/audio/broadcast/BroadcastConfigurationFactory.java @@ -16,7 +16,9 @@ * along with this program. If not, see * ******************************************************************************/ -package audio.broadcast.configuration; +package audio.broadcast; + +import audio.broadcast.shoutcast.v1.ShoutcastV1Configuration; public class BroadcastConfigurationFactory { diff --git a/src/audio/broadcast/configuration/BroadcastFormat.java b/src/audio/broadcast/BroadcastFormat.java similarity index 96% rename from src/audio/broadcast/configuration/BroadcastFormat.java rename to src/audio/broadcast/BroadcastFormat.java index 25f97f37..f6aeacf2 100644 --- a/src/audio/broadcast/configuration/BroadcastFormat.java +++ b/src/audio/broadcast/BroadcastFormat.java @@ -16,7 +16,7 @@ * along with this program. If not, see * ******************************************************************************/ -package audio.broadcast.configuration; +package audio.broadcast; public enum BroadcastFormat { diff --git a/src/audio/broadcast/handler/BroadcastHandler.java b/src/audio/broadcast/BroadcastHandler.java similarity index 97% rename from src/audio/broadcast/handler/BroadcastHandler.java rename to src/audio/broadcast/BroadcastHandler.java index 8b3e33df..1f337c86 100644 --- a/src/audio/broadcast/handler/BroadcastHandler.java +++ b/src/audio/broadcast/BroadcastHandler.java @@ -16,10 +16,9 @@ * along with this program. If not, see * ******************************************************************************/ -package audio.broadcast.handler; +package audio.broadcast; import audio.AudioPacket; -import audio.broadcast.configuration.BroadcastConfiguration; import audio.convert.IAudioConverter; import org.slf4j.Logger; import org.slf4j.LoggerFactory; diff --git a/src/audio/broadcast/configuration/BroadcastMetadata.java b/src/audio/broadcast/BroadcastMetadata.java similarity index 98% rename from src/audio/broadcast/configuration/BroadcastMetadata.java rename to src/audio/broadcast/BroadcastMetadata.java index 917e7fb2..aa83c94b 100644 --- a/src/audio/broadcast/configuration/BroadcastMetadata.java +++ b/src/audio/broadcast/BroadcastMetadata.java @@ -16,7 +16,7 @@ * along with this program. If not, see * ******************************************************************************/ -package audio.broadcast.configuration; +package audio.broadcast; public enum BroadcastMetadata { diff --git a/src/audio/broadcast/configuration/BroadcastServerType.java b/src/audio/broadcast/BroadcastServerType.java similarity index 96% rename from src/audio/broadcast/configuration/BroadcastServerType.java rename to src/audio/broadcast/BroadcastServerType.java index c5c26d52..a8abe393 100644 --- a/src/audio/broadcast/configuration/BroadcastServerType.java +++ b/src/audio/broadcast/BroadcastServerType.java @@ -16,7 +16,7 @@ * along with this program. If not, see * ******************************************************************************/ -package audio.broadcast.configuration; +package audio.broadcast; public enum BroadcastServerType { diff --git a/src/audio/broadcast/handler/BroadcastState.java b/src/audio/broadcast/BroadcastState.java similarity index 98% rename from src/audio/broadcast/handler/BroadcastState.java rename to src/audio/broadcast/BroadcastState.java index ee9bb432..818b8553 100644 --- a/src/audio/broadcast/handler/BroadcastState.java +++ b/src/audio/broadcast/BroadcastState.java @@ -16,7 +16,7 @@ * along with this program. If not, see * ******************************************************************************/ -package audio.broadcast.handler; +package audio.broadcast; public enum BroadcastState { diff --git a/src/audio/broadcast/Broadcaster.java b/src/audio/broadcast/Broadcaster.java index 7e107969..ad6b99c5 100644 --- a/src/audio/broadcast/Broadcaster.java +++ b/src/audio/broadcast/Broadcaster.java @@ -20,9 +20,6 @@ package audio.broadcast; import audio.AudioPacket; import audio.IAudioPacketListener; -import audio.broadcast.configuration.BroadcastConfiguration; -import audio.broadcast.handler.BroadcastHandler; -import audio.broadcast.handler.BroadcastState; import controller.ThreadPoolManager; import org.slf4j.Logger; import org.slf4j.LoggerFactory; diff --git a/src/audio/broadcast/BroadcasterFactory.java b/src/audio/broadcast/BroadcasterFactory.java index ce13702e..91f1f260 100644 --- a/src/audio/broadcast/BroadcasterFactory.java +++ b/src/audio/broadcast/BroadcasterFactory.java @@ -18,10 +18,8 @@ ******************************************************************************/ package audio.broadcast; -import audio.broadcast.configuration.BroadcastConfiguration; -import audio.broadcast.configuration.BroadcastFormat; -import audio.broadcast.configuration.ShoutcastV1Configuration; -import audio.broadcast.handler.ShoutcastV1Handler; +import audio.broadcast.shoutcast.v1.ShoutcastV1Configuration; +import audio.broadcast.shoutcast.v1.ShoutcastV1Handler; import audio.convert.IAudioConverter; import audio.convert.MP3AudioConverter; import controller.ThreadPoolManager; diff --git a/src/audio/broadcast/configuration/ShoutcastV1Configuration.java b/src/audio/broadcast/shoutcast/v1/ShoutcastV1Configuration.java similarity index 94% rename from src/audio/broadcast/configuration/ShoutcastV1Configuration.java rename to src/audio/broadcast/shoutcast/v1/ShoutcastV1Configuration.java index 0a00d641..3f5ac417 100644 --- a/src/audio/broadcast/configuration/ShoutcastV1Configuration.java +++ b/src/audio/broadcast/shoutcast/v1/ShoutcastV1Configuration.java @@ -16,7 +16,11 @@ * along with this program. If not, see * ******************************************************************************/ -package audio.broadcast.configuration; +package audio.broadcast.shoutcast.v1; + +import audio.broadcast.BroadcastConfiguration; +import audio.broadcast.BroadcastFormat; +import audio.broadcast.BroadcastServerType; public class ShoutcastV1Configuration extends BroadcastConfiguration { diff --git a/src/audio/broadcast/handler/ShoutcastV1Handler.java b/src/audio/broadcast/shoutcast/v1/ShoutcastV1Handler.java similarity index 98% rename from src/audio/broadcast/handler/ShoutcastV1Handler.java rename to src/audio/broadcast/shoutcast/v1/ShoutcastV1Handler.java index ab01bd93..7e4d0dcc 100644 --- a/src/audio/broadcast/handler/ShoutcastV1Handler.java +++ b/src/audio/broadcast/shoutcast/v1/ShoutcastV1Handler.java @@ -16,14 +16,15 @@ * along with this program. If not, see * ******************************************************************************/ -package audio.broadcast.handler; +package audio.broadcast.shoutcast.v1; import audio.AudioPacket; import audio.broadcast.Broadcaster; import audio.broadcast.BroadcasterFactory; -import audio.broadcast.configuration.BroadcastFormat; -import audio.broadcast.configuration.BroadcastMetadata; -import audio.broadcast.configuration.ShoutcastV1Configuration; +import audio.broadcast.BroadcastFormat; +import audio.broadcast.BroadcastMetadata; +import audio.broadcast.BroadcastHandler; +import audio.broadcast.BroadcastState; import audio.convert.IAudioConverter; import controller.ThreadPoolManager; import org.slf4j.Logger; diff --git a/src/audio/broadcast/configuration/ShoutcastV2Configuration.java b/src/audio/broadcast/shoutcast/v2/ShoutcastV2Configuration.java similarity index 95% rename from src/audio/broadcast/configuration/ShoutcastV2Configuration.java rename to src/audio/broadcast/shoutcast/v2/ShoutcastV2Configuration.java index f92f13ca..f42fd780 100644 --- a/src/audio/broadcast/configuration/ShoutcastV2Configuration.java +++ b/src/audio/broadcast/shoutcast/v2/ShoutcastV2Configuration.java @@ -16,7 +16,11 @@ * along with this program. If not, see * ******************************************************************************/ -package audio.broadcast.configuration; +package audio.broadcast.shoutcast.v2; + +import audio.broadcast.BroadcastConfiguration; +import audio.broadcast.BroadcastFormat; +import audio.broadcast.BroadcastServerType; public class ShoutcastV2Configuration extends BroadcastConfiguration { diff --git a/src/audio/broadcast/shoutcast/v2/UltravoxMessage.java b/src/audio/broadcast/shoutcast/v2/UltravoxMessage.java new file mode 100644 index 00000000..f9c94f68 --- /dev/null +++ b/src/audio/broadcast/shoutcast/v2/UltravoxMessage.java @@ -0,0 +1,157 @@ +/******************************************************************************* + * sdrtrunk + * Copyright (C) 2014-2016 Dennis Sheirer + * + * 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 audio.broadcast.shoutcast.v2; + +import bits.BinaryMessage; +import com.sun.org.apache.regexp.internal.RE; + +public abstract class UltravoxMessage +{ + public static final int[] SYNC = {0,1,2,3,4,5,6,7}; + public static final int[] RESERVED = {8,9,10,11}; + public static final int REQUIRED_DELIVERY = 12; + public static final int[] SEND_QUEUE_PRIORITY = {13,14,15}; + public static final int[] MESSAGE_CLASS = {16,17,18,19}; + public static final int[] MESSAGE_CLASS_AND_TYPE = {16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31}; + public static final int[] PAYLOAD_LENGTH = {32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47}; + + private BinaryMessage mMessage; + + /** + * Constructs a message from the byte array + */ + public UltravoxMessage(byte[] data) + { + mMessage = new BinaryMessage(data); + } + + /** + * Constructs an empty message of the specified length + * + * @param ultravoxMessageType type of message + * @param length of message in bits (64 minimum) + */ + public UltravoxMessage(UltravoxMessageType ultravoxMessageType, int length) + { + assert(length >= 64); + + mMessage = new BinaryMessage(length); + + setSync(); + setMessageType(ultravoxMessageType); + } + + /** + * Sets the message sync bits to the predefined sync pattern: 01011010 (0x5A) + */ + private void setSync() + { + mMessage.setInt(0x5A, SYNC); + } + + /** + * Ultravox message class + */ + public UltravoxMessageClass getMessageClass() + { + return UltravoxMessageClass.fromValue(mMessage.getInt(MESSAGE_CLASS)); + } + + /** + * Ultravox message type + * @return + */ + public UltravoxMessageType getMessageType() + { + return UltravoxMessageType.fromValue(mMessage.getInt(MESSAGE_CLASS_AND_TYPE)); + } + + /** + * Sets the message bits according to the message class and type + * @param messageType of ultravox message + */ + private void setMessageType(UltravoxMessageType messageType) + { + mMessage.setInt(messageType.getValue(), MESSAGE_CLASS_AND_TYPE); + } + + /** + * Indicates if this message has the required delivery flag set + */ + public boolean isRequiredDelivery() + { + return mMessage.get(REQUIRED_DELIVERY); + } + + /** + * Sets the required delivery flag according to the argument + */ + public void setRequiredDelivery(boolean required) + { + if(required) + { + mMessage.set(REQUIRED_DELIVERY); + } + else + { + mMessage.clear(REQUIRED_DELIVERY); + } + } + + /** + * Send queue priority (0 - 7) for this message + */ + public int getSendQueuePriority() + { + return mMessage.getInt(SEND_QUEUE_PRIORITY); + } + + /** + * Sets send queue priority for this message + * @param priority 0 - 7 + */ + public void setSendQueuePriority(int priority) + { + assert(0 <= priority && priority <= 7); + + mMessage.setInt(priority, SEND_QUEUE_PRIORITY); + } + + /** + * Message payload + */ + public String getPayload() + { + //TODO: parse payload field + return null; + } + + /** + * Sets the message payload, updates the message length field, and appends a trailing 0x00 byte after the payload. + */ + public void setPayload(String payload) + { + //TODO: implement payload, along with trailing 0x00 byte and update overall payload size field. + } + + private void setPayloadLength(int length) + { + //TODO: correctly size the message to payload + 1 byte and set the payload length field + } +} diff --git a/src/audio/broadcast/shoutcast/v2/UltravoxMessageClass.java b/src/audio/broadcast/shoutcast/v2/UltravoxMessageClass.java new file mode 100644 index 00000000..dd7d2572 --- /dev/null +++ b/src/audio/broadcast/shoutcast/v2/UltravoxMessageClass.java @@ -0,0 +1,57 @@ +/******************************************************************************* + * sdrtrunk + * Copyright (C) 2014-2016 Dennis Sheirer + * + * 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 audio.broadcast.shoutcast.v2; + +public enum UltravoxMessageClass +{ + OPERATIONS(0x0), + BROADCASTER(0x1), + LISTENER(0x2), + CACHEABLE_METADATA_1(0x3), + CACHEABLE_METADATA_2(0x4), + PASS_THROUGH_METADATA_1(0x5), + PASS_THROUGH_METADATA_2(0x6), + ENCODED_DATA(0x7), + ADVANCED_ENCODED_DATA(0x8), + FRAMED_DATA(0x9), + CACHEABLE_BINARY_METADATA(0xA), + UNKNOWN(0xF); + + private int mValue; + + private UltravoxMessageClass(int value) + { + mValue = value; + } + + public int getValue() + { + return mValue; + } + + public static UltravoxMessageClass fromValue(int value) + { + if(0x0 <= value && value <= 0xA) + { + return values()[value]; + } + + return UNKNOWN; + } +} diff --git a/src/audio/stream/shout/channel/ShoutChannel.java b/src/audio/broadcast/shoutcast/v2/UltravoxMessageType.java similarity index 63% rename from src/audio/stream/shout/channel/ShoutChannel.java rename to src/audio/broadcast/shoutcast/v2/UltravoxMessageType.java index 9b5901c3..62f9151c 100644 --- a/src/audio/stream/shout/channel/ShoutChannel.java +++ b/src/audio/broadcast/shoutcast/v2/UltravoxMessageType.java @@ -16,23 +16,34 @@ * along with this program. If not, see * ******************************************************************************/ -package audio.stream.shout.channel; +package audio.broadcast.shoutcast.v2; -import audio.stream.shout.source.IShoutSource; - -public class ShoutChannel +public enum UltravoxMessageType { - private String mName; - private IShoutSource mShoutSource; + AUTHENTICATE_BROADCAST(0x1001), - public ShoutChannel(String name, IShoutSource shoutSource) + UNKNOWN(0x0000); + + private int mValue; + + private UltravoxMessageType(int value) { - mName = name; - mShoutSource = shoutSource; + mValue = value; } - public String getName() + public int getValue() { - return mName; + return mValue; + } + + public static UltravoxMessageType fromValue(int value) + { + switch(value) + { + case 0x1001: + return AUTHENTICATE_BROADCAST; + default: + return UNKNOWN; + } } } diff --git a/src/bits/BinaryMessage.java b/src/bits/BinaryMessage.java index 66b9463e..b9ae1570 100644 --- a/src/bits/BinaryMessage.java +++ b/src/bits/BinaryMessage.java @@ -18,6 +18,7 @@ package bits; import java.util.BitSet; +import java.util.logging.LogManager; import edac.CRC; @@ -103,6 +104,11 @@ public class BinaryMessage extends BitSet this.or( bitset ); this.mPointer = size - 1; } + + public BinaryMessage(byte[] data) + { + this(BitSet.valueOf(data), data.length * 8); + } /** * Returns a mew binary message containing the bits from (inclusive) to @@ -367,7 +373,24 @@ public class BinaryMessage extends BitSet return value; } - + + public void setInt(int value, int[] indices) + { + for(int x = 0; x < indices.length; x++) + { + int mask = 1<<(indices.length - x - 1); + + if((value & mask) == mask) + { + set(indices[x]); + } + else + { + clear(indices[x]); + } + } + } + /** * Returns the byte value represented by the bit array * @param bits - an array of bit positions that will be treated as if they @@ -601,11 +624,11 @@ public class BinaryMessage extends BitSet } /** - * Loads the value into the buffer starting at the offset index, and + * Loads the value into the buffer starting at the offset index, and * assuming that the value represents (width) number of bits. The MSB of - * the value will be located at the offset and the LSB of the value will + * the value will be located at the offset and the LSB of the value will * be located at ( offset + width ). - * + * * @param offset - starting bit index for the MSB of the value * @param width - representative bit width of the value * @param value - value to be loaded into the buffer @@ -626,7 +649,7 @@ public class BinaryMessage extends BitSet } } } - + /** * Generates an array of message bit position indexes to support accessing * a contiguous field value @@ -775,4 +798,15 @@ public class BinaryMessage extends BitSet this.xor( mask ); } + + public static void main(String[] args) + { + BinaryMessage b = new BinaryMessage(32); + + int[] indices = {2,3,7,8}; + + b.setInt(0xF, indices); + + System.out.println(b.toString()); + } }