音视频同步!rtcp协议解析及代码实现(代码片段)

声网Agora 声网Agora     2023-01-07     233

关键词:

RTCP 是实时控制协议(Real-Time Control Protocol)的缩写。RTCP 由 RFC 3550 定义(取代作废的 RFC 1889)。

实时传输协议(RTP)和实时控制协议(RTCP)结合使用,可以监视大型多播网络的数据传递。RTP 承载媒体流,而 RTCP 用于监视传输统计信息和服务质量。监视使接收器能够检测是否有任何丢包并补偿任何延迟抖动。

两种协议都独立于基础传输层协议和网络层协议工作。RTP 标头中的信息告诉接收器如何重建数据,并描述编解码器比特流的打包方式。

下面我们重点讲解 RTCP 功能、RTCP 信息包等。最后 RTCP 协议解析实现。

RTCP 有哪些功能

1、RTCP 主要功能是提供有关质量的反馈数据分发。这是 RTP 角色不可或缺的一部分,传输协议,与流量和拥塞有关其他传输协议的控制功能。

2、RTCP 带有 RTP 的持久性传输级别标识符源称为规范名称或 CNAME。自从如果发现冲突或程序重新启动,接收方要求 CNAME 跟踪每个参与者。

接收者也可能要求 CNAME 将来自给定参与者的多个数据流关联到集合中相关 RTP 会话的数量,例如同步音频和视频。媒体间同步还需要 NTP 和 RTP 数据发送方在 RTCP 数据包中包含的时间戳。

3、前两个功能要求所有参与者发送 RTCP 数据包,因此必须控制速率以使 RTP 能够扩大到大量参与者。通过让每个参与者将其控制包发送给所有其他人,每个人都可以独立观察参与者的数量。

4、这项功能对于参加者可以任意进入和离开的松散会话进程十分有用,参加者可以自由进入或离开,没有成员控制或参数协调。

功能 1-3 应该在所有环境中使用,尤其是在 IP 多播环境。RTP 应用程序设计师应避免只能在单播模式下工作且无法扩展到的机制更大的数字。RTCP 的传输可以单独控制对于发送者和接收者,适用于例如单向链接,而接收者没有反馈可能的。

RTCP 协议的端口

RTSP 通常使用 RTP 协议来传送实时流,RTP 一般使用偶数端口,而 RTCP 使用相邻的奇数端口,即 RTP 端口号+1。

RTP 端口

RTCP 端口

RTCP 信息包有哪些

在 RTCP 通信控制中,RTCP 协议的功能是通过不同类型的 RTCP 包来实现的。RTCP 也是基于 UDP 包来传送的,主要有五种类型的封包:

  1. SR:发送端报告,由发送 RTP 数据报的应用程序或中端发出的。
  2. RR:接收端报告,由接受但不发送 RTP 数据报的应用程序或中端发出。
  3. SDES:源描述,传递与会话成员有关的标识信息的载体,如用户名、邮件、电话等。
  4. BYE:通知离开,通知回话中的其他成员将退出会话。
  5. APP:由应用程序自己定义,作为 RTCP 协议的扩展。
#define RTCP_SR      200
#define RTCP_RR      201
#define RTCP_SDES    202
#define RTCP_BYE     203
#define RTCP_APP     204

我们可以根据这五种类型包判断 RTCP 头部

static bool dissect_rtcp_heur(u_char *rtcp_info,int PayloadLen)

    unsigned int offset = 0;
    unsigned int first_byte = 0;
    unsigned int packet_type = 0;


    /* 查看第一个字节 */
    first_byte = rtcp_info[offset];

    /* 版本位是否设置为2*/
	//printf("version: %d\\n",((first_byte & 0xC0) >> 6));
    if (((first_byte & 0xC0) >> 6) != 2)
    
        return false;
    

    /* 看包类型 */
	offset += 1;
    packet_type = rtcp_info[offset];
	//printf("packet_type: %d\\n",packet_type);
    /* 复合数据包中的第一个数据包应该是发送方或接收者报告 */
    if (!((packet_type == RTCP_SR)  || (packet_type == RTCP_RR) ||
          (packet_type == RTCP_BYE) || (packet_type == RTCP_APP) ||
          (packet_type == RTCP_PSFB)))
    
        return false;
    

    /*总长度必须是4个字节的倍数*/
	//printf("PayloadLen: %d\\n",PayloadLen);
    if (PayloadLen % 4)
    
        return false;
    

    /* OK, dissect as RTCP */
    dissect_rtcp(rtcp_info,packet_type,offset,PayloadLen);
    return true;

RTCP 协议报文格式

SR:发送端报告

版本(V):同 RTP 包头部

填充 ( P ) :同 RTP 包头部。

接收报告计数器(RC):5b 该 SR 包中接收的报告块的数目。

包类型(PT): 8bit SR 包类型为 200

长度(length):SR 包以 32bit 为 1 单位的长度减 1

同步源(SSRC):SR 包发送的同步源标识符。与对应 RTP 包中的 SSRC 一样。

NTP 时间戳(Network Time Protocol):SR 包发送时的绝对时间。用于同步不同的流。

RTP 时间戳:与 NTP 时间戳对应,与 RTP 包中的时间戳具有相同的初始值。

Send’s Packet count:从开始发包到产生这个 SR 包的这段时间内发送者发送的有效数据的总字节数,不包括头部和填充,发送者改变 SSRC 时,该域要清零。

同步源 n 的 SSRC 标识符:该报告中包含的是从该源接收到的包的统计信息。

丢失率:表明从上一个 SR 或 RR 包发出依来从同步源 n 发送的 RTP 包的丢失率。

累计丢失数据:从开始接受 SSRC_n 的包到发送 SR 这个时间段内 SSRC_n 发送的 RTP 丢失的总数目。

收到的扩展最大序列号:从 SSRC_n 收到的从 RTP 数据包中的最大序列号。

接收抖动(Interarrival jitter):RTP 数据包接收时间的统计方差估计。

上次 SR 时间戳(Last SR):取最近从 SSRC_n 收到的 SR 包中的 NTP 时间戳中的中间 32bit。如果还未收到 SR 包,则为 0。

上次依赖 SR 延迟(Delay since Last SR):从上次 SSRC_n 收到 SR 包到发送本包的延迟

Wireshark 抓包:

活动会话的参与者在发送和接收 RTP 分组时使用 SR。SR 有三个不同的部分:报头信息、发送方信息和许多接收方报告块。SR 也可以有一个与大纲相关的扩展域。

Wireshark 抓包:

SDES:源描述

SDES 提供了传递与会话成员有关的标识信息的载体,如用户名、邮件、电话等。每个 RTCP 混合分组中必须有 SDES 分组。

报头包含一个长度域、一个净荷类型域(PT=202)和一个源计数(RC)域。RC 域 5 个 bit,表示分组中信息块的数量。

每个信息块包含一个 SSRC 或 CSRC 值,其后跟着一个或多个的标识符和一些可用于 SSRC 或 CSRC 的信息。

CNAME 项的 SDES 包必须包含在每个组合 RTCP 包中。SDES 包可能包括其他源描述项,这要根据特别的应用需要,并同时考虑带宽限制。

Wireshark 抓包:

SDES 源描述包提供了直观的文本信息来描述会话的参加者,包括 CNAME、NAME、EMAIL、PHONE、LOC 等源描述项。

这些为接收方获取发送方的有关信息提供了方便。SDES 包由包头与数据块组成,数据块可以没有,也可有多个。包头由版本(V)、填充(P)、长度指示、包类型(PT)和源计数(SC)组成。

PT 占 8 位,用于识别 RTCP 的 SDES 包,SC 占 5 位,指示包含在 SDES 包中的 SSRC/CSRC 块数量,零值有效,但没有意义。

BYE: 通知离开

BYE 分组用于表示一个或多个媒体源不再是处于激活状态。

Wireshark 抓包:

作为可选项,BYE 包可包括一个 8 位八进制计数,后跟文本信息,表示离开原因。

最后,组合包中每个 RTCP 包可独立处理,而不需要按照包组合的先后顺序处理。

在组合包中有以下几条强制约束。

  1. 只要带宽允许,在 SR 包或 RR 包中的接收统计应该经常发送,因此每个周期发送的组合 RTCP 包中应包含报告包。
  2. 每个组合包中都应该包含 SDES CNAME,因为新接收者需要通过接收 CNAME 来识别源,并与媒体联系进行同步。
  3. 组合包前面是包类型数量,其增长应该受到限制。

RTCP 协议如何实现媒体流的同步

通过抓包分析 RTCP 发送端报告,RTP 的同步其实就靠这三个域:

  1. sender SSRC :SR 包发送的同步源标识符。与对应 RTP 包中的 SSRC 一样。
  2. NTP timestamp:SR 包发送时的绝对时间。用于同步不同的流。
  3. RTP timestamp:与 NTP 时间戳对应,与 RTP 包中的时间戳具有相同的初始值。

那怎么计算 NTP 时间呢?在 RTCP 中 NTP 时间存放在 8 个字节中,分为:MSW 和 LSW,分别占用 4 个字节。

const char *tvb_ntp_fmt_ts_sec(u_char *rtcp_info, int offset)

	uint32_t tempstmp = 0;
	time_t temptime = 0;
	struct tm *bd;
	char *buff = NULL;
	
	tempstmp = ntohl(*(uint32_t*)(rtcp_info + offset));
	if (tempstmp == 0)
		return "NULL";
	

	/* We need a temporary variable here so the unsigned math
	* works correctly (for years > 2036 according to RFC 2030
	* chapter 3).
	*/
	temptime = (time_t)(tempstmp - NTP_BASETIME);
	bd = gmtime(&temptime);
	if (!bd)
		return "Not representable";
	

	buff = (char *)malloc(NTP_TS_SIZE);
	snprintf(buff, NTP_TS_SIZE,
		"%s %2d, %d %02d:%02d:%02d UTC",
		mon_names[bd->tm_mon],
		bd->tm_mday,
		bd->tm_year + 1900,
		bd->tm_hour,
		bd->tm_min,
		bd->tm_sec);
	return buff;

NTP timestamp

  
    /* NTP timestamp */
    ts_msw = ntohl(*(uint32_t*)(rtcp_info + offset));
	printf("ts_msw: 0x%x\\n",ts_msw);
    ts_lsw = ntohl(*(uint32_t*)(rtcp_info + offset + 4));
	printf("ts_lsw: 0x%x\\n",ts_lsw);
	printf("MSW: %s\\n",tvb_ntp_fmt_ts_sec(rtcp_info,offset));
    offset += 8;

RTCP 协议实现

下面我给出对 RTCP 协议解析实现的代码,根据回放报文,解析字段信息。

/* 接收者/发送者计数是最后5位   */
#define RTCP_COUNT(octet)   ((octet) & 0x1F)


#define RTCP_PT_MIN  192
/* Supplemental H.261 specific RTCP packet types according to Section C.3.5 */
#define RTCP_FIR     192
#define RTCP_NACK    193
#define RTCP_SMPTETC 194
#define RTCP_IJ      195
/* RTCP packet types according to Section A.11.1 */
/* And https://www.iana.org/assignments/rtp-parameters/rtp-parameters.xhtml */
#define RTCP_SR      200
#define RTCP_RR      201
#define RTCP_SDES    202
#define RTCP_BYE     203
#define RTCP_APP     204
#define RTCP_RTPFB   205
#define RTCP_PSFB    206
#define RTCP_XR      207
#define RTCP_AVB     208
#define RTCP_RSI     209
#define RTCP_TOKEN   210

#define RTCP_PT_MAX  210


static const char mon_names[12][4] = 
	"Jan",
	"Feb",
	"Mar",
	"Apr",
	"May",
	"Jun",
	"Jul",
	"Aug",
	"Sep",
	"Oct",
	"Nov",
	"Dec"
;

/** data structure to hold time values with nanosecond resolution*/
typedef struct 
	time_t	secs;
	int	nsecs;
 nstime_t;


/*
 * 1900-01-01 00:00:00 (proleptic?) UTC.
 * Used by a number of time formats.
 */
#define EPOCH_DELTA_1900_01_01_00_00_00_UTC 2208988800U

/*
 * NTP_BASETIME is in fact epoch - ntp_start_time; ntp_start_time
 * is January 1, 2036, 00:00:00 UTC.
 */
#define NTP_BASETIME EPOCH_DELTA_1900_01_01_00_00_00_UTC
#define NTP_FLOAT_DENOM 4294967296.0
#define NTP_TS_SIZE 100


/* 解剖长度字段。附加到此字段的文字表示转换为的实际字节数 (即 (原始值 + 1) * 4) */
static int dissect_rtcp_length_field(u_char *rtcp_info, int offset)


    uint16_t  raw_length = ntohs(*(uint16_t*)(rtcp_info + offset));
    printf("(%u bytes)\\n", (raw_length+1)*4);
    offset += 2;
    return offset;

static int dissect_rtcp_rr(u_char *rtcp_info, int offset,int count, int packet_length )

    int counter = 0;
    uint8_t  rr_flt = 0;
    int    rr_offset = offset;
	
    counter = 1;
    while ( counter <= count ) 
        uint32_t lsr = 0, dlsr = 0;

        /* Create a new subtree for a length of 24 bytes */

        /* SSRC_n source identifier, 32 bits */

        offset += 4;

        /* Fraction lost, 8bits */
        rr_flt = rtcp_info[offset];

        offset++;

        /* Cumulative number of packets lost, 24 bits */
        offset += 3;


        /* Sequence number cycles */

        offset += 2;
        /* highest sequence number received */

        offset += 2;

        /* Interarrival jitter */

        offset += 4;

        /* Last SR timestamp */
        lsr = ntohl(*(uint32_t*)(rtcp_info + offset));
		printf("Last SR timestamp: 0x%x\\n",lsr);
        offset += 4;

        /* Delay since last SR timestamp */
        dlsr = ntohl(*(uint32_t*)(rtcp_info + offset));

        printf("(%d milliseconds)\\n",(int)(((double)dlsr/(double)65536) * 1000.0));
        offset += 4;

        counter++;
    

    return offset;


const char *tvb_ntp_fmt_ts_sec(u_char *rtcp_info, int offset)

	uint32_t tempstmp = 0;
	time_t temptime = 0;
	struct tm *bd;
	char *buff = NULL;
	
	tempstmp = ntohl(*(uint32_t*)(rtcp_info + offset));
	if (tempstmp == 0)
		return "NULL";
	

	/* We need a temporary variable here so the unsigned math
	* works correctly (for years > 2036 according to RFC 2030
	* chapter 3).
	*/
	temptime = (time_t)(tempstmp - NTP_BASETIME);
	bd = gmtime(&temptime);
	if (!bd)
		return "Not representable";
	

	buff = (char *)malloc(NTP_TS_SIZE);
	snprintf(buff, NTP_TS_SIZE,
		"%s %2d, %d %02d:%02d:%02d UTC",
		mon_names[bd->tm_mon],
		bd->tm_mday,
		bd->tm_year + 1900,
		bd->tm_hour,
		bd->tm_min,
		bd->tm_sec);
	return buff;


static int dissect_rtcp_sr(u_char *rtcp_info, int offset,int count, int packet_length)


    uint32_t     ts_msw = 0, ts_lsw = 0;
    int         sr_offset = offset;

    /* NTP timestamp */
    ts_msw = ntohl(*(uint32_t*)(rtcp_info + offset));
	printf("ts_msw: 0x%x\\n",ts_msw);
    ts_lsw = ntohl(*(uint32_t*)(rtcp_info + offset + 4));
	printf("ts_lsw: 0x%x\\n",ts_lsw);

	//printf("offset: 0x%x 0x%x 0x%x 0x%x\\n",rtcp_info[offset],rtcp_info[offset + 1],rtcp_info[offset + 2],rtcp_info[offset + 3]);
	printf("MSW: %s\\n",tvb_ntp_fmt_ts_sec(rtcp_info,offset));
    offset += 8;

    /* RTP timestamp, 32 bits */
	
    offset += 4;
    /* Sender's packet count, 32 bits */

    offset += 4;
    /* Sender's octet count, 32 bits */

    offset += 4;


    /* The rest of the packet is equal to the RR packet */
    if ( count != 0 )
        offset = dissect_rtcp_rr(rtcp_info, offset, count, packet_length-(offset-sr_offset));
    else
    
        /* If length remaining, assume profile-specific extension bytes */
        if ((offset-sr_offset) < packet_length)
        

            offset = sr_offset + packet_length;
        
    

    return offset;


static int dissect_rtcp_sdes(u_char *rtcp_info, int offset, int count)

    int           chunk = 0;

    int           start_offset = 0;
    int           items_start_offset = 0;
    uint32_t       ssrc = 0;
    unsigned int  item_len = 0;
    unsigned int  sdes_type = 0;
    unsigned int  prefix_len = 0;

    chunk = 1;
    while ( chunk <= count ) 
	
		/* Create a subtree for this chunk; we don't yet know
		   the length. */
		start_offset = offset;

		ssrc = ntohl(*(uint32_t*)(rtcp_info + offset));
		printf("Chunk %u, SSRC/CSRC 0x%X\\n", chunk, ssrc);

		/* SSRC_n source identifier, 32 bits */
		offset += 4;

		/* Create a subtree for the SDES items; we don't yet know
		   the length */


		/*
		 * Not every message is ended with "null" bytes, so check for
		 * end of frame as well.
		 */
		 
		  /* ID, 8 bits */
		sdes_type = rtcp_info[offset];
		printf("Type: %d\\n",sdes_type);
		if (sdes_type == 0)
			break;
		offset++;
		/* Item length, 8 bits */
		item_len = rtcp_info[offset];
		printf("Length: %d\\n",item_len);
		offset++;
		
		char *pszText = (char*)malloc(item_len);
		if (pszText != 0)
		
			memcpy(pszText, rtcp_info + offset,item_len);
			pszText[item_len] = '\\0';
			printf("Text = %s\\n",pszText);
			

		chunk++;
    

    return offset;


static void dissect_rtcp(u_char *rtcp_info,int packet_type, int offset,int PayloadLen)

	unsigned int  temp_byte = 0;
	int  elem_count = 0;
	int  packet_length = 0;
	int  total_packet_length = 0;
	int loop = 2;
	bool flag_rtcp = false;

		/*检查是否为有效类型*/
		if ( ( packet_type < RTCP_PT_MIN ) || ( packet_type >  RTCP_PT_MAX ) )
			exit(-1);

		/*
		 * 获取完整的RTCP数据包的长度
		 */
		 
		packet_length = (ntohs(*(uint16_t*)(rtcp_info + offset + 1)) + 1) * 4 ;
		//printf("packet_length: %d\\n",packet_length);

		
		temp_byte = rtcp_info[offset-1];
		elem_count = RTCP_COUNT( temp_byte );/* Source count, 5 bits */
		printf("Reception report count: %d\\n",elem_count);  

		switch ( packet_type ) 
		
			
			case RTCP_SR:
			case RTCP_RR:
				/*
					Real-time Transport Control Protocol (Receiver Report)
					10.. .... = Version: RFC 1889 Version (2)
					..0. .... = Padding: False
					...0 0001 = Reception report count: 1
					Packet type: Receiver Report (201)
					Length: 7 (32 bytes)
					Sender SSRC: 0xb584b03e (3045371966)
					Source 1
				*/

				/* Packet type, 8 bits */
				offset++;
				/* Packet length in 32 bit words MINUS one, 16 bits */
				offset = dissect_rtcp_length_field(rtcp_info, offset);
				/* Sender Synchronization source, 32 bits */
				offset += 4;

				if ( packet_type == RTCP_SR )
				
					offset = dissect_rtcp_sr(rtcp_info, offset, elem_count, packet_length-8 );
					printf("dissect_rtcp_sr\\n");
				
				else
					
					offset = dissect_rtcp_rr(rtcp_info, offset, elem_count, packet_length-8 );							
				
				
				//uint16_t second_packet_type = ntohs(*(uint16_t*)(rtcp_info + offset));

				//printf("111offset: 0x%x 0x%x 0x%x 0x%x\\n",rtcp_info[offset],rtcp_info[offset + 1],rtcp_info[offset + 2],rtcp_info[offset + 3]);
				
				if (rtcp_info[offset + 1] == RTCP_SDES)
				
					
					/* Source count, 5 bits */
					offset++;
					/* Packet type, 8 bits */
					offset++;
					/* Packet length in 32 bit words MINUS one, 16 bits */
					offset = dissect_rtcp_length_field(rtcp_info, offset);
					offset = dissect_rtcp_sdes(rtcp_info,offset,elem_count);

				

			break;

			default:
				/*
				 * To prevent endless loops in case of an unknown message type
				 * increase offset. Some time the while will end :-)
				 */
				offset++;
				break;

		
		



static bool dissect_rtcp_heur(u_char *rtcp_info,int PayloadLen)

    unsigned int offset = 0;
    unsigned int first_byte = 0;
    unsigned int packet_type = 0;


    /* 查看第一个字节 */
    first_byte = rtcp_info[offset];

    /* 版本位是否设置为2*/
	//printf("version: %d\\n",((first_byte & 0xC0) >> 6));
    if (((first_byte & 0xC0) >> 6) != 2)
    
        return false;
    

    /* 看包类型 */
	offset += 1;
    packet_type = rtcp_info[offset];
	//printf("packet_type: %d\\n",packet_type);
    /* 复合数据包中的第一个数据包应该是发送方或接收者报告 */
    if (!((packet_type == RTCP_SR)  || (packet_type == RTCP_RR) ||
          (packet_type == RTCP_BYE) || (packet_type == RTCP_APP) ||
          (packet_type == RTCP_PSFB)))
    
        return false;
    

    /*总长度必须是4个字节的倍数*/
	//printf("PayloadLen: %d\\n",PayloadLen);
    if (PayloadLen % 4)
    
        return false;
    

    /* OK, dissect as RTCP */
    dissect_rtcp(rtcp_info,packet_type,offset,PayloadLen);
    return true;



static void confirm_rtcp_packet(struct ip *pIp)

	int iIpTotalLen = ntohs(pIp->ip_len);
	int offset = 0;
	int nFragSeq = 0;
	struct udphdr* pUdpHdr = (struct udphdr*)((char*)pIp + (pIp->ip_hl<<2));
	if (pIp->ip_p == IPPROTO_UDP) 
	
		printf("\\n");
		
		int iPayloadLen = iIpTotalLen - (pIp->ip_hl<<2) - 8;
		printf("UDP Payload Len %d\\n", iPayloadLen);
		
		u_char *pDnsHdr = (u_char*)(pUdpHdr+1);
		dissect_rtcp_heur(pDnsHdr,iPayloadLen);
		
		

编译运行:

总结

RTCP 协议是流媒体通信的基石。RTCP 协议则负责可靠传输、流量控制和拥塞控制等服务质量保证。上面讲解了 RTCP 功能、RTCP 数据包格式及代码实现。最后,学习一个新的协议,最好还是研究学习官方文档,因为这是最权威的资料。

音频和视频流最佳选择?srt协议解析及报文识别(代码片段)

我们所知道SRT是由Haivision和Wowza开发的开源视频流协议。很多人会认为在不久的将来,它被是RTMP的替代品。因为RTMP协议安全性稍低,延迟相对较高,而相对于SRT协议支持高质量、稳定性、亚秒级延迟、强大的编解码... 查看详情

rtsp协议格式解析(代码片段)

...支撑,理论又很难理解到位。本系列文章将从流媒体协议的基础原理开始,通过抓包分析,并结合具体的代码例程,以[原理]->[抓包]->[代码]相结合的方式,循序渐进由浅入深的介绍rtsp/rtp/rtcp开发相关的内... 查看详情

rtp协议(代码片段)

概述RTP:实时传输协议(Real-timeTransportProtocol)RTP/RTCP是实际传输数据的协议RTP传输音频/视频数据,如果是PLAY,Server发送到Client端,如果是RECORD,可以由Client发送到Server整个RTP协议由两个密切相关的部分组成:RTP数据协议和RTP控... 查看详情

rtp,rtcp,rtsp等网络协议有何用途和区别

...流媒体(通过sdp)rtp传输流媒体数据rtcp对rtp进行控制,同步。RTSP的请求主要有DESCRIBE,SETUP,PLAY,PAUSE,TEARDOWN,OPTIONS等,顾名思义可以知道起对话和控制作用RTP/RTCP是实际传输数据的协议RTCP包括SenderReport和ReceiverReport,用来进行音频/... 查看详情

rsync+notify配置解析及步骤详解(代码片段)

...源,快速,多功能的可实现增量的本地或远程的数据镜像同步备份的优秀工具。适用于多个平台。从软件名称可以看出来是远程同步的意思(remotesync)。可使本地主机不同分区或目录之间及本地和远程两台主机之间的数据快速... 查看详情

webrtc[54]-webrtc之rtcp详解

...,拥塞控制相关的带宽反馈,以及⽤户体验相关的⾳视频同步等。文本将重点介绍RTCP相关的内容和基础知识。正文RTCP类型在WebRTC内部,RTCP包的类型一般可以分为七种,具体划分如下:enumRtcpTypeskRtcpTypeSR=200,//Senderreportpayloadtype.kR... 查看详情

webrtc[54]-webrtc之rtcp详解

...,拥塞控制相关的带宽反馈,以及⽤户体验相关的⾳视频同步等。文本将重点介绍RTCP相关的内容和基础知识。正文RTCP类型在WebRTC内部,RTCP包的类型一般可以分为七种,具体划分如下:enumRtcpTypeskRtcpTypeSR=200,//Senderreportpayloadtype.kR... 查看详情

蓝牙pbap协议源码解析(代码片段)

PBAP协议使用场景:智能车载中同步联系人等信息其实,不仅可以同步联系人,还可以同步通话记录等信息。1.协议概述协议代码路径: frameworks\\opt\\bluetooth\\src\\android\\bluetooth\\client\\pbap这个包中Jar包名称,android.bluetooth.client.pbap所以进... 查看详情

rtcp协议详解(srrrsdesbyeappnacktccplislifir)(代码片段)

RTCP协议规范中定义了五种类型的RTCP包:接收⽅报告(RR)、发送⽅报告(SR)、源描述(SDES)、成员管理(BYE)和应⽤程序定义(APP)。SR:payloadtype=200RR:payloadtype=201SDES: payloadtype&#... 查看详情

rtcp多媒体控制协议调试(代码片段)

1、rtcp是个非常小的多媒体控制协议,一般和jitterbuffer一起用于rtp延时,抖动,丢包等处理。1)rtcp应用描述,值得一看详细的文档描述https://wenku.baidu.com/view/e21ee8e9b8f67c1cfad6b8f2.html2)rtcp数据结构,消息构建,感谢网友。https://www.cnb... 查看详情

h264关于rtp协议的实现

完整的C/S架构的基于RTP/RTCP的H.264视频传输方案。此方案中,在服务器端和客户端分别进行了功能模块设计。服务器端:RTP封装模块主要是对H.264码流进行打包封装;RTCP分析模块负责产牛和发送RTCP包并分析接收到的RTCP包;Q... 查看详情

rtp/rtcp协议解析

RTP协议       实时传输协议RTP(Real-timeTransportProtocol)是一个网络传输协议,它是由IETF的多媒体传输工作小组1996年在RFC1889中公布的,后在RFC3550中进行更新。       国际电信联盟... 查看详情

drf之解析器组件及序列化组件(代码片段)

...习,我们已经有了一个共识,Django无法处理application/json协议请求的数据,即,如果用户通过application/json协议发送请求数据到达Django服务器,我们通过request.POST获取到的是一个空对象。  DjangoRestFramework帮助我们实现了处理applic... 查看详情

使用rtcp实现音视频同步

参考技术A音视频同步是指音视频的rtp时间戳同步.audio/videortp时间戳不能自己同步,需要audio/videortcp同步。发送端以一定的频率发送RTCPSR(SenderReport)这个包,SR分为视频SR和音频SR,SR包内包含一个RTP时间戳和对应的NTP时间戳,可以... 查看详情

fpm启动机制及流程分析———详细(代码片段)

...GI是Web服务器(如:Nginx、Apache)和处理程序之间的一种通信协议,它是与Http类似的一种应用层通信协议,注意:它只是一种协议!前面曾一再强调,PHP只是一个脚本解析器,你可以把它理解为一个普通的函数,输入是PHP脚本。输... 查看详情

使用bind提供域名解析服务(代码片段)

...作为数据通信端口(域名解析),使用TCP53号端口实现数据同步(主从同步)。DNS工作过程:1.客户机首先会查看本地的host 查看详情

rsync服务介绍及相关实验(代码片段)

...持快速完全备份和增量备份的工具,支持本地复制,远程同步等,类似于scp命令;rsync命令在同步文件之前要先登录目标主机进行用户身份认证,认证过后才能进行数据同步,身份认证方式取决于所使用的协议类型,rsync一般使... 查看详情

网络时间服务的简介及搭建(代码片段)

...TP/CHRONY  当多台主机协作工作时,各个主机的时间同步很重要,时间不一致会造成很多重要应用的故障,如:加密协议、日志、集群等,利用NTP(NetworkTimeProtocol)协议使网络中的各个计算机时间达到同步。目前NTP协议属... 查看详情