voip基础知识 - 数据包的标题信息?

时间:2012-02-01 13:32:23

标签: java udp voip packets

我在小网络中学习使用voip over udp。我知道有一些库可以做,并且通过一些方法调用可以满足我所需要的一切,但正如我所说,我正在学习,所以需要重新发明轮子以了解它是如何工作的。

我正在调查DatagramPacket类,我注意到没有方法可以在DatagramPacket类中设置标头信息(即我需要知道的用于交错的包顺序序列号)。

反映环境的小代码:

byte[] block;
DatagramPacket packet; // UDP packet                

/* x Bytes per block , y blocks per second,
   z ms time block playback duration */

block = recorder.getBlock(); // assume I have class that handles audio
                              // recording and returns speech in a
                              // uncompressed form of bytes

packet = new DatagramPacket(block, block.length, clientIP, PORT);

首先,我假设因为它是UDP,除了他在某处抛出数据包的简单事实之外,发送者并不真正关心任何事情。所以这就是为什么里面没有这样的方法。

其次,我假设我需要自己做 - 在要发送的字节块中添加额外的字节,这将包含数据包的序列号?但是我也担心如果我这样做,那么我如何识别字节是字节字节而不是音频字节?我可以假设第一个字节代表一个数字,但我们知道该字节只能代表258个数字。我以前从未在字节级别上工作过。或者可能有其他技术?

简而言之,要做交错,我需要知道如何设置数据包序列号,因为我无法订购无序数据包:-)

谢谢,

1 个答案:

答案 0 :(得分:6)

您需要将程序使用的数据类型序列化/反序列化为字节数组。

让我们假设您正在谈论RTP,并且您想要发送包含这些字段的数据包 - 请参阅RTP规范中的第5章:

版本= 2 padding = 0 extension = 0 证监会的人数= 1 marker = 0 有效载荷类型= 8(G711 alaw) 序号= 1234 时间戳= 1 一个CSRC = 4321

让我们把它们放到一些变量中,使用整数来轻松,或者在需要处理无符号32位值时使用很长时间:

int version = 2;
int padding = 0;
int extension = 0;
int csrcCount = 1;
int marker = 0;
int payloadType = 8;
int sequenceNumber = 1234;
long timestamp = 1;
long ourCsrc = 4321;

byte buf[] = ...; //allocate this big enough to hold the RTP header + audio data

//assemble the first bytes according to the RTP spec (note, the spec marks version as bit 0 and 1, but
//this is really the high bits of the first byte ...
buf[0] = (byte) ((version & 0x3) << 6 | (padding & 0x1) << 5 | (extension & 0x1) << 4 | (csrcCount & 0xf));

//2.byte
buf[1] = (byte)((marker & 0x1) << 7 | payloadType & 0x7f);

//squence number, 2 bytes, in big endian format. So the MSB first, then the LSB.
buf[2] = (byte)((sequenceNumber & 0xff00) >> 8);
buf[3] = (byte)(sequenceNumber  & 0x00ff);

//packet timestamp , 4 bytes in big endian format
buf[4] = (byte)((timestamp & 0xff000000) >> 24);
buf[5] = (byte)((timestamp & 0x00ff0000) >> 16);
buf[6] = (byte)((timestamp & 0x0000ff00) >> 8);
buf[7] = (byte) (timestamp & 0x000000ff);
//our CSRC , 4 bytes in big endian format
buf[ 8] = (byte)((sequenceNumber & 0xff000000) >> 24);
buf[ 9] = (byte)((sequenceNumber & 0x00ff0000) >> 16);
buf[10] = (byte)((sequenceNumber & 0x0000ff00) >> 8);
buf[11] = (byte) (sequenceNumber & 0x000000ff);

这是标题,现在您可以将音频字节复制到buf,从buf[12]开始,并将buf作为一个数据包发送。

现在,上面只是为了说明原理,根据RTP规范,RTP数据包的实际串行器必须处理更多(例如,您可能需要一些扩展头,您可能需要更多一个CSRC,你需要根据你拥有的音频数据的格式正确的有效载荷类型,你需要打包并正确安排这些音频数据 - 例如对于G.711Alaw你应该用160字节的音频数据填充每个RTP数据包并且每20毫秒发送一个数据包。