2 The oRTP library is an RTP (Realtime Transport Protocol - rfc3550) stack.
3 Copyright (C) 2001 Simon MORLAT simon.morlat@linphone.org
5 This library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Lesser General Public
7 License as published by the Free Software Foundation; either
8 version 2.1 of the License, or (at your option) any later version.
10 This library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Lesser General Public License for more details.
15 You should have received a copy of the GNU Lesser General Public
16 License along with this library; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21 #include "ortp/ortp.h"
25 /*in case of coumpound packet, set read pointer of m to the beginning of the next RTCP
27 bool_t rtcp_next_packet(mblk_t *m){
28 const rtcp_common_header_t *ch=rtcp_get_common_header(m);
30 int nextlen=sizeof(rtcp_common_header_t)+
31 (rtcp_common_header_get_length(ch)*4);
32 if (m->b_rptr+nextlen<m->b_wptr){
40 void rtcp_rewind(mblk_t *m){
41 m->b_rptr=m->b_datap->db_base;
44 /* get common header; this function will also check the sanity of the packet*/
45 const rtcp_common_header_t * rtcp_get_common_header(const mblk_t *m){
47 rtcp_common_header_t *ch;
49 ortp_fatal("RTCP parser does not work on fragmented mblk_t. Use msgpullup() before to re-assemble the packet.");
52 if (size<sizeof(rtcp_common_header_t)){
53 ortp_warning("Bad RTCP packet, too short.");
56 ch=(rtcp_common_header_t*)m->b_rptr;
60 bool_t rtcp_is_SR(const mblk_t *m){
61 const rtcp_common_header_t *ch=rtcp_get_common_header(m);
62 if (ch!=NULL && rtcp_common_header_get_packet_type(ch)==RTCP_SR){
63 if (msgdsize(m)<sizeof(rtcp_sr_t)){
64 ortp_warning("Too short RTCP SR packet.");
72 /*Sender Report accessors */
73 uint32_t rtcp_SR_get_ssrc(const mblk_t *m){
74 rtcp_sr_t *sr=(rtcp_sr_t*)m->b_rptr;
75 return ntohl(sr->ssrc);
78 const sender_info_t * rtcp_SR_get_sender_info(const mblk_t *m){
79 rtcp_sr_t *sr=(rtcp_sr_t*)m->b_rptr;
83 const report_block_t * rtcp_SR_get_report_block(const mblk_t *m, int idx){
84 rtcp_sr_t *sr=(rtcp_sr_t*)m->b_rptr;
85 report_block_t *rb=&sr->rb[idx];
86 int size=sizeof(rtcp_common_header_t)+(4*rtcp_common_header_get_length(&sr->ch));
87 if ( ( (uint8_t*)rb)+sizeof(report_block_t) <= m->b_rptr + size ) {
90 if (idx<rtcp_common_header_get_rc(&sr->ch)){
91 ortp_warning("RTCP packet should include a report_block_t at pos %i but has no space for it.",idx);
97 /*Receiver report accessors*/
98 bool_t rtcp_is_RR(const mblk_t *m){
99 const rtcp_common_header_t *ch=rtcp_get_common_header(m);
100 if (ch!=NULL && rtcp_common_header_get_packet_type(ch)==RTCP_RR){
101 if (msgdsize(m)<sizeof(rtcp_rr_t)){
102 ortp_warning("Too short RTCP RR packet.");
110 uint32_t rtcp_RR_get_ssrc(const mblk_t *m){
111 rtcp_rr_t *rr=(rtcp_rr_t*)m->b_rptr;
112 return ntohl(rr->ssrc);
115 const report_block_t * rtcp_RR_get_report_block(const mblk_t *m,int idx){
116 rtcp_rr_t *rr=(rtcp_rr_t*)m->b_rptr;
117 report_block_t *rb=&rr->rb[idx];
118 int size=sizeof(rtcp_common_header_t)+(4*rtcp_common_header_get_length(&rr->ch));
119 if ( ( (uint8_t*)rb)+sizeof(report_block_t) <= (m->b_rptr + size ) ){
122 if (idx<rtcp_common_header_get_rc(&rr->ch)){
123 ortp_warning("RTCP packet should include a report_block_t at pos %i but has no space for it.",idx);
130 bool_t rtcp_is_SDES(const mblk_t *m){
131 const rtcp_common_header_t *ch=rtcp_get_common_header(m);
132 if (ch && rtcp_common_header_get_packet_type(ch)==RTCP_SDES){
133 if (msgdsize(m)<sizeof(rtcp_common_header_t)+
134 (4*rtcp_common_header_get_length(ch))){
135 ortp_warning("Too short RTCP SDES packet.");
143 void rtcp_sdes_parse(const mblk_t *m, SdesItemFoundCallback cb, void *user_data){
144 uint8_t *rptr=(uint8_t*)m->b_rptr+sizeof(rtcp_common_header_t);
145 const rtcp_common_header_t *ch=(rtcp_common_header_t*)m->b_rptr;
146 uint8_t *end=rptr+sizeof(rtcp_common_header_t)+
147 (4*rtcp_common_header_get_length(ch));
150 bool_t chunk_start=TRUE;
152 if (end>(uint8_t*)m->b_wptr) end=(uint8_t*)m->b_wptr;
157 ssrc=ntohl(*(uint32_t*)rptr);
160 ortp_warning("incorrect chunk start in RTCP SDES");
166 uint8_t type=rptr[0];
169 if (type==RTCP_SDES_END){
170 /* pad to next 32bit boundary*/
171 rptr=(uint8_t*)(((unsigned long)rptr+4) & ~0x3);
173 if (nchunk<rtcp_common_header_get_rc(ch)){
180 cb(user_data,ssrc,type,(char*)rptr,len);
183 ortp_warning("bad item length in RTCP SDES");
195 bool_t rtcp_is_BYE(const mblk_t *m){
196 const rtcp_common_header_t *ch=rtcp_get_common_header(m);
197 if (ch && rtcp_common_header_get_packet_type(ch)==RTCP_BYE){
198 if (msgdsize(m)<sizeof(rtcp_common_header_t)+
199 rtcp_common_header_get_length(ch)){
200 ortp_warning("Too short RTCP BYE packet.");
208 bool_t rtcp_BYE_get_ssrc(const mblk_t *m, int idx, uint32_t *ssrc){
209 rtcp_bye_t *bye=(rtcp_bye_t*)m->b_rptr;
210 int rc=rtcp_common_header_get_rc(&bye->ch);
211 int len=rtcp_common_header_get_length(&bye->ch);
213 if ((uint8_t*)&bye->ssrc[idx]<=(m->b_rptr
214 +sizeof(rtcp_common_header_t)+len-4)) {
215 *ssrc=ntohl(bye->ssrc[idx]);
218 ortp_warning("RTCP BYE should contain %i ssrc, but there is not enough room for it.");
224 bool_t rtcp_BYE_get_reason(const mblk_t *m, const char **reason, int *reason_len){
225 rtcp_bye_t *bye=(rtcp_bye_t*)m->b_rptr;
226 int rc=rtcp_common_header_get_rc(&bye->ch);
227 int len=rtcp_common_header_get_length(&bye->ch);
228 uint8_t *rptr=(uint8_t*)m->b_rptr+sizeof(rtcp_common_header_t)+rc*4;
229 uint8_t *end=(uint8_t*)(m->b_rptr+sizeof(rtcp_common_header_t)+len);
231 uint8_t content_len=rptr[0];
232 if (rptr+1+content_len<=end){
233 *reason=(char*)rptr+1;
234 *reason_len=content_len;
237 ortp_warning("RTCP BYE has not enough space for reason phrase.");
245 bool_t rtcp_is_APP(const mblk_t *m){
246 const rtcp_common_header_t *ch=rtcp_get_common_header(m);
247 if (ch!=NULL && rtcp_common_header_get_packet_type(ch)==RTCP_APP){
248 if (msgdsize(m)<sizeof(rtcp_common_header_t)+
249 rtcp_common_header_get_length(ch)){
250 ortp_warning("Too short RTCP APP packet.");
253 if (sizeof(rtcp_common_header_t)+rtcp_common_header_get_length(ch)
254 < sizeof(rtcp_app_t)){
255 ortp_warning("Bad RTCP APP packet.");
263 int rtcp_APP_get_subtype(const mblk_t *m){
264 rtcp_app_t *app=(rtcp_app_t*)m->b_rptr;
265 return rtcp_common_header_get_rc(&app->ch);
268 uint32_t rtcp_APP_get_ssrc(const mblk_t *m){
269 rtcp_app_t *app=(rtcp_app_t*)m->b_rptr;
270 return ntohl(app->ssrc);
272 /* name argument is supposed to be at least 4 characters (note: no '\0' written)*/
273 void rtcp_APP_get_name(const mblk_t *m, char *name){
274 rtcp_app_t *app=(rtcp_app_t*)m->b_rptr;
275 memcpy(name,app->name,4);
277 /* retrieve the data. when returning, data points directly into the mblk_t */
278 void rtcp_APP_get_data(const mblk_t *m, uint8_t **data, int *len){
279 rtcp_app_t *app=(rtcp_app_t*)m->b_rptr;
280 int datalen=sizeof(rtcp_common_header_t)+rtcp_common_header_get_length(&app->ch)-8;
282 *data=(uint8_t*)m->b_rptr+sizeof(rtcp_app_t);
290 /*old functions: deprecated, but some useful code parts can be reused */
291 /* Start from now this source code file was written by Nicola Baldo as an extension of
292 the oRTP library. Copyright (C) 2005 Nicola Baldo nicola@baldo.biz*/
294 void report_block_parse(RtpSession *session, report_block_t *rb, struct timeval rcv_time_tv)
296 rb->ssrc = ntohl(rb->ssrc);
298 if ( rb->ssrc != session->snd.ssrc )
301 ortp_debug("Received rtcp report block related to unknown ssrc (not from us)... discarded");
308 uint32_t rcv_time_msw;
309 uint32_t rcv_time_lsw;
313 rcv_time_msw = rcv_time_tv.tv_sec;
314 #if defined(_WIN32_WCE)
315 rcv_time_lsw = (uint32_t) ((double)rcv_time_tv.tv_usec*(double)(((uint64_t)1)<<32)*1.0e-6);
317 rcv_time_lsw = (uint32_t) ((double)rcv_time_tv.tv_usec*(double)(1LL<<32)*1.0e-6);
319 rcv_time = (rcv_time_msw<<16) | (rcv_time_lsw >> 16);
322 rb->cum_num_packet_lost = ntoh24(rb->cum_num_packet_lost);
323 rb->ext_high_seq_num_rec = ntohl(rb->ext_high_seq_num_rec);
324 rb->interarrival_jitter = ntohl(rb->interarrival_jitter);
325 rb->lsr = ntohl(rb->lsr);
326 rb->delay_snc_last_sr = ntohl(rb->delay_snc_last_sr);
329 /* calculating Round Trip Time*/
332 rtt = (double) (rcv_time - rb->delay_snc_last_sr - rb->lsr);
334 //printf("RTT = %f s\n",rtt);
341 void rtp_session_rtcp_parse(RtpSession *session, mblk_t *mp)
343 rtcp_common_header_t *rtcp;
346 RtpStream *rtpstream=&session->rtp;
347 struct timeval rcv_time_tv;
350 gettimeofday(&rcv_time_tv,NULL);
352 return_if_fail(mp!=NULL);
354 msgsize=(int) (mp->b_wptr-mp->b_rptr);
356 if (msgsize < RTCP_COMMON_HEADER_SIZE)
358 ortp_debug("Receiving too short rtcp packet... discarded");
362 rtcp=(rtcp_common_header_t *)mp->b_rptr;
364 /* compound rtcp packet can be composed by more than one rtcp message */
365 while (msgsize >= RTCP_COMMON_HEADER_SIZE)
368 if (rtcp->version!=2)
370 ortp_debug("Receiving rtcp packet with version number !=2...discarded");
374 /* convert header data from network order to host order */
375 rtcp->length = ntohs(rtcp->length);
378 rtcp_pk_size = (rtcp->length + 1) * 4;
379 /* Sanity check of simple RTCP packet length. */
380 if (rtcp_pk_size > msgsize)
382 ortp_debug("Receiving rtcp packet shorter than the specified length.. discared");
386 switch (rtcp->packet_type)
393 rtcp_sr_t *sr = (rtcp_sr_t *) rtcp;
397 if ( ntohl(sr->ssrc) != session->rcv.ssrc )
399 ortp_debug("Receiving rtcp sr packet from unknown ssrc.. discarded");
403 if (msgsize < RTCP_COMMON_HEADER_SIZE + RTCP_SSRC_FIELD_SIZE + RTCP_SENDER_INFO_SIZE + (RTCP_REPORT_BLOCK_SIZE*sr->ch.rc))
405 ortp_debug("Receiving too short rtcp sr packet... discarded");
409 /* parsing RTCP Sender Info */
410 sr->si.ntp_timestamp_msw = ntohl(sr->si.ntp_timestamp_msw);
411 sr->si.ntp_timestamp_lsw = ntohl(sr->si.ntp_timestamp_lsw);
412 sr->si.rtp_timestamp = ntohl(sr->si.rtp_timestamp);
413 sr->si.senders_packet_count = ntohl(sr->si.senders_packet_count);
414 sr->si.senders_octet_count = ntohl(sr->si.senders_octet_count);
416 /* saving data to fill LSR and DLSR field in next RTCP report to be transmitted */
417 rtpstream->last_rcv_SR_ts = (sr->si.ntp_timestamp_msw << 16) | (sr->si.ntp_timestamp_lsw >> 16);
418 rtpstream->last_rcv_SR_time.tv_usec = rcv_time_tv.tv_usec;
419 rtpstream->last_rcv_SR_time.tv_sec = rcv_time_tv.tv_sec;
422 /* parsing all RTCP report blocks */
423 for (i=0; i<sr->ch.rc; i++)
426 report_block_parse(session, rb, rcv_time_tv);
437 rtcp_rr_t *rr = (rtcp_rr_t *) rtcp;
441 if (session->rcv.ssrc == 0)
443 /* rcv.ssrc is not set, so we adopt the incoming one */
444 session->rcv.ssrc = ntohl(rr->ssrc);
446 else if ( ntohl(rr->ssrc) != session->rcv.ssrc )
448 ortp_debug("Receiving rtcp rr packet from unknown ssrc.. discarded");
452 if (msgsize < RTCP_COMMON_HEADER_SIZE + RTCP_SSRC_FIELD_SIZE + (RTCP_REPORT_BLOCK_SIZE*rr->ch.rc))
454 ortp_debug("Receiving too short rtcp sr packet... discarded");
458 /* parsing all RTCP report blocks */
459 for (i=0; i<rr->ch.rc; i++)
462 report_block_parse(session, rb, rcv_time_tv);
470 /* to be implemented */
476 rtcp_bye_t *bye = (rtcp_bye_t *) rtcp;
477 unsigned sclen = bye->ch.rc * 4;
478 int reason_space_len = rtcp_pk_size
479 - sizeof (rtcp_common_header_t)
483 bool_t rcv_ssrc_match = FALSE;
485 if (reason_space_len < 0) {
486 ortp_debug("Receiving too short RTCP BYE packet... discarded");
489 for (i = 0; i < bye->ch.rc; i++) {
490 if (ntohl(bye->ssrc[i]) == session->rcv.ssrc) {
491 rcv_ssrc_match = TRUE;
495 if (rcv_ssrc_match) {
496 if (session->on_rtcp_bye.count > 0) {
498 if (reason_space_len > 1) {
499 uint8_t *reasonbuf = (uint8_t *) rtcp
500 + sizeof (rtcp_common_header_t)
502 if (reasonbuf[0] <= reason_space_len-1)
503 reason = ortp_strndup((char *)(reasonbuf+1), reasonbuf[0]);
505 ortp_debug("Incorrect RTCP BYE reason length");
507 rtp_signal_table_emit2(&session->on_rtcp_bye,
512 ortp_debug("Got RTCP BYE without RTCP BYE handler");
515 ortp_debug("No SSRC in the BYE packet matched our rcv.ssrc.");
521 /* to be implemented */
527 ortp_debug("Receiving unknown rtcp packet type... discarded");
533 msgsize -= rtcp_pk_size; /* size of unparsed portion of UDP packet, in octets */
534 rtcp = (rtcp_common_header_t *) (rtcp_pk_size + (char *) rtcp); /* pointer to next RTCP packet in current UDP packet */
538 /* The function did not failed sanity checks, write down the RTPC/RTCP
540 session->last_recv_time = rcv_time_tv;