Browse Source

T1978551 #comment 可视柜台音视频流量优化 #time 0.5h

胡琛80272472 6 years ago
parent
commit
77d1a97d39
5 changed files with 497 additions and 51 deletions
  1. 7 5
      Common/rec_common.h
  2. 277 13
      libtoolkit/rtp.c
  3. 46 1
      libtoolkit/rtp.h
  4. 153 31
      libtoolkit/rtpsession.c
  5. 14 1
      libtoolkit/rtpsession.h

+ 7 - 5
Common/rec_common.h

@@ -15,11 +15,13 @@
 #define REC_COMMON_VIDEO_CLOCK	90000
 
 #define REC_COMMON_VIDEO_FPS_DEN	1
-#define REC_COMMON_VIDEO_FPS_NUM	8
-#define REC_COMMON_VIDEO_FPS_MOBILE 5   //移动版视频5帧/s
-#define REC_COMMON_VIDEO_FPS_MOBILE_AGENT 2  //移动版坐席视频2帧/s
-#define REC_COMMON_VIDEO_FPS		8.0f
-#define REC_COMMON_VIDEO_RAW_FPS	8.0f
+#define REC_COMMON_VIDEO_FPS_NUM	10			//8
+#define REC_COMMON_VIDEO_FPS_MOBILE 8           //5   //移动版视频5帧/s
+#define REC_COMMON_VIDEO_FPS_MOBILE_AGENT 8 	//2  //移动版坐席视频2帧/s
+#define REC_COMMON_VIDEO_FPS		10.0f		//8.0f
+#define REC_COMMON_VIDEO_RAW_FPS	15.0f		//8.0f
+#define REC_COMMON_VIDEO_PADRAW_FPS	10.0f	
+
 #define REC_COMMON_VIDEO_RAW_FPS_DEN	1
 #define REC_COMMON_VIDEO_RAW_FPS_NUM	8
 #define REC_COMMON_VIDEO_SNAPSHOT_FPS	1.0f

+ 277 - 13
libtoolkit/rtp.c

@@ -27,6 +27,9 @@ struct rtp_state {
 	/* for rtcp sending */
 	DWORD transmit_interval;
 	DWORD last_transmit_tick;
+
+	/*for rtcp tmmbr */
+	RtcpTmmbrInfo tmmbr_info;
 };
 
 #ifndef JAN_1970
@@ -37,6 +40,25 @@ struct rtp_state {
 
 
 
+#define rtcp_fb_tmmbr_fci_get_ssrc(tmmbr) ntohl((tmmbr)->ssrc)
+#define rtcp_fb_tmmbr_fci_get_mxtbr_exp(tmmbr) \
+	((unsigned char)((ntohl((tmmbr)->value) >> 26) & 0x0000003F))
+#define rtcp_fb_tmmbr_fci_set_mxtbr_exp(tmmbr, mxtbr_exp) \
+	((tmmbr)->value) = htonl((ntohl((tmmbr)->value) & 0x03FFFFFF) | (((mxtbr_exp) & 0x0000003F) << 26))
+#define rtcp_fb_tmmbr_fci_get_mxtbr_mantissa(tmmbr) \
+	((unsigned int)((ntohl((tmmbr)->value) >> 9) & 0x0001FFFF))
+#define rtcp_fb_tmmbr_fci_set_mxtbr_mantissa(tmmbr, mxtbr_mantissa) \
+	((tmmbr)->value) = htonl((ntohl((tmmbr)->value) & 0xFC0001FF) | (((mxtbr_mantissa) & 0x0001FFFF) << 9))
+#define rtcp_fb_tmmbr_fci_get_measured_overhead(tmmbr) \
+	((unsigned short)(ntohl((tmmbr)->value) & 0x000001FF))
+#define rtcp_fb_tmmbr_fci_set_measured_overhead(tmmbr, measured_overhead) \
+	((tmmbr)->value) = htonl((ntohl((tmmbr)->value) & 0xFFFFFE00) | ((measured_overhead) & 0x000001FF))
+
+
+#define MIN_RTCP_PSFB_PACKET_SIZE (sizeof(rtcp_common_t) + sizeof(rtcp_fb_header_t))
+#define MIN_RTCP_RTPFB_PACKET_SIZE (sizeof(rtcp_common_t) + sizeof(rtcp_fb_header_t))
+
+
 TOOLKIT_API int rtp_state_fill_rtcp_sender_info(rtp_state *rs, rtcp_sender_info_t *info);
 TOOLKIT_API int rtp_state_fill_rtcp_reception_report(rtp_state *rs, rtcp_rr_t *report);
 TOOLKIT_API int rtp_state_fill_rtcp_sdes_item(rtp_state *rs, rtcp_sdes_type_t type, rtcp_sdes_item_t *item, int *fill_n);
@@ -85,6 +107,65 @@ static void gettimeofday(struct timeval *tv)
 	tv->tv_usec = st.wMilliseconds * 1000;
 }
 
+static char *copymsg(char *msg, int len)
+{
+	char *newm;
+	newm=malloc(len);
+	memcpy(newm,msg,len);
+	return newm;
+}
+
+static void freemsg(char *msg)
+{
+	if (msg != NULL) {
+		free(msg);
+	}
+}
+
+static size_t rtcp_get_size(const char *msg){
+	rtcp_common_t *ch = (rtcp_common_t *)msg;
+	if (ch==NULL) return 0;
+	return (1+ntohs(ch->length))*4;
+}
+
+static int rtcp_is_rtpfb(const char *msg) {
+	rtcp_common_t *ch = (rtcp_common_t *)msg;
+	if ((ch != NULL) && (ch->pt == RTCP_RTPFB)) {
+		return TRUE;
+	}
+	return FALSE;
+}
+
+static rtcp_rtpfb_type_t rtcp_rtpfb_get_type(const char *msg) {
+	rtcp_common_t *ch = (rtcp_common_t *)msg;
+	return (rtcp_rtpfb_type_t)ch->count;
+}
+
+static unsigned int rtcp_rtpfb_get_packet_sender_ssrc(const char *msg) {
+	rtcp_fb_header_t *fbh = (rtcp_fb_header_t *)(msg + sizeof(rtcp_common_t));
+	return ntohl(fbh->packet_sender_ssrc);
+}
+
+static unsigned int rtcp_rtpfb_get_media_source_ssrc(const char *msg) {
+	rtcp_fb_header_t *fbh = (rtcp_fb_header_t *)(msg + sizeof(rtcp_common_t));
+	return ntohl(fbh->media_source_ssrc);
+}
+
+static rtcp_fb_tmmbr_fci_t * rtcp_rtpfb_tmmbr_get_fci(const char *msg) {
+	size_t size = sizeof(rtcp_common_t) + sizeof(rtcp_fb_header_t) + sizeof(rtcp_fb_tmmbr_fci_t);
+	size_t rtcp_size = rtcp_get_size(msg);
+	if (size > rtcp_size) {
+		return NULL;
+	}
+	return (rtcp_fb_tmmbr_fci_t *)(msg + size - sizeof(rtcp_fb_tmmbr_fci_t));
+}
+
+static unsigned __int64 rtcp_rtpfb_tmmbr_get_max_bitrate(const char *msg) {
+	rtcp_fb_tmmbr_fci_t *fci = rtcp_rtpfb_tmmbr_get_fci(msg);
+	return rtcp_fb_tmmbr_fci_get_mxtbr_mantissa(fci) * (1 << rtcp_fb_tmmbr_fci_get_mxtbr_exp(fci));
+}
+
+
 TOOLKIT_API int rtp_state_fill_rtp(rtp_state *rs, void *hdr, unsigned int pt, unsigned int mark, unsigned int delta_ts)
 {
 	rtp_hdr *header;
@@ -135,16 +216,26 @@ TOOLKIT_API int rtp_state_set_rtcp_sdes_string(rtp_state *rs,
 	return rs->sdes_str[type] ? 0 : -1;
 }
 
+static unsigned __int64 rtp_timeval_to_ntp(const struct timeval *tv){
+   unsigned __int64 msw;
+   unsigned __int64 lsw;
+   msw=tv->tv_sec + 0x83AA7E80; /* 0x83AA7E80 is the number of seconds from 1900 to 1970 */
+   lsw=(unsigned int)((double)tv->tv_usec*(double)(((unsigned __int64)1)<<32)*1.0e-6);
+   return msw<<32 | lsw;
+}
+
 TOOLKIT_API int rtp_state_fill_rtcp_sender_info(rtp_state *rs, rtcp_sender_info_t *info)
 {
 	struct timeval tv;
+	unsigned __int64 ntp;
 
 	if (!rs)
 		return -1;
 	info->ssrc = rs->ssrc; /* sender's own ssrc */
 	gettimeofday(&tv);
-	info->ntp_sec = (unsigned int)htonl(tv.tv_sec + JAN_1970);
-	info->ntp_frac = (unsigned int)htonl((unsigned long)(tv.tv_usec*4294.967296));
+	ntp=rtp_timeval_to_ntp(&tv);
+	info->ntp_sec = htonl(ntp >>32);//(unsigned int)htonl(tv.tv_sec + JAN_1970);
+	info->ntp_frac = htonl(ntp & 0xFFFFFFFF);//(unsigned int)htonl((unsigned long)(tv.tv_usec*4294.967296));
 	info->rtp_ts = (unsigned int)htonl(rs->ts);
 	info->psent = (unsigned int)htonl((unsigned long)rs->s.total_tx_packets);
 	info->osent = (unsigned int)htonl((unsigned long)rs->s.total_tx_bytes);
@@ -170,23 +261,26 @@ TOOLKIT_API int rtp_state_fill_rtcp_reception_report(rtp_state *rs, rtcp_rr_t *r
 	if (packet_loss_since_last_sr < 0)
 		packet_loss_since_last_sr = 0;
 	rs->s.rx_seq_at_last_sr = ext_seq; /* update */
+	rs->s.rx_packets_since_last_sr = 0;//RESET
 	rs->s.total_packet_lost += (unsigned int)packet_loss_since_last_sr;
 	if (expected == 0)
 		expected = 1;
 	if (rs->s.lsr_tm.tv_sec != 0) {
 		struct timeval now;
+		double delay;
 		gettimeofday(&now);
-		delay_since_lsr = (0x10000 * (now.tv_sec - rs->s.lsr_tm.tv_sec));
-		delay_since_lsr += (now.tv_usec - rs->s.lsr_tm.tv_usec) * 0x10000 / 1000000;
+		delay= (now.tv_sec-rs->s.lsr_tm.tv_sec)+ ((now.tv_usec-rs->s.lsr_tm.tv_usec)*1e-6);
+		delay= (delay*65536);
+		delay_since_lsr=(unsigned int) delay;
 	}
 	loss_fraction = (unsigned char)(256 * packet_loss_since_last_sr / expected);
 	report->ssrc = rs->s.peer_ssrc;
 	report->fl_cnpl = htonl((loss_fraction << 24) | (rs->s.total_packet_lost&0xffffff));
 	report->last_seq = htonl(ext_seq);
 	report->jitter = htonl(rs->s.inter_jitter);
-	report->lsr = rs->s.lsr;
+	report->lsr = htonl(rs->s.lsr);
 	report->dlsr = htonl(delay_since_lsr);
-
+	
 	return 0;
 }
 
@@ -257,6 +351,7 @@ TOOLKIT_API int rtp_state_rtcp_make_sr(rtp_state *rs, char *buf, size_t buflen)
 	rtcp_common_t *common;
 	rtcp_sdes_t *sdes;
 	int n, t, m;
+	int reception_report_result;
 
 	if (!buf)
 		return -1;
@@ -267,8 +362,12 @@ TOOLKIT_API int rtp_state_rtcp_make_sr(rtp_state *rs, char *buf, size_t buflen)
 	n += sizeof(rtcp_common_t);
 	rtp_state_fill_rtcp_sender_info(rs, (rtcp_sender_info_t *)&buf[n]);
 	n += sizeof(rtcp_sender_info_t);
-	rtp_state_fill_rtcp_reception_report(rs, (rtcp_rr_t *)&buf[n]);
-	n += sizeof(rtcp_rr_t);
+	reception_report_result = rtp_state_fill_rtcp_reception_report(rs, (rtcp_rr_t *)&buf[n]);
+	if (reception_report_result < 0){
+	    //reception_report fillʧ°Ü£¬²»·¢ËÍreception_report
+	} else {
+		n += sizeof(rtcp_rr_t);
+	}
 	common->p = 0;
 	common->version = 2;
 	common->pt = RTCP_SR;
@@ -300,6 +399,7 @@ TOOLKIT_API int rtp_state_rtcp_make_rr(rtp_state *rs, char *buf, size_t buflen)
 	rtcp_common_t *common;
 	rtcp_sdes_t *sdes;
 	int n, t, m;
+	int reception_report_result;
 
 	if (!buf)
 		return -1;
@@ -308,11 +408,14 @@ TOOLKIT_API int rtp_state_rtcp_make_rr(rtp_state *rs, char *buf, size_t buflen)
 	n = 0;
 	common = (rtcp_common_t*)&buf[n];
 	n += sizeof(rtcp_common_t);
-	rtp_state_fill_rtcp_reception_report(rs, (rtcp_rr_t *)&buf[n]);
+	reception_report_result = rtp_state_fill_rtcp_reception_report(rs, (rtcp_rr_t *)&buf[n]);
+	if (reception_report_result < 0){
+	    return reception_report_result;
+	}
 	n += sizeof(rtcp_rr_t);
 	common->p = 0;
 	common->version = 2;
-	common->pt = RTCP_SR;
+	common->pt = RTCP_RR;
 	common->count = 1;
 	common->length = htons(n / 4 - 1);
 
@@ -351,7 +454,7 @@ TOOLKIT_API int rtp_state_rtcp_make_bye(rtp_state *rs, char *buf, size_t buflen)
 	n += sizeof(rtcp_bye_t);
 	bye->common.p = 0;
 	bye->common.version = 2;
-	bye->common.pt = RTCP_SR;
+	bye->common.pt = RTCP_BYE;
 	bye->common.count = 1;
 	bye->ssrc[0] = rs->ssrc;
 	bye->common.length = htons(n / 4 - 1);
@@ -456,6 +559,156 @@ TOOLKIT_API int rtp_state_rtcp_make_h261_nack(rtp_state *rs, char *buf, size_t b
 	return m;
 }
 
+
+TOOLKIT_API int rtp_state_rtcp_make_rtcp_fb_tmmbr(rtp_state *rs, char *buf, size_t buflen, unsigned __int64 mxtbr, unsigned short measured_overhead) {
+	rtcp_common_t *ch;
+	rtcp_fb_header_t *fbh;
+	rtcp_fb_tmmbr_fci_t *fci;
+	unsigned char mxtbr_exp = 0;
+	unsigned int mxtbr_mantissa = 0;
+	int length = 0;
+
+	/* Compute mxtbr exp and mantissa */
+	while (mxtbr >= (1 << 17)) {
+		mxtbr >>= 1;
+		mxtbr_exp++;
+	}
+	mxtbr_mantissa = mxtbr & 0x0001FFFF;
+
+	/* Fill TMMBR */
+	ch = (rtcp_common_t *)&buf[length];
+	length += sizeof(rtcp_common_t);
+	fbh = (rtcp_fb_header_t *)&buf[length];
+	length += sizeof(rtcp_fb_header_t);
+	fci = (rtcp_fb_tmmbr_fci_t *)&buf[length];
+	length += sizeof(rtcp_fb_tmmbr_fci_t);
+	fbh->packet_sender_ssrc = rs->ssrc;
+	fbh->media_source_ssrc = htonl(0);
+	fci->ssrc = rs->s.peer_ssrc;
+	rtcp_fb_tmmbr_fci_set_mxtbr_exp(fci, mxtbr_exp);
+	rtcp_fb_tmmbr_fci_set_mxtbr_mantissa(fci, mxtbr_mantissa);
+	rtcp_fb_tmmbr_fci_set_measured_overhead(fci, measured_overhead);
+
+	/* Fill common header */
+	ch->p = 0;
+	ch->version = 2;
+	ch->pt = RTCP_RTPFB;
+    ch->count = RTCP_RTPFB_TMMBR;
+	ch->length = htons(length / 4 - 1);
+
+	/* Store packet to be able to retransmit. */
+	if (rs->tmmbr_info.sent) freemsg(rs->tmmbr_info.sent);
+	rs->tmmbr_info.sent = copymsg(buf, length);
+
+	return length;
+}
+
+
+TOOLKIT_API int rtp_state_rtcp_make_rtcp_fb_tmmbn(rtp_state *rs, char *buf, size_t buflen, unsigned int ssrc) {
+	rtcp_common_t *ch;
+	rtcp_fb_header_t *fbh;
+	rtcp_fb_tmmbr_fci_t *fci;
+	int length = 0;
+
+	if (!rs->tmmbr_info.received) return 0;
+
+	/* Fill TMMBN */
+	ch = (rtcp_common_t *)&buf[length];
+	length += sizeof(rtcp_common_t);
+	fbh = (rtcp_fb_header_t *)&buf[length];
+	length += sizeof(rtcp_fb_header_t);
+	fci = (rtcp_fb_tmmbr_fci_t *)&buf[length];
+	length += sizeof(rtcp_fb_tmmbr_fci_t);
+	fbh->packet_sender_ssrc = rs->ssrc;
+	fbh->media_source_ssrc = htonl(0);
+	memcpy(fci, rtcp_rtpfb_tmmbr_get_fci(rs->tmmbr_info.received), sizeof(rtcp_fb_tmmbr_fci_t));
+	fci->ssrc = htonl(ssrc);
+
+	/* Fill common header */
+	ch->p = 0;
+	ch->version = 2;
+	ch->pt = RTCP_RTPFB;
+    ch->count = RTCP_RTPFB_TMMBN;
+	ch->length = htons(length / 4 - 1);
+
+	return length;
+}
+
+
+int rtp_state_get_tmmbr_wait_send_maxbitrate(rtp_state *rs, unsigned __int64 *mxtbr){
+	if (rs->tmmbr_info.sent) {
+		*mxtbr = rtcp_rtpfb_tmmbr_get_max_bitrate(rs->tmmbr_info.sent);
+		return 0;
+	}
+	return -1;
+}
+
+
+static void handle_rtcp_rtpfb_packet(rtp_state *rs, const char *buf, int len) {
+	rtcp_common_t *ch = (rtcp_common_t *)&buf[0];
+
+	switch ((rtcp_rtpfb_type_t)ch->count) {
+		case RTCP_RTPFB_TMMBR:
+			if (rs->tmmbr_info.received) freemsg((char *)(rs->tmmbr_info.received));
+			rs->tmmbr_info.received = copymsg(buf, len);
+			rs->s.tmmbr_max_bitrate = rtcp_rtpfb_tmmbr_get_max_bitrate(buf);
+		  	break;
+	  case RTCP_RTPFB_TMMBN:
+		  if (rs->tmmbr_info.sent) {
+			  rtcp_fb_tmmbr_fci_t *tmmbn_fci = rtcp_rtpfb_tmmbr_get_fci((char *)buf);
+			  rtcp_fb_tmmbr_fci_t *tmmbr_fci = rtcp_rtpfb_tmmbr_get_fci((char *)(rs->tmmbr_info.sent));
+			  if ((tmmbn_fci->ssrc == rs->ssrc) && (tmmbn_fci->value == tmmbr_fci->value)) {
+				  freemsg((char *)(rs->tmmbr_info.sent));
+				  rs->tmmbr_info.sent = NULL;
+			  }
+		  }
+		  break;
+	  default:
+		  break;
+  }
+}
+
+static unsigned int report_block_get_fraction_lost(const rtcp_rr_t * rr) {
+	return (ntohl(rr->fl_cnpl)>>24);
+}
+
+static unsigned int report_block_get_cum_packet_lost(const rtcp_rr_t * rr){
+	unsigned int cum_loss = (unsigned int)ntohl(rr->fl_cnpl);
+	if (((cum_loss>>23)&1)==0)
+		return (unsigned int) (0x00FFFFFF & cum_loss);
+	else
+		return (unsigned int)(0xFF000000 | (cum_loss-0xFFFFFF-1));
+}
+
+static void compute_rtt_from_report_block(rtp_state *rs, const struct timeval *now, rtcp_rr_t *rr) {
+	unsigned int last_sr_time;
+	unsigned int sr_delay;
+	
+	unsigned __int64 curntp;
+	unsigned int approx_ntp;
+
+	last_sr_time = ntohl(rr->lsr);
+	sr_delay = ntohl(rr->dlsr);
+	curntp=rtp_timeval_to_ntp(now);
+	approx_ntp=(curntp>>16) & 0xFFFFFFFF;
+	//printf("compute_rtt_from_report_block, last_sr_time:%u sr_delay:%u, approx_ntp:%u", last_sr_time, sr_delay, approx_ntp);
+
+	if (last_sr_time!=0 && sr_delay!=0){
+		/*we cast to int32_t to check for crazy RTT time (negative)*/
+		double rtt_frac=(unsigned int)(approx_ntp-last_sr_time-sr_delay);
+		//printf("compute_rtt_from_report_block, rtt_frac:%lf", rtt_frac);
+		if (rtt_frac>=0){
+			rtt_frac/=65536.0;
+
+			rs->s.rtt=(float)rtt_frac;
+		}
+	}
+
+	rs->s.cum_loss = report_block_get_cum_packet_lost(rr);
+	rs->s.fraction_lost = report_block_get_fraction_lost(rr);
+}
+
+
 /**
  * called when receive a peer's rtp data packet
  */
@@ -471,17 +724,28 @@ TOOLKIT_API int rtp_state_on_recv_rtcp(rtp_state *rs, const void *buf, int len)
 			if (common->pt == RTCP_SR) {
 				rtcp_sender_info_t *si;
 				si = (rtcp_sender_info_t *)((const char*)buf + n);
-				rs->s.lsr = (si->ntp_sec&0xffff0000) | (si->ntp_frac&0x0000ffff);
+				rs->s.lsr = ( ntohl( si->ntp_sec ) << 16 ) | ( ntohl( si->ntp_frac ) >> 16 );
 				gettimeofday(&rs->s.lsr_tm);
 			}
 			if ((common->pt == RTCP_SR || common->pt == RTCP_RR) && common->count) {
 				rtcp_rr_t *rr;
+				struct timeval now;
+				gettimeofday(&now);
+				
 				if (common->pt == RTCP_SR)
 					rr = (rtcp_rr_t *)((const char*)buf + n + sizeof(rtcp_sender_info_t));
-				else
+				else {
 					rr = (rtcp_rr_t *)((const char*)buf + n);
+					compute_rtt_from_report_block(rs, &now, rr);
+					rs->s.report_block_last_number_of_packets = ntohl(rr->last_seq) - rs->s.report_block_last_seq;
+					rs->s.report_block_last_seq = ntohl(rr->last_seq);
+				}
+				
 				/* nothing todo */
 			}
+			if (rtcp_is_rtpfb((char *)common), rtcp_get_size((char *)common)) {
+				handle_rtcp_rtpfb_packet(rs, (char *)common, rtcp_get_size((char *)common));
+			}
 			n += ntohs(common->length) * 4;
 		}
 		return 0;

+ 46 - 1
libtoolkit/rtp.h

@@ -9,6 +9,9 @@
 extern "C" {
 #endif
 
+
+#define IP_UDP_OVERHEAD (20 + 8)
+
 #define RTP_VERSION    2
 #define RTP_MAX_SDES 255      /* maximum text length for SDES */
 
@@ -91,7 +94,10 @@ typedef enum {
    RTCP_BYE  = 203,
    RTCP_APP  = 204,
    RTCP_FIR = 192, /* h261 specific, HW use this to request full intra-frame */
-   RTCP_NACK = 193 /* h261 specific */
+   RTCP_NACK = 193, /* h261 specific */
+   RTCP_RTPFB = 205,
+   RTCP_PSFB = 206,
+   RTCP_XR = 207
 } rtcp_type_t;
 
 typedef enum {
@@ -209,6 +215,32 @@ typedef struct {
 	unsigned int ssrc;
 }rtcp_fir_t;
 
+
+/* RTCP FB packet */
+typedef enum {
+	RTCP_RTPFB_NACK = 1,
+	RTCP_RTPFB_TMMBR = 3,
+	RTCP_RTPFB_TMMBN = 4
+} rtcp_rtpfb_type_t;
+
+typedef struct _rtcp_fb_header {
+	unsigned int packet_sender_ssrc;
+	unsigned int media_source_ssrc;
+} rtcp_fb_header_t;
+
+
+typedef struct rtcp_fb_tmmbr_fci {
+	unsigned int ssrc;
+	unsigned int value;
+} rtcp_fb_tmmbr_fci_t;
+
+
+typedef struct _RtcpTmmbrInfo {
+	char *sent;
+	char *received;
+} RtcpTmmbrInfo;
+
+
 typedef struct {
 	unsigned int peer_ssrc; /* network byte order */
 
@@ -230,6 +262,14 @@ typedef struct {
 	unsigned int transit;
 	unsigned int lsr; /* last sr ntp */
 	struct timeval lsr_tm; /* local time ticks after receive */
+
+	float rtt;/*last round trip delay calculated*/
+	int cum_loss;
+	unsigned int fraction_lost;
+	unsigned int report_block_last_seq;
+	int report_block_last_number_of_packets;
+	
+	unsigned __int64 tmmbr_max_bitrate;
 }rtcp_statistics;
 
 #pragma pack(1)
@@ -254,6 +294,8 @@ typedef struct rtp_dtmf_event rtp_dtmf_event;
 
 typedef struct rtp_state rtp_state;
 
+int rtp_state_get_tmmbr_wait_send_maxbitrate(rtp_state *rs, unsigned __int64 *mxtbr);
+
 TOOLKIT_API int rtp_state_fill_rtp(rtp_state *rs, void *hdr, unsigned int pt, unsigned int mark, unsigned int delta_ts);
 TOOLKIT_API int rtp_state_advance_timestamp(rtp_state *rs, unsigned int delta_ts);
 TOOLKIT_API int rtp_state_set_rtcp_sdes_string(rtp_state *rs, 
@@ -265,6 +307,9 @@ TOOLKIT_API int rtp_state_rtcp_make_rr(rtp_state *rs, char *buf, size_t buflen);
 TOOLKIT_API int rtp_state_rtcp_make_h261_fir(rtp_state *rs, char *buf, size_t buflen);
 
 
+TOOLKIT_API int rtp_state_rtcp_make_rtcp_fb_tmmbn(rtp_state *rs, char *buf, size_t buflen, unsigned int ssrc);
+TOOLKIT_API int rtp_state_rtcp_make_rtcp_fb_tmmbr(rtp_state *rs, char *buf, size_t buflen, unsigned __int64 mxtbr, unsigned short measured_overhead);
+
 /**
  * called when receive a peer's rtp data packet
  */

+ 153 - 31
libtoolkit/rtpsession.c

@@ -158,6 +158,73 @@ static int udp_poll_recv2(int sock,
 	return ret == 0 ? (int)dwBytesRecv : -1;
 }
 
+
+
+static int rtp_session_send_rtcp_fb_tmmbn(rtp_session_t *sess, unsigned int ssrc) {
+	if (sess && !(sess->flags & RTP_SESSION_FLAG_NO_RTCP)) {
+		char tmp[MAX_RTCP_BUF];
+		int n;
+		n = rtp_state_rtcp_make_rtcp_fb_tmmbn(sess->rtpstat, tmp, sizeof(tmp), ssrc);
+		if (n > 0) {
+			udp_block_send(sess->rtcp_fd, (struct sockaddr*)&sess->remote_rtcp_addr, 
+		  		sizeof(struct sockaddr_in), tmp, n);
+		}
+	} else {
+		return -1;
+	}
+	return 0;
+}
+
+//notice£¬this function must be called after rtp_state_on_recv_rtcp£¬
+//because rtp_state_on_recv_rtcp will update tmmbr_info.received before we send tmmbn.
+static void handle_rtcp_feedback_packet(rtp_session_t *sess, const char *buf, unsigned *flags) {
+	rtcp_fb_header_t *fbh;
+	rtcp_common_t *ch = (rtcp_common_t *)&buf[0];
+	//we send tmmbn
+	switch ((rtcp_rtpfb_type_t)ch->count) {
+		case RTCP_RTPFB_TMMBR:
+			fbh = (rtcp_fb_header_t *)(buf + sizeof(rtcp_common_t));
+		  	rtp_session_send_rtcp_fb_tmmbn(sess, ntohl(fbh->packet_sender_ssrc));
+		    *flags |= RTP_SESSION_HAS_RTPFB_TMMBR;
+		  	break;
+	  default:
+		  break;
+    }
+}
+
+static void handle_rtcp_sr_packet(rtp_session_t *sess, const char *buf) {
+	//we send RR
+	if (sess->flags == RTP_SESSION_FLAG_RECVONLY || sess->flags == RTP_SESSION_FLAG_SENDRECV) {
+		char tmp[MAX_RTCP_BUF];
+		int length = rtp_state_rtcp_make_rr(sess->rtpstat, tmp, sizeof(tmp));
+		if (length > 0) {
+			udp_block_send(sess->rtcp_fd, (struct sockaddr*)&sess->remote_rtcp_addr, 
+				sizeof(struct sockaddr_in), tmp, length);
+		}
+	}
+}
+
+static void handle_rtcp_packet(rtp_session_t *sess, const char *buf, int len) {
+
+	int n  = 0;
+	while( n < len) {
+		const rtcp_common_t *common = (rtcp_common_t *)((const char*)buf + n);
+		if (common->version != 2)
+			return ;
+		n += sizeof(rtcp_common_t);
+		
+		switch (common->pt) {
+		case RTCP_SR:
+			handle_rtcp_sr_packet(sess, (char *)common);
+			break;
+		default:
+			break;
+		}
+		n += ntohs(common->length) * 4;
+	}
+}
+
+
 static int recv_rtcp_raw(rtp_session_t *sess, char *buf, int n)
 {
 	int rc;
@@ -170,12 +237,7 @@ static int recv_rtcp_raw(rtp_session_t *sess, char *buf, int n)
 	rc = udp_poll_recv(sess->rtcp_fd, (struct sockaddr*)&addr, &addrlen, buf, n);
 	if (rc > 0) {
 		if (is_addr_equal(&sess->remote_rtcp_addr, &addr)) {
-			if (!(sess->flags & RTP_SESSION_FLAG_SENDONLY)) {
-				char tmp[MAX_RTCP_BUF];
-				rc = rtp_state_rtcp_make_rr(sess->rtpstat, tmp, sizeof(tmp));
-				udp_block_send(sess->rtcp_fd, (struct sockaddr*)&sess->remote_rtcp_addr, 
-					sizeof(struct sockaddr_in), tmp, rc);
-			}
+			handle_rtcp_packet(sess, buf, n);
 			return rc;
 		}
 	}
@@ -218,6 +280,9 @@ static int recv_rtcp(rtp_session_t *sess, unsigned *flags)
 			case RTCP_NACK:
 				f |= RTP_SESSION_HAS_NACK;
 				break;
+			case RTCP_RTPFB:
+				handle_rtcp_feedback_packet(sess, (char *)common, &f);
+				break;
 			default:
 				break;
 			}
@@ -359,7 +424,7 @@ TOOLKIT_API int rtp_session_reset2(rtp_session_t *sess,
 		int rc = 1;
 		struct sockaddr_in addr;
 		int addrlen = sizeof(addr);
-		char tmp[1500];
+		char tmp[MAX_RTCP_BUF];
 		while (rc > 0) { 
 			rc = udp_poll_recv(sess->rtp_fd, (struct sockaddr*)&addr, &addrlen, tmp, sizeof(tmp));
 		}
@@ -395,48 +460,70 @@ TOOLKIT_API int rtp_session_send_hook(rtp_session_t *sess,
 	int ret;
 	if (!sess || !buf || n <= 0)
 		return -1;
+	
+	rtp_state_fill_rtp(sess->rtpstat, &hdr, pt, mark, delta_ts);
+	return rtp_session_send_hook2(sess, rtcp_rx_flags, &hdr, buf, n, on_tx_hook, hook_arg);
+}
+
+
+TOOLKIT_API int rtp_session_send_hook2(rtp_session_t *sess, 
+	unsigned *rtcp_rx_flags,
+	const rtp_hdr *hdr,
+	const char *buf, 
+	int n, 
+	void (*on_tx_hook)(const char *buf, int size, void *arg), void *hook_arg)
+{
+	int ret;
+	if (!sess || !buf || n <= 0)
+		return -1;
 
 	if (rtcp_rx_flags)
 		*rtcp_rx_flags = 0;
 	if (!(sess->flags & RTP_SESSION_FLAG_NO_RTCP)) {
+		//only in sendonly we process recv_rtcp in rtp_session_send_hook function.
 		if (!(sess->flags & RTP_SESSION_FLAG_RECVONLY)) {
 			if (sess->remote_rtcp_addr.sin_port != 0)
 				recv_rtcp(sess, rtcp_rx_flags);
 		}
 	}
 
-	rtp_state_fill_rtp(sess->rtpstat, &hdr, pt, mark, delta_ts);
 	{
 		static int ss_seq = 0;
 		if (++ss_seq == 60) {
 			ret = 0;
 		} else {
 			ret = udp_block_send2(sess->rtp_fd, (struct sockaddr*)&sess->remote_rtp_addr, 
-				sizeof(struct sockaddr_in), (char*)&hdr, sizeof(hdr), buf, n);
+				sizeof(struct sockaddr_in), (char*)hdr, sizeof(*hdr), buf, n);
 		}
 	}
 	if (on_tx_hook) {
-		int size = sizeof(hdr) + n;
+		int size = sizeof(*hdr) + n;
 		char *tbuf = (char*)malloc(size);
-		memcpy(tbuf, &hdr, sizeof(hdr));
-		memcpy(tbuf+sizeof(hdr), buf, n);
+		memcpy(tbuf, hdr, sizeof(*hdr));
+		memcpy(tbuf+sizeof(*hdr), buf, n);
 		(*on_tx_hook)(tbuf, size, hook_arg);
 		free(tbuf);
 	}
 	if (ret != 0)
 		return ret;
-	rtp_state_on_send_rtp(sess->rtpstat, sizeof(hdr)+n);
+	rtp_state_on_send_rtp(sess->rtpstat, sizeof(*hdr)+n);
 	if (!(sess->flags & RTP_SESSION_FLAG_NO_RTCP)) {
 		if (rtp_state_need_send_rtcp(sess->rtpstat, TRUE) && sess->remote_rtcp_addr.sin_port != 0) {
 			char tmp[MAX_RTCP_BUF];
+			unsigned __int64 mxtbr;
 			ret = rtp_state_rtcp_make_sr(sess->rtpstat, tmp, sizeof(tmp));
 			udp_block_send(sess->rtcp_fd, (struct sockaddr*)&sess->remote_rtcp_addr, 
 				sizeof(struct sockaddr_in), tmp, ret);
+			//retry send tmmbr
+			if (rtp_state_get_tmmbr_wait_send_maxbitrate(sess->rtpstat, &mxtbr) == 0){
+				rtp_session_send_rtcp_fb_tmmbr(sess, mxtbr);
+			}
 		}
 	}
 	return 0;
 }
 
+
 TOOLKIT_API int rtp_session_send_raw(rtp_session_t *sess, 
 						 unsigned *rtcp_rx_flags,
 						 const char *buf, 
@@ -461,9 +548,14 @@ TOOLKIT_API int rtp_session_send_raw(rtp_session_t *sess,
 	if (!(sess->flags & RTP_SESSION_FLAG_NO_RTCP)) {
 		if (rtp_state_need_send_rtcp(sess->rtpstat, TRUE) && sess->remote_rtcp_addr.sin_port != 0) {
 			char tmp[MAX_RTCP_BUF];
+			unsigned __int64 mxtbr;
 			ret = rtp_state_rtcp_make_sr(sess->rtpstat, tmp, sizeof(tmp));
 			udp_block_send(sess->rtcp_fd, (struct sockaddr*)&sess->remote_rtcp_addr, 
 				sizeof(struct sockaddr_in), tmp, ret);
+			//retry send tmmbr
+			if (rtp_state_get_tmmbr_wait_send_maxbitrate(sess->rtpstat, &mxtbr) == 0){
+				rtp_session_send_rtcp_fb_tmmbr(sess, mxtbr);
+			}
 		}
 	}
 	return 0;
@@ -483,6 +575,20 @@ TOOLKIT_API int rtp_session_send_rtcp_h261_fir(rtp_session_t *sess)
 	return 0;
 }
 
+
+TOOLKIT_API int rtp_session_send_rtcp_fb_tmmbr(rtp_session_t *sess, unsigned __int64 mxtbr) {
+	if (sess && !(sess->flags & RTP_SESSION_FLAG_NO_RTCP)) {
+		char tmp[MAX_RTCP_BUF];
+		int n;
+		n = rtp_state_rtcp_make_rtcp_fb_tmmbr(sess->rtpstat, tmp, sizeof(tmp), mxtbr, IP_UDP_OVERHEAD);
+		udp_block_send(sess->rtcp_fd, (struct sockaddr*)&sess->remote_rtcp_addr, 
+			sizeof(struct sockaddr_in), tmp, n);
+	} else {
+		return -1;
+	}
+	return 0;
+}
+
 TOOLKIT_API int rtp_session_recv_hook(rtp_session_t *sess, 
 	unsigned *pt,
 	unsigned *mark, 
@@ -491,33 +597,58 @@ TOOLKIT_API int rtp_session_recv_hook(rtp_session_t *sess,
 	char *buf, 
 	int n,
 	void (*on_rx_hook)(const char *buf, int size, void *arg), void *hook_arg)
+{
+	int result;
+	rtp_hdr hdr;
+	if (!sess || !buf || n <= 0)
+		return -1;
+	
+	result = rtp_session_recv_hook2(sess, &hdr, buf, n, on_rx_hook, hook_arg);
+	if (result > 0) {
+		if (pt)
+			*pt = hdr.pt;
+		if (mark)
+			*mark = hdr.m;
+		if (ts)
+			*ts = ntohl(hdr.ts);
+		if (seq)
+			*seq = ntohs(hdr.seq);
+	}
+	return result;
+}
+
+
+TOOLKIT_API int rtp_session_recv_hook2(rtp_session_t *sess, 
+	rtp_hdr *hdr,
+	char *buf, 
+	int n,
+	void (*on_rx_hook)(const char *buf, int size, void *arg), void *hook_arg)
 {
 	int ret;
 	int max_cnt;
 	int i;
-	rtp_hdr hdr;
-	struct sockaddr_in addr;
+	struct sockaddr_in addr = {0};
 	int addrlen = sizeof(addr);
 	if (!sess || !buf || n <= 0)
 		return -1;
 
 	max_cnt = 5;
 	for (i = 0 ; i < max_cnt; ++i) {
-		ret = udp_poll_recv2(sess->rtp_fd, (struct sockaddr*)&addr, &addrlen, (char*)&hdr, sizeof(hdr), buf, n);
+		ret = udp_poll_recv2(sess->rtp_fd, (struct sockaddr*)&addr, &addrlen, (char*)hdr, sizeof(*hdr), buf, n);
 		if (ret > 0) {
 			if (on_rx_hook) {
-				if (ret <= sizeof(hdr)) {
-					(*on_rx_hook)((char*)&hdr, ret, hook_arg);
+				if (ret <= sizeof(*hdr)) {
+					(*on_rx_hook)((char*)hdr, ret, hook_arg);
 				} else {
 					char *tbuf = (char*)malloc(ret);
-					memcpy(tbuf, (char*)&hdr, sizeof(hdr));
-					memcpy(tbuf+sizeof(hdr), buf, ret - sizeof(hdr)); 
+					memcpy(tbuf, (char*)hdr, sizeof(*hdr));
+					memcpy(tbuf+sizeof(*hdr), buf, ret - sizeof(*hdr)); 
 					(*on_rx_hook)(tbuf, ret, hook_arg);
 					free(tbuf);
 				}
 			}
 			if (is_addr_equal(&sess->remote_rtp_addr, &addr)) {
-				if (rtp_state_on_recv_rtp(sess->rtpstat, &hdr, ret)==0) {
+				if (rtp_state_on_recv_rtp(sess->rtpstat, hdr, ret)==0) {
 					break;
 				}
 			}
@@ -528,16 +659,7 @@ TOOLKIT_API int rtp_session_recv_hook(rtp_session_t *sess,
 	if (i >= 5) 
 		return -1;
 
-	if (pt)
-		*pt = hdr.pt;
-	if (mark)
-		*mark = hdr.m;
-	if (ts)
-		*ts = ntohl(hdr.ts);
-	if (seq)
-		*seq = ntohs(hdr.seq);
-
-	return ret - sizeof(hdr);
+	return ret - sizeof(*hdr);
 }
 
 TOOLKIT_API int rtp_session_recv(rtp_session_t *sess, 

+ 14 - 1
libtoolkit/rtpsession.h

@@ -56,7 +56,12 @@ TOOLKIT_API int rtp_session_send_hook(rtp_session_t *sess,
 					 const char *buf, 
 					 int n, 
 					 void (*on_tx_hook)(const char *buf, int size, void *arg), void *hook_arg);
-
+TOOLKIT_API int rtp_session_send_hook2(rtp_session_t *sess, 
+	unsigned *rtcp_rx_flags,
+	const rtp_hdr *hdr,
+	const char *buf, 
+	int n, 
+	void (*on_tx_hook)(const char *buf, int size, void *arg), void *hook_arg);
 TOOLKIT_API int rtp_session_send_raw(rtp_session_t *sess, 
 						 unsigned *rtcp_rx_flags,
 						 const char *buf, 
@@ -64,6 +69,8 @@ TOOLKIT_API int rtp_session_send_raw(rtp_session_t *sess,
 
 // huawei openeye need this
 TOOLKIT_API int rtp_session_send_rtcp_h261_fir(rtp_session_t *sess);
+// bitrate control
+TOOLKIT_API int rtp_session_send_rtcp_fb_tmmbr(rtp_session_t *sess, unsigned __int64 mxtbr);
 
 #define RTP_SESSION_HAS_SDES	0x01
 #define	RTP_SESSION_HAS_FIR		0x02
@@ -72,6 +79,7 @@ TOOLKIT_API int rtp_session_send_rtcp_h261_fir(rtp_session_t *sess);
 #define RTP_SESSION_HAS_RR		0x10
 #define RTP_SESSION_HAS_APP		0x20
 #define RTP_SESSION_HAS_NACK	0x40
+#define RTP_SESSION_HAS_RTPFB_TMMBR	0x80
 
 TOOLKIT_API int rtp_session_recv(rtp_session_t *sess, 
 					 unsigned *pt,
@@ -88,6 +96,11 @@ TOOLKIT_API int rtp_session_recv_hook(rtp_session_t *sess,
 	char *buf, 
 	int n,
 	void (*on_rx_hook)(const char *buf, int size, void *arg), void *hook_arg);
+TOOLKIT_API int rtp_session_recv_hook2(rtp_session_t *sess, 
+	rtp_hdr *hdr,
+	char *buf, 
+	int n,
+	void (*on_rx_hook)(const char *buf, int size, void *arg), void *hook_arg);
 TOOLKIT_API int rtp_session_recv_raw(rtp_session_t *sess, 
 						 char *buf, 
 						 int n);