我尝试用java创建自己的RTP数据包,然后发送了我的数据包 与其他VoIP的RTP数据包一起使用。
问题:
在接收器中,因为我的数据包,我的数据包被检测为数据包丢失 没有序列号系列与VoIP的RTP数据包。
问题:
如何获取模拟rtp数据包的序列号?
答案 0 :(得分:1)
序列号可以在RTP数据包的第3和第4个八位字节中找到。
RTP序列号必须是串联的。如果您尝试将RTP数据包插入另一个应用程序发送的另一个流中,则接收应用程序将检测到无序数据包(如果数字不是串联数据)或重复数据包(如果序列号相同)。在这两种情况下,这很可能会导致数据包丢失。
有关完整详细信息,请参阅RFC 3550(特别是附录A,其中介绍了包括丢包检测在内的算法)
答案 1 :(得分:1)
见下文Mobicents项目的实施。
/ * * JBoss,专业开源之家 *版权所有2011,Red Hat,Inc。和个人贡献者 *由@authors标签。请参阅发行版中的copyright.txt *个人贡献者的完整列表。 * *这是免费软件;您可以重新分发和/或修改它 *根据GNU宽通用公共许可证的条款 *由自由软件基金会出版;版本2.1的 *许可证,或(根据您的选择)任何更新版本。 * *本软件的发布是希望它有用, *但没有任何担保;甚至没有暗示的保证 *适销性或特定用途的适用性。见GNU *更少的通用公共许可证了解更多详情。 * *您应该已收到GNU Lesser General Public的副本 *许可证以及此软件;如果没有,请写信给Free * Software Foundation,Inc.,51 Franklin St,Fifth Floor,Boston,MA * 02110-1301 USA,或查看FSF网站:http://www.fsf.org。 * /
package org.mobicents.media.server.impl.rtp;
import java.io.Serializable; import java.nio.ByteBuffer;
/ ** *由固定RTP头部组成的数据包,可能是空的列表 *贡献源和有效载荷数据。一些基础协议可能 *需要封装要定义的RTP数据包。通常一个 *底层协议的数据包包含一个RTP数据包, *但如果封装允许,则可以包含多个RTP数据包 * 方法 * * @author Oleg Kulikov * @author amit bhayani * / 公共类RtpPacket实现Serializable {
//underlying buffer
private ByteBuffer buffer;
/**
* Creates new instance of RTP packet.
*
* @param capacity the maximum available size for packet.
* @param allocateDirect if false then packet will use backing array to hold
* raw data and if true the direct buffer will be allocated
*/
public RtpPacket(int capacity, boolean allocateDirect) {
buffer = allocateDirect ?
ByteBuffer.allocateDirect(capacity) :
ByteBuffer.allocate(capacity);
}
/**
* Provides access to the underlying buffer.
*
* @return the underlying buffer instance.
*/
protected ByteBuffer getBuffer() {
return buffer;
}
/**
* Verion field.
*
* This field identifies the version of RTP. The version defined by
* this specification is two (2). (The value 1 is used by the first
* draft version of RTP and the value 0 is used by the protocol
* initially implemented in the "vat" audio tool.)
*
* @return the version value.
*/
public int getVersion() {
return (buffer.get(0) & 0xC0) >> 6;
}
/**
* Countributing source field.
*
* The CSRC list identifies the contributing sources for the
* payload contained in this packet. The number of identifiers is
* given by the CC field. If there are more than 15 contributing
* sources, only 15 may be identified. CSRC identifiers areinserted by
* mixers, using the SSRC identifiers of contributing
* sources. For example, for audio packets the SSRC identifiers of
* all sources that were mixed together to create a packet are
* listed, allowing correct talker indication at the receiver.
*
* @return synchronization source.
*/
public int getContributingSource() {
return buffer.get(0) & 0x0F;
}
/**
* Padding indicator.
*
* If the padding bit is set, the packet contains one or more
* additional padding octets at the end which are not part of the
* payload. The last octet of the padding contains a count of how
* many padding octets should be ignored. Padding may be needed by
* some encryption algorithms with fixed block sizes or for
* carrying several RTP packets in a lower-layer protocol data
* unit.
*
* @return true if padding bit set.
*/
public boolean hasPadding() {
return (buffer.get(0) & 0x20) == 0x020;
}
/**
* Extension indicator.
*
* If the extension bit is set, the fixed header is followed by
* exactly one header extension.
*
* @return true if extension bit set.
*/
public boolean hasExtensions() {
return (buffer.get(0) & 0x10) == 0x010;
}
/**
* Marker bit.
*
* The interpretation of the marker is defined by a profile. It is
* intended to allow significant events such as frame boundaries to
* be marked in the packet stream. A profile may define additional
* marker bits or specify that there is no marker bit by changing
* the number of bits in the payload type field
*
* @return true if marker set.
*/
public boolean getMarker() {
return (buffer.get(1) & 0xff & 0x80) == 0x80;
}
/**
* Payload type.
*
* This field identifies the format of the RTP payload and
* determines its interpretation by the application. A profile
* specifies a default static mapping of payload type codes to
* payload formats. Additional payload type codes may be defined
* dynamically through non-RTP means
*
* @return integer value of payload type.
*/
public int getPayloadType() {
return (buffer.get(1) & 0xff & 0x7f);
}
/**
* Sequence number field.
*
* The sequence number increments by one for each RTP data packet
* sent, and may be used by the receiver to detect packet loss and
* to restore packet sequence. The initial value of the sequence
* number is random (unpredictable) to make known-plaintext attacks
* on encryption more difficult, even if the source itself does not
* encrypt, because the packets may flow through a translator that
* does.
*
* @return the sequence number value.
*/
public int getSeqNumber() {
short sn = buffer.getShort(2);
return (sn & 0xffff);
}
/**
* Timestamp field.
*
* The timestamp reflects the sampling instant of the first octet
* in the RTP data packet. The sampling instant must be derived
* from a clock that increments monotonically and linearly in time
* to allow synchronization and jitter calculations.
* The resolution of the clock must be sufficient for the
* desired synchronization accuracy and for measuring packet
* arrival jitter (one tick per video frame is typically not
* sufficient). The clock frequency is dependent on the format of
* data carried as payload and is specified statically in the
* profile or payload format specification that defines the format,
* or may be specified dynamically for payload formats defined
* through non-RTP means. If RTP packets are generated
* periodically, the nominal sampling instant as determined from
* the sampling clock is to be used, not a reading of the system
* clock. As an example, for fixed-rate audio the timestamp clock
* would likely increment by one for each sampling period. If an
* audio application reads blocks covering 160 sampling periods
* from the input device, the timestamp would be increased by 160
* for each such block, regardless of whether the block is
* transmitted in a packet or dropped as silent.
*
* The initial value of the timestamp is random, as for the sequence
* number. Several consecutive RTP packets may have equal timestamps if
* they are (logically) generated at once, e.g., belong to the same
* video frame. Consecutive RTP packets may contain timestamps that are
* not monotonic if the data is not transmitted in the order it was
* sampled, as in the case of MPEG interpolated video frames. (The
* sequence numbers of the packets as transmitted will still be
* monotonic.)
*
* @return timestamp value
*/
public long getTimestamp() {
return ((long)(buffer.get(4) & 0xff) << 24) |
((long)(buffer.get(5) & 0xff) << 16) |
((long)(buffer.get(6) & 0xff) << 8) |
((long)(buffer.get(7) & 0xff));
}
/**
* Synchronization source field.
*
* The SSRC field identifies the synchronization source. This
* identifier is chosen randomly, with the intent that no two
* synchronization sources within the same RTP session will have
* the same SSRC identifier. Although the
* probability of multiple sources choosing the same identifier is
* low, all RTP implementations must be prepared to detect and
* resolve collisions. Section 8 describes the probability of
* collision along with a mechanism for resolving collisions and
* detecting RTP-level forwarding loops based on the uniqueness of
* the SSRC identifier. If a source changes its source transport
* address, it must also choose a new SSRC identifier to avoid
* being interpreted as a looped source.
*
* @return the sysncronization source
*/
public long getSyncSource() {
return ((long)(buffer.get(8) & 0xff) << 24) |
((long)(buffer.get(9) & 0xff) << 16) |
((long)(buffer.get(10) & 0xff) << 8) |
((long)(buffer.get(11) & 0xff));
}
/**
* The number of bytes transmitted by RTP in a packet.
*
* @return the number of bytes.
*/
public int getPayloadLength() {
return buffer.limit() - 12;
}
/**
* Reads the data transported by RTP in a packet, for example
* audio samples or compressed video data.
*
* @param buff the buffer used for reading
* @param offset the initial offset inside buffer.
*/
public void getPayload(byte[] buff, int offset) {
buffer.position(12);
buffer.get(buff, offset, buffer.limit() - 12);
}
/**
* Encapsulates data into the packet for transmission via RTP.
*
* @param mark mark field
* @param payloadType payload type field.
* @param seqNumber sequence number field
* @param timestamp timestamp field
* @param ssrc synchronization source field
* @param data data buffer
* @param offset offset in the data buffer
* @param len the number of bytes
*/
public void wrap(boolean mark, int payloadType, int seqNumber, long timestamp, long ssrc, byte[] data, int offset, int len) {
buffer.clear();
buffer.rewind();
//no extensions, paddings and cc
buffer.put((byte)0x80);
byte b = (byte) (payloadType);
if (mark) {
b = (byte) (b | 0x80);
}
buffer.put(b);
//sequence number
buffer.put((byte) ((seqNumber & 0xFF00) >> 8));
buffer.put((byte) (seqNumber & 0x00FF));
//timestamp
buffer.put((byte) ((timestamp & 0xFF000000) >> 24));
buffer.put((byte) ((timestamp & 0x00FF0000) >> 16));
buffer.put((byte) ((timestamp & 0x0000FF00) >> 8));
buffer.put((byte) ((timestamp & 0x000000FF)));
//ssrc
buffer.put((byte) ((ssrc & 0xFF000000) >> 24));
buffer.put((byte) ((ssrc & 0x00FF0000) >> 16));
buffer.put((byte) ((ssrc & 0x0000FF00) >> 8));
buffer.put((byte) ((ssrc & 0x000000FF)));
buffer.put(data, offset, len);
buffer.flip();
buffer.rewind();
}
@Override
public String toString() {
return "RTP Packet[marker=" + getMarker() + ", seq=" + getSeqNumber() +
", timestamp=" + getTimestamp() + ", payload_size=" + getPayloadLength() +
", payload=" + getPayloadType() + "]";
}
}