java - voip 基础知识 - 数据包的 header 信息?

标签 java udp voip packets

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

我目前正在调查 DatagramPacket 类,我注意到没有方法可以在 DatagramPacket 类中设置 header 信息(即我需要知道的数据包顺序序号,以便进行交错)。

一些反射(reflect)环境的代码:

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,所以发送方除了将数据包扔到某个地方这一简单事实外,并不真正关心任何其他事情。所以这就是为什么里面没有这个方法。

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

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

谢谢你,

最佳答案

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

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

版本 = 2 填充 = 0 扩展 = 0 证监会计数 = 1 标记 = 0 有效负载类型 = 8 (G711 alaw) 序号 = 1234 时间戳 = 1 一个证监会=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);

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

现在,以上当然只是为了展示原理,根据 RTP 规范,RTP 数据包的实际序列化程序必须处理更多(例如,您可能需要一些扩展 header ,您可能需要更多一个 CSRC,您需要根据您拥有的音频数据格式使用正确的有效负载类型,您需要正确打包和安排这些音频数据 - 例如,对于 G.711Alaw,您应该用 160 字节的音频数据填充每个 RTP 数据包每 20 毫秒发送一个数据包。

关于java - voip 基础知识 - 数据包的 header 信息?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9096631/

相关文章:

java - Spring Integration 多个 UDP 入站/出站 channel

android - Twilio Voip session 是否加密?

c++ - 实现 ENUM DNS 查找的库?

java - 使用 JDK8 从本地时区数据库获取 DST 小时

Java 和安卓 : Getting a substring from a string

java - Tomcat 上的 Spring + Hessian

javascript - WebRTC 数据通道服务器到客户端的 UDP 通信。目前可能吗?

c - UDP 套接字设置超时

ios - 如何让 iOS VoIP 应用程序在响铃时服从“请勿打扰”?

java - 创建 jar 文件时注意依赖关系