0

Java を使用して独自の RTP パケットを作成しようとしましたが、他の VoIP の RTP パケットと一緒にパケットを送信しました。

問題 :

受信側で、私のパケットは VoIP の RTP パケットのシーケンス番号系列を持っていなかったため、パケット損失として検出されました。

質問:

シミュレートされた rtp パケットの一連のシーケンス番号を取得するにはどうすればよいですか?

4

2 に答える 2

1

シーケンス番号は、RTP パケットの 3 番目と 4 番目のオクテットにあります。

RTP シーケンス番号は連続している必要があります。別のアプリケーションから送信された別のストリームに RTP パケットを挿入しようとすると、受信側のアプリケーションは、順序が正しくないパケット (番号が連続していない場合) または重複したパケット (シーケンス番号が同じ場合) を検出します。どちらの場合も、パケットがドロップされる可能性が高くなります。

詳細については、RFC 3550 を参照してください (具体的には、パケット損失検出を含むアルゴリズムを説明する付録 A)。

于 2013-04-08T06:42:53.723 に答える
1

以下の Mobicents プロジェクトの実装を参照してください。

/*
 * JBoss, Home of Professional Open Source
 * Copyright 2011, Red Hat, Inc. and individual contributors
 * by the @authors tag. See the copyright.txt in the distribution for a
 * full listing of individual contributors.
 *
 * This is free software; you can redistribute it and/or modify it
 * under the terms of the GNU Lesser General Public License as
 * published by the Free Software Foundation; either version 2.1 of
 * the License, or (at your option) any later version.
 *
 * This software is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this software; if not, write to the Free
 * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
 * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
 */

package org.mobicents.media.server.impl.rtp;

import java.io.Serializable;
import java.nio.ByteBuffer;

/**
 * A data packet consisting of the fixed RTP header, a possibly empty list of
 * contributing sources, and the payload data. Some underlying protocols may
 * require an encapsulation of the RTP packet to be defined. Typically one
 * packet of the underlying protocol contains a single RTP packet,
 * but several RTP packets may be contained if permitted by the encapsulation
 * method
 *
 * @author Oleg Kulikov
 * @author amit bhayani
 */
public class RtpPacket implements 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() + "]";
    }

}
于 2013-04-21T15:43:27.920 に答える