tags:

views:

420

answers:

5

Hey all!

For part of a project I'm working on I am implementing a RTPpacket where I have to fill the header array of byte with RTP header fields.

  //size of the RTP header:
  static int HEADER_SIZE = 12; // bytes

  //Fields that compose the RTP header
  public int Version; // 2 bits
  public int Padding; // 1 bit
  public int Extension; // 1 bit
  public int CC; // 4 bits
  public int Marker; // 1 bit
  public int PayloadType; // 7 bits
  public int SequenceNumber; // 16 bits
  public int TimeStamp; // 32 bits
  public int Ssrc; // 32 bits

  //Bitstream of the RTP header
  public byte[] header = new byte[ HEADER_SIZE ];

This was my approach:

/*      
 * bits 0-1: Version
 * bit    2: Padding 
 * bit    3: Extension
 * bits 4-7: CC
 */
header[0] = new Integer( (Version << 6)|(Padding << 5)|(Extension << 6)|CC ).byteValue();

/* 
 * bit    0: Marker
 * bits 1-7: PayloadType
 */
header[1] = new Integer( (Marker << 7)|PayloadType ).byteValue();

/* SequenceNumber takes 2 bytes = 16 bits */
header[2] = new Integer( SequenceNumber >> 8 ).byteValue();
header[3] = new Integer( SequenceNumber ).byteValue();

/* TimeStamp takes 4 bytes = 32 bits */
for ( int i = 0; i < 4; i++ )
    header[7-i] = new Integer( TimeStamp >> (8*i) ).byteValue();

/* Ssrc takes 4 bytes = 32 bits */
for ( int i = 0; i < 4; i++ )
    header[11-i] = new Integer( Ssrc >> (8*i) ).byteValue();

Any other, maybe 'better' ways to do this?

+1  A: 

You can convert an int directly to a byte in Java, without having to create an Integer object. An explicit cast is required, because a byte has a narrower range of possible values than an int. For instance:

header[1] = (byte) (Marker << 7 | PayloadType);
Syntactic
A: 

There is one problem with such data. Usually protocols use unsigned bytes there and Java has signed bytes. So, for correct byte array fill I usually use such construct:

bytearray[index] = (byte) ((some integer-result calculation) & 0xff);

Simple casting to byte type won't work correctly.

Update. "& 0xff" is not needed here. Simple cast will work.

Alexander Babaev
Really?Have a look at the source code for `Integer#byteValue()`: /** * Returns the value of this <code>Integer</code> as a * <code>byte</code>. */ public byte byteValue() { return (byte)value; }
rhu
Alexander Babaev
+2  A: 

I think I would use a ByteBuffer

ByteBuffer buf = ByteBuffer.wrap(header);
buf.setOrder(ByteOrder.BIG_ENDIAN);
buf.put((byte)((Version << 6)|(Padding << 5)|(Extension << 6)|CC));
buf.put((byte)((Marker << 7)|PayloadType));
buf.put((short)SequenceNumber);
buf.put(TimeStamp);
buf.put(Ssrc);
Maurice Perry
A: 

in addition to the presented answers give a try to Preon

dfa
A: 

With Preon, the RtpHeader could be represented like this:

public class RtpHeader {

    @BoundNumber(size = "2")
    public int version;

    @Bound
    public boolean padding;

    @Bound
    public boolean extension;

    @BoundNumber(size="4")
    public int csrcCount;

    @Bound
    public boolean marker;

    @BoundNumber(size="7")
    public int payloadType;

    @BoundNumber(size="16", byteOrder = ByteOrder.BigEndian)
    public int sequenceNumber;

    @BoundNumber(size="32", byteOrder = ByteOrder.BigEndian)
    public int timestamp;

    @BoundNumber(size="32", byteOrder = ByteOrder.BigEndian)
    public int synchronizationSource;

    @BoundList(size="csrcCount")
    public int[] csrcs; 

}

Encoding this to bytes could be as simple as this:

    Codec<RtpHeader> codec = Codecs.create(RtpHeader.class);
    RtpHeader header = new RtpHeader();
    ... // Setting header values
    OutputStream out = ...;
    Codecs.encode(header, codec, out);

However, bear in mind that encoding in Preon is still in early stages. It seems to work, for this particular case, but I am not going to make any guarantees.

The benefit of using Preon is obviously the fact that you don't have to bother writing all of the encoding and decoding logic yourself.

Wilfred Springer