2012-02-01 68 views
3

我做了一些关于在小型网络中使用voip over 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个数字。我从来没有真正在字节级别上工作过。或者还有其他技术?

不久说,做交错,我需要知道如何设置数据包的序列号,因为我不能为了无序的数据包:-)

谢谢你,

回答

6

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

让我们假设你在谈论RTP,和你想发送具有这些领域 - 看第5章在RTP规格:

版本= 2 填充= 0 延长= 0 CSRC计数= 1 标记= 0 有效载荷类型= 8(G711阿劳) 序列号= 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数据包的实际串行器将不得不处理更多的事情(例如,您可能需要一些扩展头,您可能需要更多根据您所拥有的音频数据的格式,您需要正确的有效负载类型,您需要正确打包和调度这些音频数据 - 例如,对于G.711Alaw,您应该为每个RTP数据包填充160个字节的音频数据和每20毫秒发送一个数据包

+0

哦,这就是我正在寻找的东西,这么多的学习和分析,但我现在有方向,这是非常重要的,谢谢 – Aubergine 2012-02-01 17:17:23

+0

我问博士们有关位移的显示你的代码他们说单独铸造就够了。所以如果我可以调用,我必须严格使用你提供的移位:buf [4] =(byte)sequenceNumber?谢谢。 – Aubergine 2012-02-06 16:56:07

+0

@Aubergine您需要将4字节整数的最高有效字节放入buf [4]中,并且您无法通过将整型转换为字节来完成此操作。对于最低有效字节,'buf [7] =(byte)timestamp;'就足够了,而不是buf [7] =(byte)(timestamp&0x000000ff);' – nos 2012-02-07 08:04:33