Java voip基础-数据包的报头信息?

Java voip基础-数据包的报头信息?,java,udp,voip,packets,Java,Udp,Voip,Packets,我学习了在小型网络中通过udp使用voip。我知道有很多库可以通过几个方法调用来完成我所需要的一切,但正如我所说的,我正在学习,所以需要重新发明轮子,看看它是如何工作的 我目前正在研究DatagramPacket类,我注意到没有任何方法可以在DatagramPacket类中设置报头信息(即我需要知道的包顺序号来进行交错) 一个反映环境的小代码: byte[] block; DatagramPacket packet; // UDP packet /* x Byt

我学习了在小型网络中通过udp使用voip。我知道有很多库可以通过几个方法调用来完成我所需要的一切,但正如我所说的,我正在学习,所以需要重新发明轮子,看看它是如何工作的

我目前正在研究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个数字。我以前从未真正研究过字节级。或者有其他的技巧

简而言之,要进行交织,我需要知道如何设置数据包序列号,因为我不能订购无序数据包:-)


谢谢,

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

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

版本=2 填充=0 扩展=0 中国证监会计数=1 标记=0 有效负载类型=8(G711 alaw) 序号=1234 时间戳=1 一个=4321

让我们将它们放入一些变量中,为了方便起见,可以使用整数,或者在需要处理无符号32位值时使用long:

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);
int版本=2;
int padding=0;
int扩展=0;
int csrcCount=1;
int标记=0;
int payloadType=8;
int sequenceNumber=1234;
长时间戳=1;
long=4321;
字节buf[]=//分配足够大的空间来容纳RTP头+音频数据
//根据RTP规范组装第一个字节(注意,规范将版本标记为位0和1,但是
//这是第一个字节的高位。。。
buf[0]=(字节)((版本&0x3)24);
buf[5]=(字节)((时间戳&0x00ff0000)>>16);
buf[6]=(字节)((时间戳&0x0000ff00)>>8);
buf[7]=(字节)(时间戳&0x000000ff);
//我们的CSRC,4字节大端格式
buf[8]=(字节)((sequenceNumber&0xff000000)>>24);
buf[9]=(字节)((sequenceNumber&0x00ff0000)>>16);
buf[10]=(字节)((sequenceNumber&0x0000ff00)>>8);
buf[11]=(字节)(sequenceNumber&0x000000ff);
这就是标题,现在您可以将音频字节复制到
buf
,从
buf[12]
开始,并将
buf
作为一个数据包发送


当然,以上只是为了说明原理,根据RTP规范,RTP数据包的实际序列化程序需要处理更多的内容(例如,您可能需要一些扩展标题,您可能需要多个CSC,您需要根据音频数据的格式确定正确的有效负载类型,您需要正确打包和安排这些音频数据-例如,对于g.711Alaw,您应该使用160字节的音频数据填充每个RTP数据包,并每20毫秒发送一个数据包。)ond.

哦,这正是我想要的。要学习和分析的东西太多了,但我现在有了方向,这很重要!谢谢我问博士们关于显示代码的位移位的问题,他们说仅强制转换就足够了。所以如果我可以调用:buf[4]=(byte),我是否严格需要使用你提供的移位sequenceNumber?谢谢。@Aubergine您需要将4字节整数的最高有效字节放入buf[4],而不能通过将整数转换为一个字节来实现。对于最低有效字节,
buf[7]=(字节)时间戳;
就足够了,而不是
buf[7]=(字节)(时间戳&0x000000ff)首先,谢谢。我发现你的回答很有帮助。我有一个问题。为什么要在移位位之前加上和值。例如,为什么
版本&0x3
时间戳&0xff000000
?看起来你在用1来应用位掩码。这不是没有必要吗?或者我遗漏了什么吗?@strwils很多都只是为了可读性和清晰性。
version&0x3
明确表示版本字段仅为2位。
timestamp&0xff000000
明确表示提取的是前8位,仅为
(timestamp>>24)
不会做你想做的事情,因为右移时会有符号扩展。如果需要,你可以在需要的时候很好地优化代码,但通常情况下JIT会处理这些优化,如果你失去了代码的可读性,这是不值得的。