/*******************************************************************************
* 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 <http://www.gnu.org/licenses/>
*
******************************************************************************/
package audio.broadcast.shoutcast.v2.ultravox;
import bits.BinaryMessage;
import org.apache.commons.lang3.Validate;
import java.util.Arrays;
public abstract class UltravoxMessage
{
public static final String ULTRAVOX_VERSION = "2.1";
public static final String VALID_RESPONSE_PREFIX = "ACK";
public static final String VALID_RESPONSE_PAYLOAD_PREFIX = "ACK:";
public static final String ERROR_RESPONSE_PREFIX = "NAK:";
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 ultravox from the byte array
*/
public UltravoxMessage(byte[] data)
{
mMessage = new BinaryMessage(data.length * 8);
int pointer = 0;
for(byte b: data)
{
mMessage.setByte(pointer, b);
pointer += 8;
}
}
/**
* Constructs an empty ultravox of the specified length
*
* @param ultravoxMessageType type of ultravox
*/
public UltravoxMessage(UltravoxMessageType ultravoxMessageType)
{
mMessage = new BinaryMessage(56);
setSync();
setMessageType(ultravoxMessageType);
}
/**
* Message byte array
*
* @return ultravox bytes
*/
public byte[] getMessage()
{
return mMessage.toByteArray();
}
public String toString()
{
return getMessageType().name();
}
/**
* Sets the ultravox sync bits to the predefined sync pattern: 01011010 (0x5A)
*/
private void setSync()
{
mMessage.setInt(0x5A, SYNC);
}
/**
* Ultravox ultravox class
*/
public UltravoxMessageClass getMessageClass()
{
return UltravoxMessageClass.fromValue(mMessage.getInt(MESSAGE_CLASS));
}
/**
* Ultravox ultravox type
* @return
*/
public UltravoxMessageType getMessageType()
{
return UltravoxMessageType.fromValue(mMessage.getInt(MESSAGE_CLASS_AND_TYPE));
}
/**
* Sets the ultravox bits according to the ultravox class and type
* @param messageType of ultravox ultravox
*/
private void setMessageType(UltravoxMessageType messageType)
{
mMessage.setInt(messageType.getValue(), MESSAGE_CLASS_AND_TYPE);
}
/**
* Indicates if this ultravox 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 ultravox
*/
public int getSendQueuePriority()
{
return mMessage.getInt(SEND_QUEUE_PRIORITY);
}
/**
* Sets send queue priority for this ultravox
* @param priority 0 - 7
*/
public void setSendQueuePriority(int priority)
{
Validate.isTrue(0 <= priority && priority <= 7);
mMessage.setInt(priority, SEND_QUEUE_PRIORITY);
}
/**
* Message payload
*/
public String getPayload()
{
int payloadLength = mMessage.getInt(PAYLOAD_LENGTH);
byte[] payload = new byte[payloadLength];
int payloadPointer = 48;
for(int x = 0; x < payloadLength; x++)
{
payload[x] = mMessage.getByte(payloadPointer);
payloadPointer += 8;
}
//Strip the trailing 0x00 null value from a server response
if(payload[payload.length - 1] == 0)
{
return new String(Arrays.copyOf(payload, payload.length - 1));
}
return new String(payload);
}
/**
* Sets the ultravox payload, updates the ultravox length field, and appends a trailing 0x00 byte after the payload.
*/
public void setPayload(String payload)
{
setPayload(payload.getBytes());
}
public void setPayload(byte[] payload)
{
int messageBitLength = (7 + payload.length) * 8;
mMessage.setSize(messageBitLength);
mMessage.setInt(payload.length, PAYLOAD_LENGTH);
int payloadPointer = 48;
for(byte payloadByte: payload)
{
mMessage.setByte(payloadPointer, payloadByte);
payloadPointer += 8;
}
mMessage.setByte(payloadPointer, (byte)0x00);
}
/**
* Indicates if the response is a valid (ie non-error) response
*/
public boolean isValidResponse()
{
String payload = getPayload();
return payload != null && payload.startsWith(VALID_RESPONSE_PREFIX);
}
/**
* Indicates if the response message contains an error message.
*/
public boolean isErrorResponse()
{
String payload = getPayload();
return payload != null && payload.startsWith(ERROR_RESPONSE_PREFIX);
}
/**
* Textual message available when the error response flag is set.
*/
public String getErrorMessage()
{
String payload = getPayload();
if(payload != null)
{
return payload.replace(ERROR_RESPONSE_PREFIX, "");
}
return null;
}
}