在SIP对讲机中RTP/RTCP的实现

  1. 云栖社区>
  2. 博客>
  3. 正文

在SIP对讲机中RTP/RTCP的实现

长征2号 2018-01-21 12:29:53 浏览2007
展开阅读全文

       RTP/RTCP的定义及用途,还是请大家自己google。对于wifi手机来说呢,RTP协议用来传送编码后的语音,RTCP协议用来传送控制信息,公司的RTCP附带了一些语音统计信息和jitter buffer的统计信息用来防止语音抖动。由于是公司的东西,我就不细说了。下面是这两个协议的具体实现代码:
        RTP和RTCP的头部信息如下,一会给出详细的字节图和编码过程。
        RTP的头部信息:

 
复制代码
  1.   typedef struct _RTP_HEAD
    {
        unsigned char    Version        : 2;
        unsigned char    Padding        : 1;
        unsigned char    Extension    : 1;
        unsigned char    Ccount        : 4;
        unsigned char    Marker        : 1;
        unsigned char    Ptype        : 7;
        WORD            Snumber;        //16bits
        DWORD            Timestamp;        //32
        DWORD            Ssrc;            //32
        DWORD            Csrc;            //32
    }RTP_HEAD,*pRTP_HEAD;


        RTCP的头部信息:

 
复制代码
  1. typedef struct _RTCP_HEAD
    {
        unsigned char    Version        : 2;
        unsigned char    Padding        : 1;
        unsigned char    PCount        : 5;
        unsigned char    Ptype;            //8bits
        WORD            Length;            //16bits
    }RTCP_HEAD,*pRTCP_HEAD;


        里面各个bit位表示的意思老规矩,不懂google之。
        具体实现呢,不能给出公司的代码,只能给出尽量通用一些的代码,程序员对比bit图和程序源代码应该很容易就能理解:
        RTP的bit图和代码实现:

 
复制代码
  1. //     0                   1                   2                   3
    //     0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
    //    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    //  0 |V=2|P|X|  CC   |M|     PT      |       sequence number         |
    //    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    //  4 |                           timestamp                           |
    //    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    //  8 |           synchronization source (SSRC) identifier            |
    //    +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
    // 12 |                        payload header                         |
    //    |                             ....                              |
    //    +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
    //    |                           payload                             |
    //    |                             ....                              |
    //    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 
    void RTPCompose( string& buffer,
                      int payloadType, int sequenceNum, int timestamp, int ssrc,
                      const char* payloadHeader, int payloadHeaderLength,
                      const char* payload, int payloadLength )
    {
            ASSERT( payload && payloadLength >= 0 );
            buffer.resize( 12 + payloadHeaderLength + payloadLength );
                         buffer[0]  = (char)(2<<6);                //  v=2, p=x=cc=0
                         buffer[1]  = (char)(payloadType & 0x127); // 7-bits for payload type
           *((unsigned short*)&buffer[2]) = (unsigned short)sequenceNum;
           *((unsigned int*)&buffer[4]) = (unsigned int)timestamp;
           *((unsigned int*)&buffer[8]) = (unsigned int)ssrc;
           memcpy( &buffer[12], payloadHeader, payloadHeaderLength );
           memcpy( &buffer[12+payloadHeaderLength], payload, payloadLength );
    }


        解码是编码的逆过程俺就不罗嗦了。
        RTCP的bit图和代码实现:

 
复制代码
  1. //        0                   1                   2                   3
    //        0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
    //       +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    //byte=0 |V=2|P|    RC   |   PT=SR=200   |             length            |
    //       +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    //     4 |                         SSRC of sender                        |
    //       +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
    //     8 |              NTP timestamp, most significant word             |
    //       +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    //    12 |             NTP timestamp, least significant word             |
    //       +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    //    16 |                         RTP timestamp                         |
    //       +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    //    20 |                     sender's packet count                     |
    //       +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    //    24 |                      sender's octet count                     |
    //       +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
    //    28 |V=2|P|    SC   |  PT=SDES=202  |             length            |
    //       +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
    //    32 |                          SSRC/CSRC_1                          |
    //       +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    //    36 |    CNAME=1    |     length    | user and domain name        ...
    //       +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    void RTCPSRCompose( string& buffer,
                         int receptionCount, int ssrc, int64 ntpTimestamp, int rtpTimestamp,
                         int sentPackets, int sentBytes,
                         const wstring& cname )
    {
           const string& cnameUTF8 = ConvertToUTF8( cname );
           int length = 8 + 20 + 4 + 6 + cnameUTF8.size( ); // 注意此处可能存在bug。
                        buffer.resize( length );
                        buffer[0]  = (char)(2<<6);                              //  V=2,  P=RC=0
                        buffer[1]  = (char)200;                                 // PT=SR=200
       *(unsigned short*)&buffer[2]  = 6;                                         // length (7 32-bit words, minus one)
       *(unsigned int*)&buffer[4]  = (unsigned int)ssrc;
       *(unsigned int*)&buffer[8]  = (unsigned int)(ntpTimestamp >> 32);        // High 32-bits
       *(unsigned int*)&buffer[12] = (unsigned int)(ntpTimestamp & 0xFFFFFFFF); // Low 32-bits
       *(unsigned int*)&buffer[16] = (unsigned int)rtpTimestamp;
       *(unsigned int*)&buffer[20] = (unsigned int)sentPackets;
       *(unsigned int*)&buffer[24] = (unsigned int)sentBytes;
                               buffer[28] = (char)(2<<6 & 1);                          //  V=2, P=0, SC=1
       *(unsigned short*)&buffer[30] = 0xFFFF;                                    // 注意这里应该填写长度,由于我们并没有数据因此无法填写。请程序员按自己的
                                                                                                     包长自己填写。
       *(unsigned int*)&buffer[32] = (unsigned int)ssrc;
                        buffer[36] = 1;                                         // CNAME=1
                        buffer[37] = (char)cnameUTF8.size( );
         memcpy( &buffer[38], cnameUTF8.c_str( ), cnameUTF8.size( ) );              // 同理此处请程序员自己填写
    }


    以上是较为简单的实现。实际应用中必然需要填写自己附加的信息。实际上这个项目的代码均为在linux下用纯c写的代码,而我上传得代码为windows 下的c++代码。由于c++中Cstring类的存在,使RTP/RTCP的代码简化了不少。如果是在linux下编程的朋友稍加修改后,即可使用。此处仅仅只是给出RTP/RTCP的一个最简单和相对比较通用的实现而已。
    最后当然要唠叨一下TBCP突发通话消息如何通过RTCP包传送,很简单,将上面RTCP包中的RC项由subtype代替。其它按上一篇讲解的携带 TBCP消息的RTCP包的标准编写就可以了。注意,这个标准是别人定的,如果觉得不好,自己定一个也是可以的。这样就要编写自己的服务器端了。下次再讨论一下关于PTT的在线服务,创建群组列表等对PTT来说至关重要的问题的实现。



本文转自einyboy博客园博客,原文链接:http://www.cnblogs.com/einyboy/archive/2012/10/18/2729687.html,如需转载请自行联系原作者。



网友评论

登录后评论
0/500
评论
长征2号
+ 关注