mirror of
https://gitlab.linphone.org/BC/public/linphone-iphone.git
synced 2026-05-01 18:06:24 +00:00
git-svn-id: svn+ssh://svn.savannah.nongnu.org/linphone/trunk@1 3f6dc0c8-ddfe-455d-9043-3cd528dc4637
541 lines
15 KiB
C
541 lines
15 KiB
C
/*
|
|
The oRTP library is an RTP (Realtime Transport Protocol - rfc3550) stack.
|
|
Copyright (C) 2001 Simon MORLAT simon.morlat@linphone.org
|
|
|
|
This library is free software; you can redistribute it and/or
|
|
modify it under the terms of the GNU Lesser General Public
|
|
License as published by the Free Software Foundation; either
|
|
version 2.1 of the License, or (at your option) any later version.
|
|
|
|
This library is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
Lesser General Public License for more details.
|
|
|
|
You should have received a copy of the GNU Lesser General Public
|
|
License along with this library; if not, write to the Free Software
|
|
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
*/
|
|
|
|
|
|
#include "ortp/ortp.h"
|
|
#include "utils.h"
|
|
|
|
|
|
/*in case of coumpound packet, set read pointer of m to the beginning of the next RTCP
|
|
packet */
|
|
bool_t rtcp_next_packet(mblk_t *m){
|
|
const rtcp_common_header_t *ch=rtcp_get_common_header(m);
|
|
if (ch){
|
|
int nextlen=sizeof(rtcp_common_header_t)+
|
|
(rtcp_common_header_get_length(ch)*4);
|
|
if (m->b_rptr+nextlen<m->b_wptr){
|
|
m->b_rptr+=nextlen;
|
|
return TRUE;
|
|
}
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
void rtcp_rewind(mblk_t *m){
|
|
m->b_rptr=m->b_datap->db_base;
|
|
}
|
|
|
|
/* get common header; this function will also check the sanity of the packet*/
|
|
const rtcp_common_header_t * rtcp_get_common_header(const mblk_t *m){
|
|
int size=msgdsize(m);
|
|
rtcp_common_header_t *ch;
|
|
if (m->b_cont!=NULL){
|
|
ortp_fatal("RTCP parser does not work on fragmented mblk_t. Use msgpullup() before to re-assemble the packet.");
|
|
return NULL;
|
|
}
|
|
if (size<sizeof(rtcp_common_header_t)){
|
|
ortp_warning("Bad RTCP packet, too short.");
|
|
return NULL;
|
|
}
|
|
ch=(rtcp_common_header_t*)m->b_rptr;
|
|
return ch;
|
|
}
|
|
|
|
bool_t rtcp_is_SR(const mblk_t *m){
|
|
const rtcp_common_header_t *ch=rtcp_get_common_header(m);
|
|
if (ch!=NULL && rtcp_common_header_get_packet_type(ch)==RTCP_SR){
|
|
if (msgdsize(m)<sizeof(rtcp_sr_t)){
|
|
ortp_warning("Too short RTCP SR packet.");
|
|
return FALSE;
|
|
}
|
|
return TRUE;
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
/*Sender Report accessors */
|
|
uint32_t rtcp_SR_get_ssrc(const mblk_t *m){
|
|
rtcp_sr_t *sr=(rtcp_sr_t*)m->b_rptr;
|
|
return ntohl(sr->ssrc);
|
|
}
|
|
|
|
const sender_info_t * rtcp_SR_get_sender_info(const mblk_t *m){
|
|
rtcp_sr_t *sr=(rtcp_sr_t*)m->b_rptr;
|
|
return &sr->si;
|
|
}
|
|
|
|
const report_block_t * rtcp_SR_get_report_block(const mblk_t *m, int idx){
|
|
rtcp_sr_t *sr=(rtcp_sr_t*)m->b_rptr;
|
|
report_block_t *rb=&sr->rb[idx];
|
|
int size=sizeof(rtcp_common_header_t)+(4*rtcp_common_header_get_length(&sr->ch));
|
|
if ( ( (uint8_t*)rb)+sizeof(report_block_t) <= m->b_rptr + size ) {
|
|
return rb;
|
|
}else{
|
|
if (idx<rtcp_common_header_get_rc(&sr->ch)){
|
|
ortp_warning("RTCP packet should include a report_block_t at pos %i but has no space for it.",idx);
|
|
}
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
/*Receiver report accessors*/
|
|
bool_t rtcp_is_RR(const mblk_t *m){
|
|
const rtcp_common_header_t *ch=rtcp_get_common_header(m);
|
|
if (ch!=NULL && rtcp_common_header_get_packet_type(ch)==RTCP_RR){
|
|
if (msgdsize(m)<sizeof(rtcp_rr_t)){
|
|
ortp_warning("Too short RTCP RR packet.");
|
|
return FALSE;
|
|
}
|
|
return TRUE;
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
uint32_t rtcp_RR_get_ssrc(const mblk_t *m){
|
|
rtcp_rr_t *rr=(rtcp_rr_t*)m->b_rptr;
|
|
return ntohl(rr->ssrc);
|
|
}
|
|
|
|
const report_block_t * rtcp_RR_get_report_block(const mblk_t *m,int idx){
|
|
rtcp_rr_t *rr=(rtcp_rr_t*)m->b_rptr;
|
|
report_block_t *rb=&rr->rb[idx];
|
|
int size=sizeof(rtcp_common_header_t)+(4*rtcp_common_header_get_length(&rr->ch));
|
|
if ( ( (uint8_t*)rb)+sizeof(report_block_t) <= (m->b_rptr + size ) ){
|
|
return rb;
|
|
}else{
|
|
if (idx<rtcp_common_header_get_rc(&rr->ch)){
|
|
ortp_warning("RTCP packet should include a report_block_t at pos %i but has no space for it.",idx);
|
|
}
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
/*SDES accessors */
|
|
bool_t rtcp_is_SDES(const mblk_t *m){
|
|
const rtcp_common_header_t *ch=rtcp_get_common_header(m);
|
|
if (ch && rtcp_common_header_get_packet_type(ch)==RTCP_SDES){
|
|
if (msgdsize(m)<sizeof(rtcp_common_header_t)+
|
|
(4*rtcp_common_header_get_length(ch))){
|
|
ortp_warning("Too short RTCP SDES packet.");
|
|
return FALSE;
|
|
}
|
|
return TRUE;
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
void rtcp_sdes_parse(const mblk_t *m, SdesItemFoundCallback cb, void *user_data){
|
|
uint8_t *rptr=(uint8_t*)m->b_rptr+sizeof(rtcp_common_header_t);
|
|
const rtcp_common_header_t *ch=(rtcp_common_header_t*)m->b_rptr;
|
|
uint8_t *end=rptr+sizeof(rtcp_common_header_t)+
|
|
(4*rtcp_common_header_get_length(ch));
|
|
uint32_t ssrc=0;
|
|
int nchunk=0;
|
|
bool_t chunk_start=TRUE;
|
|
|
|
if (end>(uint8_t*)m->b_wptr) end=(uint8_t*)m->b_wptr;
|
|
|
|
while(rptr<end){
|
|
if (chunk_start){
|
|
if (rptr+4<=end){
|
|
ssrc=ntohl(*(uint32_t*)rptr);
|
|
rptr+=4;
|
|
}else{
|
|
ortp_warning("incorrect chunk start in RTCP SDES");
|
|
break;
|
|
}
|
|
chunk_start=FALSE;
|
|
}else{
|
|
if (rptr+2<=end){
|
|
uint8_t type=rptr[0];
|
|
uint8_t len=rptr[1];
|
|
|
|
if (type==RTCP_SDES_END){
|
|
/* pad to next 32bit boundary*/
|
|
rptr=(uint8_t*)(((unsigned long)rptr+4) & ~0x3);
|
|
nchunk++;
|
|
if (nchunk<rtcp_common_header_get_rc(ch)){
|
|
chunk_start=TRUE;
|
|
continue;
|
|
}else break;
|
|
}
|
|
rptr+=2;
|
|
if (rptr+len<=end){
|
|
cb(user_data,ssrc,type,(char*)rptr,len);
|
|
rptr+=len;
|
|
}else{
|
|
ortp_warning("bad item length in RTCP SDES");
|
|
break;
|
|
}
|
|
}else{
|
|
/*end of packet */
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/*BYE accessors */
|
|
bool_t rtcp_is_BYE(const mblk_t *m){
|
|
const rtcp_common_header_t *ch=rtcp_get_common_header(m);
|
|
if (ch && rtcp_common_header_get_packet_type(ch)==RTCP_BYE){
|
|
if (msgdsize(m)<sizeof(rtcp_common_header_t)+
|
|
rtcp_common_header_get_length(ch)){
|
|
ortp_warning("Too short RTCP BYE packet.");
|
|
return FALSE;
|
|
}
|
|
return TRUE;
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
bool_t rtcp_BYE_get_ssrc(const mblk_t *m, int idx, uint32_t *ssrc){
|
|
rtcp_bye_t *bye=(rtcp_bye_t*)m->b_rptr;
|
|
int rc=rtcp_common_header_get_rc(&bye->ch);
|
|
int len=rtcp_common_header_get_length(&bye->ch);
|
|
if (idx<rc){
|
|
if ((uint8_t*)&bye->ssrc[idx]<=(m->b_rptr
|
|
+sizeof(rtcp_common_header_t)+len-4)) {
|
|
*ssrc=ntohl(bye->ssrc[idx]);
|
|
return TRUE;
|
|
}else{
|
|
ortp_warning("RTCP BYE should contain %i ssrc, but there is not enough room for it.");
|
|
}
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
bool_t rtcp_BYE_get_reason(const mblk_t *m, const char **reason, int *reason_len){
|
|
rtcp_bye_t *bye=(rtcp_bye_t*)m->b_rptr;
|
|
int rc=rtcp_common_header_get_rc(&bye->ch);
|
|
int len=rtcp_common_header_get_length(&bye->ch);
|
|
uint8_t *rptr=(uint8_t*)m->b_rptr+sizeof(rtcp_common_header_t)+rc*4;
|
|
uint8_t *end=(uint8_t*)(m->b_rptr+sizeof(rtcp_common_header_t)+len);
|
|
if (rptr<end){
|
|
uint8_t content_len=rptr[0];
|
|
if (rptr+1+content_len<=end){
|
|
*reason=(char*)rptr+1;
|
|
*reason_len=content_len;
|
|
return TRUE;
|
|
}else{
|
|
ortp_warning("RTCP BYE has not enough space for reason phrase.");
|
|
return FALSE;
|
|
}
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
/*APP accessors */
|
|
bool_t rtcp_is_APP(const mblk_t *m){
|
|
const rtcp_common_header_t *ch=rtcp_get_common_header(m);
|
|
if (ch!=NULL && rtcp_common_header_get_packet_type(ch)==RTCP_APP){
|
|
if (msgdsize(m)<sizeof(rtcp_common_header_t)+
|
|
rtcp_common_header_get_length(ch)){
|
|
ortp_warning("Too short RTCP APP packet.");
|
|
return FALSE;
|
|
}
|
|
if (sizeof(rtcp_common_header_t)+rtcp_common_header_get_length(ch)
|
|
< sizeof(rtcp_app_t)){
|
|
ortp_warning("Bad RTCP APP packet.");
|
|
return FALSE;
|
|
}
|
|
return TRUE;
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
int rtcp_APP_get_subtype(const mblk_t *m){
|
|
rtcp_app_t *app=(rtcp_app_t*)m->b_rptr;
|
|
return rtcp_common_header_get_rc(&app->ch);
|
|
}
|
|
|
|
uint32_t rtcp_APP_get_ssrc(const mblk_t *m){
|
|
rtcp_app_t *app=(rtcp_app_t*)m->b_rptr;
|
|
return ntohl(app->ssrc);
|
|
}
|
|
/* name argument is supposed to be at least 4 characters (note: no '\0' written)*/
|
|
void rtcp_APP_get_name(const mblk_t *m, char *name){
|
|
rtcp_app_t *app=(rtcp_app_t*)m->b_rptr;
|
|
memcpy(name,app->name,4);
|
|
}
|
|
/* retrieve the data. when returning, data points directly into the mblk_t */
|
|
void rtcp_APP_get_data(const mblk_t *m, uint8_t **data, int *len){
|
|
rtcp_app_t *app=(rtcp_app_t*)m->b_rptr;
|
|
int datalen=sizeof(rtcp_common_header_t)+rtcp_common_header_get_length(&app->ch)-8;
|
|
if (datalen>0){
|
|
*data=(uint8_t*)m->b_rptr+sizeof(rtcp_app_t);
|
|
*len=datalen;
|
|
}else{
|
|
*len=0;
|
|
*data=NULL;
|
|
}
|
|
}
|
|
|
|
/*old functions: deprecated, but some useful code parts can be reused */
|
|
/* Start from now this source code file was written by Nicola Baldo as an extension of
|
|
the oRTP library. Copyright (C) 2005 Nicola Baldo nicola@baldo.biz*/
|
|
|
|
void report_block_parse(RtpSession *session, report_block_t *rb, struct timeval rcv_time_tv)
|
|
{
|
|
rb->ssrc = ntohl(rb->ssrc);
|
|
|
|
if ( rb->ssrc != session->snd.ssrc )
|
|
|
|
{
|
|
ortp_debug("Received rtcp report block related to unknown ssrc (not from us)... discarded");
|
|
return;
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
uint32_t rcv_time_msw;
|
|
uint32_t rcv_time_lsw;
|
|
uint32_t rcv_time;
|
|
double rtt;
|
|
|
|
rcv_time_msw = rcv_time_tv.tv_sec;
|
|
#if defined(_WIN32_WCE)
|
|
rcv_time_lsw = (uint32_t) ((double)rcv_time_tv.tv_usec*(double)(((uint64_t)1)<<32)*1.0e-6);
|
|
#else
|
|
rcv_time_lsw = (uint32_t) ((double)rcv_time_tv.tv_usec*(double)(1LL<<32)*1.0e-6);
|
|
#endif
|
|
rcv_time = (rcv_time_msw<<16) | (rcv_time_lsw >> 16);
|
|
|
|
/*
|
|
rb->cum_num_packet_lost = ntoh24(rb->cum_num_packet_lost);
|
|
rb->ext_high_seq_num_rec = ntohl(rb->ext_high_seq_num_rec);
|
|
rb->interarrival_jitter = ntohl(rb->interarrival_jitter);
|
|
rb->lsr = ntohl(rb->lsr);
|
|
rb->delay_snc_last_sr = ntohl(rb->delay_snc_last_sr);
|
|
*/
|
|
|
|
/* calculating Round Trip Time*/
|
|
if (rb->lsr != 0)
|
|
{
|
|
rtt = (double) (rcv_time - rb->delay_snc_last_sr - rb->lsr);
|
|
rtt = rtt/65536;
|
|
//printf("RTT = %f s\n",rtt);
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
void rtp_session_rtcp_parse(RtpSession *session, mblk_t *mp)
|
|
{
|
|
rtcp_common_header_t *rtcp;
|
|
int msgsize;
|
|
int rtcp_pk_size;
|
|
RtpStream *rtpstream=&session->rtp;
|
|
struct timeval rcv_time_tv;
|
|
|
|
|
|
gettimeofday(&rcv_time_tv,NULL);
|
|
|
|
return_if_fail(mp!=NULL);
|
|
|
|
msgsize=(int) (mp->b_wptr-mp->b_rptr);
|
|
|
|
if (msgsize < RTCP_COMMON_HEADER_SIZE)
|
|
{
|
|
ortp_debug("Receiving too short rtcp packet... discarded");
|
|
return;
|
|
}
|
|
|
|
rtcp=(rtcp_common_header_t *)mp->b_rptr;
|
|
|
|
/* compound rtcp packet can be composed by more than one rtcp message */
|
|
while (msgsize >= RTCP_COMMON_HEADER_SIZE)
|
|
{
|
|
|
|
if (rtcp->version!=2)
|
|
{
|
|
ortp_debug("Receiving rtcp packet with version number !=2...discarded");
|
|
return;
|
|
}
|
|
|
|
/* convert header data from network order to host order */
|
|
rtcp->length = ntohs(rtcp->length);
|
|
|
|
/* compute length */
|
|
rtcp_pk_size = (rtcp->length + 1) * 4;
|
|
/* Sanity check of simple RTCP packet length. */
|
|
if (rtcp_pk_size > msgsize)
|
|
{
|
|
ortp_debug("Receiving rtcp packet shorter than the specified length.. discared");
|
|
return;
|
|
}
|
|
|
|
switch (rtcp->packet_type)
|
|
|
|
{
|
|
|
|
case RTCP_SR:
|
|
|
|
{
|
|
rtcp_sr_t *sr = (rtcp_sr_t *) rtcp;
|
|
report_block_t *rb;
|
|
int i;
|
|
|
|
if ( ntohl(sr->ssrc) != session->rcv.ssrc )
|
|
{
|
|
ortp_debug("Receiving rtcp sr packet from unknown ssrc.. discarded");
|
|
return;
|
|
}
|
|
|
|
if (msgsize < RTCP_COMMON_HEADER_SIZE + RTCP_SSRC_FIELD_SIZE + RTCP_SENDER_INFO_SIZE + (RTCP_REPORT_BLOCK_SIZE*sr->ch.rc))
|
|
{
|
|
ortp_debug("Receiving too short rtcp sr packet... discarded");
|
|
return;
|
|
}
|
|
|
|
/* parsing RTCP Sender Info */
|
|
sr->si.ntp_timestamp_msw = ntohl(sr->si.ntp_timestamp_msw);
|
|
sr->si.ntp_timestamp_lsw = ntohl(sr->si.ntp_timestamp_lsw);
|
|
sr->si.rtp_timestamp = ntohl(sr->si.rtp_timestamp);
|
|
sr->si.senders_packet_count = ntohl(sr->si.senders_packet_count);
|
|
sr->si.senders_octet_count = ntohl(sr->si.senders_octet_count);
|
|
|
|
/* saving data to fill LSR and DLSR field in next RTCP report to be transmitted */
|
|
rtpstream->last_rcv_SR_ts = (sr->si.ntp_timestamp_msw << 16) | (sr->si.ntp_timestamp_lsw >> 16);
|
|
rtpstream->last_rcv_SR_time.tv_usec = rcv_time_tv.tv_usec;
|
|
rtpstream->last_rcv_SR_time.tv_sec = rcv_time_tv.tv_sec;
|
|
|
|
|
|
/* parsing all RTCP report blocks */
|
|
for (i=0; i<sr->ch.rc; i++)
|
|
{
|
|
rb = &(sr->rb[i]);
|
|
report_block_parse(session, rb, rcv_time_tv);
|
|
}
|
|
|
|
}
|
|
break;
|
|
|
|
|
|
|
|
case RTCP_RR:
|
|
|
|
{
|
|
rtcp_rr_t *rr = (rtcp_rr_t *) rtcp;
|
|
report_block_t *rb;
|
|
int i;
|
|
|
|
if (session->rcv.ssrc == 0)
|
|
{
|
|
/* rcv.ssrc is not set, so we adopt the incoming one */
|
|
session->rcv.ssrc = ntohl(rr->ssrc);
|
|
}
|
|
else if ( ntohl(rr->ssrc) != session->rcv.ssrc )
|
|
{
|
|
ortp_debug("Receiving rtcp rr packet from unknown ssrc.. discarded");
|
|
return;
|
|
}
|
|
|
|
if (msgsize < RTCP_COMMON_HEADER_SIZE + RTCP_SSRC_FIELD_SIZE + (RTCP_REPORT_BLOCK_SIZE*rr->ch.rc))
|
|
{
|
|
ortp_debug("Receiving too short rtcp sr packet... discarded");
|
|
return;
|
|
}
|
|
|
|
/* parsing all RTCP report blocks */
|
|
for (i=0; i<rr->ch.rc; i++)
|
|
{
|
|
rb = &(rr->rb[i]);
|
|
report_block_parse(session, rb, rcv_time_tv);
|
|
}
|
|
|
|
}
|
|
break;
|
|
|
|
|
|
case RTCP_SDES:
|
|
/* to be implemented */
|
|
break;
|
|
|
|
|
|
case RTCP_BYE:
|
|
{
|
|
rtcp_bye_t *bye = (rtcp_bye_t *) rtcp;
|
|
unsigned sclen = bye->ch.rc * 4;
|
|
int reason_space_len = rtcp_pk_size
|
|
- sizeof (rtcp_common_header_t)
|
|
- sclen;
|
|
int i;
|
|
char *reason = NULL;
|
|
bool_t rcv_ssrc_match = FALSE;
|
|
|
|
if (reason_space_len < 0) {
|
|
ortp_debug("Receiving too short RTCP BYE packet... discarded");
|
|
return;
|
|
}
|
|
for (i = 0; i < bye->ch.rc; i++) {
|
|
if (ntohl(bye->ssrc[i]) == session->rcv.ssrc) {
|
|
rcv_ssrc_match = TRUE;
|
|
break;
|
|
}
|
|
}
|
|
if (rcv_ssrc_match) {
|
|
if (session->on_rtcp_bye.count > 0) {
|
|
/* Get reason. */
|
|
if (reason_space_len > 1) {
|
|
uint8_t *reasonbuf = (uint8_t *) rtcp
|
|
+ sizeof (rtcp_common_header_t)
|
|
+ sclen;
|
|
if (reasonbuf[0] <= reason_space_len-1)
|
|
reason = ortp_strndup((char *)(reasonbuf+1), reasonbuf[0]);
|
|
else
|
|
ortp_debug("Incorrect RTCP BYE reason length");
|
|
}
|
|
rtp_signal_table_emit2(&session->on_rtcp_bye,
|
|
(long)reason);
|
|
if (reason)
|
|
ortp_free(reason);
|
|
} else {
|
|
ortp_debug("Got RTCP BYE without RTCP BYE handler");
|
|
}
|
|
} else {
|
|
ortp_debug("No SSRC in the BYE packet matched our rcv.ssrc.");
|
|
}
|
|
break;
|
|
}
|
|
|
|
case RTCP_APP:
|
|
/* to be implemented */
|
|
break;
|
|
|
|
|
|
default:
|
|
|
|
ortp_debug("Receiving unknown rtcp packet type... discarded");
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
msgsize -= rtcp_pk_size; /* size of unparsed portion of UDP packet, in octets */
|
|
rtcp = (rtcp_common_header_t *) (rtcp_pk_size + (char *) rtcp); /* pointer to next RTCP packet in current UDP packet */
|
|
|
|
}
|
|
|
|
/* The function did not failed sanity checks, write down the RTPC/RTCP
|
|
reception time. */
|
|
session->last_recv_time = rcv_time_tv;
|
|
}
|