00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027 #include "ortp/ortp.h"
00028 #include "ortp/rtpsession.h"
00029 #include "ortp/rtcp.h"
00030 #include "utils.h"
00031 #include "rtpsession_priv.h"
00032
00033 #define rtcp_bye_set_ssrc(b,pos,ssrc) (b)->ssrc[pos]=htonl(ssrc)
00034 #define rtcp_bye_get_ssrc(b,pos) ntohl((b)->ssrc[pos])
00035
00036
00037 void rtcp_common_header_init(rtcp_common_header_t *ch, RtpSession *s,int type, int rc, int bytes_len){
00038 rtcp_common_header_set_version(ch,2);
00039 rtcp_common_header_set_padbit(ch,0);
00040 rtcp_common_header_set_packet_type(ch,type);
00041 rtcp_common_header_set_rc(ch,rc);
00042 rtcp_common_header_set_length(ch,(bytes_len/4)-1);
00043 }
00044
00045 static mblk_t *sdes_chunk_new(uint32_t ssrc){
00046 mblk_t *m=allocb(RTCP_SDES_CHUNK_DEFAULT_SIZE,0);
00047 sdes_chunk_t *sc=(sdes_chunk_t*)m->b_rptr;
00048 sc->csrc=htonl(ssrc);
00049 m->b_wptr+=sizeof(sc->csrc);
00050 return m;
00051 }
00052
00053
00054 static mblk_t * sdes_chunk_append_item(mblk_t *m, rtcp_sdes_type_t sdes_type, const char *content)
00055 {
00056 if ( content )
00057 {
00058 sdes_item_t si;
00059 si.item_type=sdes_type;
00060 si.len=(uint8_t) MIN(strlen(content),RTCP_SDES_MAX_STRING_SIZE);
00061 m=appendb(m,(char*)&si,RTCP_SDES_ITEM_HEADER_SIZE,FALSE);
00062 m=appendb(m,content,si.len,FALSE);
00063 }
00064 return m;
00065 }
00066
00067 static void sdes_chunk_set_ssrc(mblk_t *m, uint32_t ssrc){
00068 sdes_chunk_t *sc=(sdes_chunk_t*)m->b_rptr;
00069 sc->csrc=htonl(ssrc);
00070 }
00071
00072 #define sdes_chunk_get_ssrc(m) ntohl(((sdes_chunk_t*)((m)->b_rptr))->csrc)
00073
00074 static mblk_t * sdes_chunk_pad(mblk_t *m){
00075 return appendb(m,"",1,TRUE);
00076 }
00077
00082 void rtp_session_set_source_description(RtpSession *session,
00083 const char *cname, const char *name, const char *email, const char *phone,
00084 const char *loc, const char *tool, const char *note){
00085 mblk_t *chunk = sdes_chunk_new(session->snd.ssrc);
00086 mblk_t *m=chunk;
00087 const char *_cname=cname;
00088 if (_cname==NULL)
00089 {
00090 _cname="Unknown";
00091 }
00092 chunk=sdes_chunk_append_item(chunk, RTCP_SDES_CNAME, _cname);
00093 chunk=sdes_chunk_append_item(chunk, RTCP_SDES_NAME, name);
00094 chunk=sdes_chunk_append_item(chunk, RTCP_SDES_EMAIL, email);
00095 chunk=sdes_chunk_append_item(chunk, RTCP_SDES_PHONE, phone);
00096 chunk=sdes_chunk_append_item(chunk, RTCP_SDES_LOC, loc);
00097 chunk=sdes_chunk_append_item(chunk, RTCP_SDES_TOOL, tool);
00098 chunk=sdes_chunk_append_item(chunk, RTCP_SDES_NOTE, note);
00099 chunk=sdes_chunk_pad(chunk);
00100 if (session->sd!=NULL) freemsg(session->sd);
00101 session->sd=m;
00102 }
00103
00104 void
00105 rtp_session_add_contributing_source(RtpSession *session, uint32_t csrc,
00106 const char *cname, const char *name, const char *email, const char *phone,
00107 const char *loc, const char *tool, const char *note)
00108 {
00109 mblk_t *chunk = sdes_chunk_new(csrc);
00110 mblk_t *m=chunk;
00111 char *_cname=(char*)cname;
00112 if (_cname==NULL)
00113 {
00114 _cname="toto";
00115 }
00116 chunk=sdes_chunk_append_item(chunk, RTCP_SDES_CNAME, cname);
00117 chunk=sdes_chunk_append_item(chunk, RTCP_SDES_NAME, name);
00118 chunk=sdes_chunk_append_item(chunk, RTCP_SDES_EMAIL, email);
00119 chunk=sdes_chunk_append_item(chunk, RTCP_SDES_PHONE, phone);
00120 chunk=sdes_chunk_append_item(chunk, RTCP_SDES_LOC, loc);
00121 chunk=sdes_chunk_append_item(chunk, RTCP_SDES_TOOL, tool);
00122 chunk=sdes_chunk_append_item(chunk, RTCP_SDES_NOTE, note);
00123 chunk=sdes_chunk_pad(chunk);
00124 putq(&session->contributing_sources,m);
00125 }
00126
00127
00128
00129 mblk_t* rtp_session_create_rtcp_sdes_packet(RtpSession *session)
00130 {
00131 mblk_t *mp=allocb(sizeof(rtcp_common_header_t),0);
00132 rtcp_common_header_t *rtcp;
00133 mblk_t *tmp,*m=mp;
00134 queue_t *q;
00135 int rc=0;
00136 rtcp = (rtcp_common_header_t*)mp->b_wptr;
00137 mp->b_wptr+=sizeof(rtcp_common_header_t);
00138
00139
00140 sdes_chunk_set_ssrc(session->sd,session->snd.ssrc);
00141 m=concatb(m,dupmsg(session->sd));
00142 rc++;
00143
00144 q=&session->contributing_sources;
00145 for (tmp=qbegin(q); !qend(q,tmp); tmp=qnext(q,mp)){
00146 m=concatb(m,dupmsg(tmp));
00147 rc++;
00148 }
00149 rtcp_common_header_init(rtcp,session,RTCP_SDES,rc,msgdsize(mp));
00150 return mp;
00151 }
00152
00153
00154 mblk_t *rtcp_create_simple_bye_packet(uint32_t ssrc, const char *reason)
00155 {
00156 int packet_size;
00157 int strsize = 0;
00158 int strpadding = 0;
00159 mblk_t *mp;
00160 rtcp_bye_t *rtcp;
00161
00162 packet_size = RTCP_BYE_HEADER_SIZE;
00163 if (reason!=NULL) {
00164 strsize=(int)MIN(strlen(reason),RTCP_BYE_REASON_MAX_STRING_SIZE);
00165 if (strsize > 0) {
00166 strpadding = 3 - (strsize % 4);
00167 packet_size += 1 + strsize + strpadding;
00168 }
00169 }
00170 mp = allocb(packet_size, 0);
00171
00172 rtcp = (rtcp_bye_t*)mp->b_rptr;
00173 rtcp_common_header_init(&rtcp->ch,NULL,RTCP_BYE,1,packet_size);
00174 rtcp->ssrc[0] = htonl(ssrc);
00175 mp->b_wptr += RTCP_BYE_HEADER_SIZE;
00176
00177 if (reason!=NULL) {
00178 const char pad[] = {0, 0, 0};
00179 unsigned char strsize_octet = (unsigned char)strsize;
00180
00181 appendb(mp, (const char*)&strsize_octet, 1, FALSE);
00182 appendb(mp, reason,strsize, FALSE);
00183 appendb(mp, pad,strpadding, FALSE);
00184 }
00185 return mp;
00186 }
00187
00188 void rtp_session_remove_contributing_sources(RtpSession *session, uint32_t ssrc)
00189 {
00190 queue_t *q=&session->contributing_sources;
00191 mblk_t *tmp;
00192 for (tmp=qbegin(q); !qend(q,tmp); tmp=qnext(q,tmp)){
00193 uint32_t csrc=sdes_chunk_get_ssrc(tmp);
00194 if (csrc==ssrc) {
00195 remq(q,tmp);
00196 break;
00197 }
00198 }
00199 tmp=rtcp_create_simple_bye_packet(ssrc, NULL);
00200 rtp_session_rtcp_send(session,tmp);
00201 }
00202
00203 static void sender_info_init(sender_info_t *info, RtpSession *session){
00204 struct timeval tv;
00205 uint32_t tmp;
00206 gettimeofday(&tv,NULL);
00207 info->ntp_timestamp_msw=htonl(tv.tv_sec + 0x83AA7E80);
00208 #if defined(_WIN32_WCE)
00209 tmp=(uint32_t)((double)tv.tv_usec*(double)(((uint64_t)1)<<32)*1.0e-6);
00210 #else
00211 tmp=(uint32_t)((double)tv.tv_usec*(double)(1LL<<32)*1.0e-6);
00212 #endif
00213 info->ntp_timestamp_lsw=htonl(tmp);
00214 info->rtp_timestamp=htonl(session->rtp.snd_last_ts);
00215 info->senders_packet_count=(uint32_t) htonl((u_long) session->rtp.stats.packet_sent);
00216 info->senders_octet_count=(uint32_t) htonl((u_long) session->rtp.stats.sent);
00217 session->rtp.last_rtcp_packet_count=session->rtp.stats.packet_sent;
00218 }
00219
00220
00221
00222 static void report_block_init(report_block_t *b, RtpSession *session){
00223 int packet_loss=0;
00224 uint8_t loss_fraction=0;
00225 RtpStream *stream=&session->rtp;
00226 uint32_t delay_snc_last_sr=0;
00227 uint32_t fl_cnpl;
00228
00229
00230
00231
00232
00233
00234
00235 if (stream->hwrcv_seq_at_last_SR!=0){
00236 packet_loss=(stream->hwrcv_extseq - stream->hwrcv_seq_at_last_SR) - stream->hwrcv_since_last_SR;
00237 if (packet_loss<0)
00238 packet_loss=0;
00239 stream->stats.cum_packet_loss+=packet_loss;
00240 loss_fraction=(int)(256.0*(float)packet_loss/(float)stream->hwrcv_since_last_SR);
00241 }
00242
00243 stream->hwrcv_since_last_SR=0;
00244 stream->hwrcv_seq_at_last_SR=stream->hwrcv_extseq;
00245
00246 if (stream->last_rcv_SR_time.tv_sec!=0){
00247 struct timeval now;
00248 float delay;
00249 gettimeofday(&now,NULL);
00250 delay=(float) ((now.tv_sec-stream->last_rcv_SR_time.tv_sec)*1e6 ) + (now.tv_usec-stream->last_rcv_SR_time.tv_usec);
00251 delay=(float) (delay*65536*1e-6);
00252 delay_snc_last_sr=(uint32_t) delay;
00253 }
00254
00255 b->ssrc=htonl(session->rcv.ssrc);
00256 fl_cnpl=((loss_fraction&0xFF)<<24) | (stream->stats.cum_packet_loss & 0xFFFFFF);
00257 b->fl_cnpl=htonl(fl_cnpl);
00258 b->interarrival_jitter=htonl((uint32_t) stream->jittctl.inter_jitter);
00259 b->ext_high_seq_num_rec=htonl(stream->hwrcv_extseq);
00260 b->lsr=htonl(stream->last_rcv_SR_ts);
00261 b->delay_snc_last_sr=htonl(delay_snc_last_sr);
00262 }
00263
00264
00265
00266 static int rtcp_sr_init(RtpSession *session, uint8_t *buf, int size){
00267 rtcp_sr_t *sr=(rtcp_sr_t*)buf;
00268 int rr=(session->rtp.stats.packet_recv>0);
00269 int sr_size=sizeof(rtcp_sr_t)-sizeof(report_block_t)+(rr*sizeof(report_block_t));
00270 if (size<sr_size) return 0;
00271 rtcp_common_header_init(&sr->ch,session,RTCP_SR,rr,sr_size);
00272 sr->ssrc=htonl(session->snd.ssrc);
00273 sender_info_init(&sr->si,session);
00274
00275 if (rr)
00276 report_block_init(&sr->rb[0],session);
00277 return sr_size;
00278 }
00279
00280 static int rtcp_rr_init(RtpSession *session, uint8_t *buf, int size){
00281 rtcp_rr_t *rr=(rtcp_rr_t*)buf;
00282 if (size<sizeof(rtcp_rr_t)) return 0;
00283 rtcp_common_header_init(&rr->ch,session,RTCP_RR,1,sizeof(rtcp_rr_t));
00284 rr->ssrc=htonl(session->snd.ssrc);
00285 report_block_init(&rr->rb[0],session);
00286 return sizeof(rtcp_rr_t);
00287 }
00288
00289 static int rtcp_app_init(RtpSession *session, uint8_t *buf, uint8_t subtype, const char *name, int size){
00290 rtcp_app_t *app=(rtcp_app_t*)buf;
00291 if (size<sizeof(rtcp_app_t)) return 0;
00292 rtcp_common_header_init(&app->ch,session,RTCP_APP,subtype,size);
00293 app->ssrc=htonl(session->snd.ssrc);
00294 memset(app->name,0,4);
00295 strncpy(app->name,name,4);
00296 return sizeof(rtcp_app_t);
00297 }
00298
00299 static mblk_t * make_rr(RtpSession *session){
00300 mblk_t *cm=NULL;
00301 mblk_t *sdes=NULL;
00302
00303 cm=allocb(sizeof(rtcp_sr_t),0);
00304 cm->b_wptr+=rtcp_rr_init(session,cm->b_wptr,sizeof(rtcp_rr_t));
00305
00306 if (session->sd!=NULL)
00307 sdes=rtp_session_create_rtcp_sdes_packet(session);
00308
00309 cm->b_cont=sdes;
00310 return cm;
00311 }
00312
00313
00314 static mblk_t * make_sr(RtpSession *session){
00315 mblk_t *cm=NULL;
00316 mblk_t *sdes=NULL;
00317
00318 cm=allocb(sizeof(rtcp_sr_t),0);
00319 cm->b_wptr+=rtcp_sr_init(session,cm->b_wptr,sizeof(rtcp_sr_t));
00320
00321 if (session->sd!=NULL)
00322 sdes=rtp_session_create_rtcp_sdes_packet(session);
00323
00324 cm->b_cont=sdes;
00325 return cm;
00326 }
00327
00328 void rtp_session_rtcp_process_send(RtpSession *session){
00329 RtpStream *st=&session->rtp;
00330 mblk_t *m;
00331 if (st->rcv_last_app_ts - st->last_rtcp_report_snt_r > st->rtcp_report_snt_interval
00332 || st->snd_last_ts - st->last_rtcp_report_snt_s > st->rtcp_report_snt_interval){
00333 st->last_rtcp_report_snt_r=st->rcv_last_app_ts;
00334 st->last_rtcp_report_snt_s=st->snd_last_ts;
00335 m=make_sr(session);
00336
00337 rtp_session_rtcp_send(session,m);
00338 ortp_debug("Rtcp compound message sent.");
00339 }
00340 }
00341
00342 void rtp_session_rtcp_process_recv(RtpSession *session){
00343 RtpStream *st=&session->rtp;
00344 mblk_t *m=NULL;
00345 if (st->rcv_last_app_ts - st->last_rtcp_report_snt_r > st->rtcp_report_snt_interval
00346 || st->snd_last_ts - st->last_rtcp_report_snt_s > st->rtcp_report_snt_interval){
00347 st->last_rtcp_report_snt_r=st->rcv_last_app_ts;
00348 st->last_rtcp_report_snt_s=st->snd_last_ts;
00349
00350 if (session->rtp.last_rtcp_packet_count<session->rtp.stats.packet_sent){
00351 m=make_sr(session);
00352 session->rtp.last_rtcp_packet_count=session->rtp.stats.packet_sent;
00353 }else if (session->rtp.stats.packet_recv>0){
00354
00355 m=make_rr(session);
00356 }
00357 if (m!=NULL){
00358
00359 rtp_session_rtcp_send(session,m);
00360 ortp_debug("Rtcp compound message sent.");
00361 }
00362 }
00363 }
00364
00365 void rtp_session_send_rtcp_APP(RtpSession *session, uint8_t subtype, const char *name, const uint8_t *data, int datalen){
00366 mblk_t *h=allocb(sizeof(rtcp_app_t),0);
00367 mblk_t *d;
00368 h->b_wptr+=rtcp_app_init(session,h->b_wptr,subtype,name,datalen+sizeof(rtcp_app_t));
00369 d=esballoc((uint8_t*)data,datalen,0,NULL);
00370 h->b_cont=d;
00371 rtp_session_rtcp_send(session,h);
00372 }
00373
00379 int
00380 rtp_session_bye(RtpSession *session, const char *reason)
00381 {
00382 mblk_t *cm;
00383 mblk_t *sdes = NULL;
00384 mblk_t *bye = NULL;
00385 int ret;
00386
00387
00388 bye = rtcp_create_simple_bye_packet(session->snd.ssrc, reason);
00389
00390
00391 if (session->rtp.stats.packet_sent>0)
00392 {
00393 cm = allocb(sizeof(rtcp_sr_t), 0);
00394 cm->b_wptr += rtcp_sr_init(session,cm->b_wptr, sizeof(rtcp_sr_t));
00395
00396 sdes = rtp_session_create_rtcp_sdes_packet(session);
00397
00398 concatb(concatb(cm, sdes), bye);
00399 } else if (session->rtp.stats.packet_recv>0){
00400
00401 cm = allocb(sizeof(rtcp_rr_t), 0);
00402 cm->b_wptr += rtcp_rr_init(session, cm->b_wptr, sizeof(rtcp_rr_t));
00403
00404 cm->b_cont = bye;
00405 }else cm=bye;
00406
00407
00408 ret = rtp_session_rtcp_send(session, cm);
00409
00410 return ret;
00411 }
00412