📄 rtpsession.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*/#if defined(WIN32) || defined(_WIN32_WCE)#include "ortp-config-win32.h"#else#include "ortp-config.h"#endif#include "ortp/ortp.h"#include "ortp/telephonyevents.h"#include "ortp/rtcp.h"#include "jitterctl.h"#include "scheduler.h"#include "utils.h"#include "rtpsession_priv.h"extern mblk_t *rtcp_create_simple_bye_packet(uint32_t ssrc, const char *reason);extern int rtcp_sr_init(RtpSession *session, char *buf, int size);extern int rtcp_rr_init(RtpSession *session, char *buf, int size);/* this function initialize all session parameter's that depend on the payload type */static void payload_type_changed(RtpSession *session, PayloadType *pt){ jitter_control_set_payload(&session->rtp.jittctl,pt); session->rtp.rtcp_report_snt_interval=RTCP_DEFAULT_REPORT_INTERVAL*pt->clock_rate; rtp_session_set_time_jump_limit(session,session->rtp.time_jump); if (pt->type==PAYLOAD_VIDEO){ session->permissive=TRUE; ortp_message("Using permissive algorithm"); } else session->permissive=FALSE;}void wait_point_init(WaitPoint *wp){ ortp_mutex_init(&wp->lock,NULL); ortp_cond_init(&wp->cond,NULL); wp->time=0; wp->wakeup=FALSE;}void wait_point_uninit(WaitPoint *wp){ ortp_cond_destroy(&wp->cond); ortp_mutex_destroy(&wp->lock);}#define wait_point_lock(wp) ortp_mutex_lock(&(wp)->lock)#define wait_point_unlock(wp) ortp_mutex_unlock(&(wp)->lock)void wait_point_wakeup_at(WaitPoint *wp, uint32_t t, bool_t dosleep){ wp->time=t; wp->wakeup=TRUE; if (dosleep) ortp_cond_wait(&wp->cond,&wp->lock);}bool_t wait_point_check(WaitPoint *wp, uint32_t t){ bool_t ok=FALSE; if (wp->wakeup){ if (TIME_IS_NEWER_THAN(t,wp->time)){ wp->wakeup=FALSE; ok=TRUE; } } return ok;}#define wait_point_wakeup(wp) ortp_cond_signal(&(wp)->cond);extern void rtp_parse(RtpSession *session, mblk_t *mp, uint32_t local_str_ts, struct sockaddr *addr, socklen_t addrlen);static uint32_t uint32_t_random(){ return random();}#define RTP_SEQ_IS_GREATER(seq1,seq2)\ ((uint16_t)((uint16_t)(seq1) - (uint16_t)(seq2))< (uint16_t)(1<<15))/* put an rtp packet in queue. It is called by rtp_parse()*/void rtp_putq(queue_t *q, mblk_t *mp){ mblk_t *tmp; rtp_header_t *rtp=(rtp_header_t*)mp->b_rptr,*tmprtp; /* insert message block by increasing time stamp order : the last (at the bottom) message of the queue is the newest*/ ortp_debug("rtp_putq(): Enqueuing packet with ts=%i and seq=%i",rtp->timestamp,rtp->seq_number); if (qempty(q)) { putq(q,mp); return; } tmp=qlast(q); /* we look at the queue from bottom to top, because enqueued packets have a better chance to be enqueued at the bottom, since there are surely newer */ while (!qend(q,tmp)) { tmprtp=(rtp_header_t*)tmp->b_rptr; ortp_debug("rtp_putq(): Seeing packet with seq=%i",tmprtp->seq_number); if (rtp->seq_number == tmprtp->seq_number) { /* this is a duplicated packet. Don't queue it */ ortp_debug("rtp_putq: duplicated message."); freemsg(mp); return; }else if (RTP_SEQ_IS_GREATER(rtp->seq_number,tmprtp->seq_number)){ insq(q,tmp->b_next,mp); return; } tmp=tmp->b_prev; } /* this packet is the oldest, it has to be placed on top of the queue */ insq(q,qfirst(q),mp); }mblk_t *rtp_getq(queue_t *q,uint32_t timestamp, int *rejected){ mblk_t *tmp,*ret=NULL,*old=NULL; rtp_header_t *tmprtp; uint32_t ts_found=0; *rejected=0; ortp_debug("rtp_getq(): Timestamp %i wanted.",timestamp); if (qempty(q)) { /*ortp_debug("rtp_getq: q is empty.");*/ return NULL; } /* return the packet with ts just equal or older than the asked timestamp */ /* packets with older timestamps are discarded */ while ((tmp=qfirst(q))!=NULL) { tmprtp=(rtp_header_t*)tmp->b_rptr; ortp_debug("rtp_getq: Seeing packet with ts=%i",tmprtp->timestamp); if ( RTP_TIMESTAMP_IS_NEWER_THAN(timestamp,tmprtp->timestamp) ) { if (ret!=NULL && tmprtp->timestamp==ts_found) { /* we've found two packets with same timestamp. return the first one */ break; } if (old!=NULL) { ortp_debug("rtp_getq: discarding too old packet with ts=%i",ts_found); (*rejected)++; freemsg(old); } ret=getq(q); /* dequeue the packet, since it has an interesting timestamp*/ ts_found=tmprtp->timestamp; ortp_debug("rtp_getq: Found packet with ts=%i",tmprtp->timestamp); old=ret; } else { break; } } return ret;}mblk_t *rtp_getq_permissive(queue_t *q,uint32_t timestamp, int *rejected){ mblk_t *tmp,*ret=NULL; rtp_header_t *tmprtp; *rejected=0; ortp_debug("rtp_getq_permissive(): Timestamp %i wanted.",timestamp); if (qempty(q)) { /*ortp_debug("rtp_getq: q is empty.");*/ return NULL; } /* return the packet with the older timestamp (provided that it is older than the asked timestamp) */ tmp=qfirst(q); tmprtp=(rtp_header_t*)tmp->b_rptr; ortp_debug("rtp_getq_permissive: Seeing packet with ts=%i",tmprtp->timestamp); if ( RTP_TIMESTAMP_IS_NEWER_THAN(timestamp,tmprtp->timestamp) ) { ret=getq(q); /* dequeue the packet, since it has an interesting timestamp*/ ortp_debug("rtp_getq_permissive: Found packet with ts=%i",tmprtp->timestamp); } return ret;}voidrtp_session_init (RtpSession * session, int mode){ JBParameters jbp; memset (session, 0, sizeof (RtpSession)); session->mode = (RtpSessionMode) mode; if ((mode == RTP_SESSION_RECVONLY) || (mode == RTP_SESSION_SENDRECV)) { rtp_session_set_flag (session, RTP_SESSION_RECV_SYNC); rtp_session_set_flag (session, RTP_SESSION_RECV_NOT_STARTED); } if ((mode == RTP_SESSION_SENDONLY) || (mode == RTP_SESSION_SENDRECV)) { rtp_session_set_flag (session, RTP_SESSION_SEND_NOT_STARTED); session->snd.ssrc=uint32_t_random(); /* set default source description */ rtp_session_set_source_description(session,"unknown@unknown",NULL,NULL, NULL,NULL,"oRTP-" ORTP_VERSION,"This is free sofware (LGPL) !"); } session->snd.telephone_events_pt=-1; /* not defined a priori */ session->rcv.telephone_events_pt=-1; /* not defined a priori */ rtp_session_set_profile (session, &av_profile); /*the default profile to work with */ session->rtp.socket=-1; session->rtcp.socket=-1;#ifndef WIN32 session->rtp.snd_socket_size=0; /*use OS default value unless on windows where they are definitely too short*/ session->rtp.rcv_socket_size=0;#else session->rtp.snd_socket_size=session->rtp.rcv_socket_size=65536;#endif session->dscp=RTP_DEFAULT_DSCP; session->multicast_ttl=RTP_DEFAULT_MULTICAST_TTL; session->multicast_loopback=RTP_DEFAULT_MULTICAST_LOOPBACK; qinit(&session->rtp.rq); qinit(&session->rtp.tev_rq); qinit(&session->contributing_sources); session->eventqs=NULL; /* init signal tables */ rtp_signal_table_init (&session->on_ssrc_changed, session,"ssrc_changed"); rtp_signal_table_init (&session->on_payload_type_changed, session,"payload_type_changed"); rtp_signal_table_init (&session->on_telephone_event, session,"telephone-event"); rtp_signal_table_init (&session->on_telephone_event_packet, session,"telephone-event_packet"); rtp_signal_table_init (&session->on_timestamp_jump,session,"timestamp_jump"); rtp_signal_table_init (&session->on_network_error,session,"network_error"); rtp_signal_table_init (&session->on_rtcp_bye,session,"rtcp_bye"); wait_point_init(&session->snd.wp); wait_point_init(&session->rcv.wp); /*defaults send payload type to 0 (pcmu)*/ rtp_session_set_send_payload_type(session,0); /*sets supposed recv payload type to undefined */ rtp_session_set_recv_payload_type(session,-1); /* configure jitter buffer with working default parameters */ jbp.min_size=RTP_DEFAULT_JITTER_TIME; jbp.nom_size=RTP_DEFAULT_JITTER_TIME; jbp.max_size=-1; jbp.max_packets= 100;/* maximum number of packet allowed to be queued */ jbp.adaptive=TRUE; rtp_session_enable_jitter_buffer(session,TRUE); rtp_session_set_jitter_buffer_params(session,&jbp); rtp_session_set_time_jump_limit(session,5000); rtp_session_enable_rtcp(session,TRUE); session->recv_buf_size = UDP_MAX_SIZE; session->symmetric_rtp = FALSE; session->permissive=FALSE; msgb_allocator_init(&session->allocator);}/** * Creates a new rtp session. * If the session is able to send data (RTP_SESSION_SENDONLY or * RTP_SESSION_SENDRECV), then a random SSRC number is choosed for * the outgoing stream. * @param mode One of the RtpSessionMode flags. * * @return the newly created rtp session.**/RtpSession *rtp_session_new (int mode){ RtpSession *session; session = (RtpSession *) ortp_malloc (sizeof (RtpSession)); rtp_session_init (session, mode); return session;}/** * Sets the scheduling mode of the rtp session. If @yesno is TRUE, the rtp session is in * the scheduled mode, that means that you can use session_set_select() to block until it's time * to receive or send on this session according to the timestamp passed to the respective functions. * You can also use blocking mode (see rtp_session_set_blocking_mode() ), to simply block within * the receive and send functions. * If @yesno is FALSE, the ortp scheduler will not manage those sessions, meaning that blocking mode * and the use of session_set_select() for this session are disabled. *@param session a rtp session. *@param yesno a boolean to indicate the scheduling mode. * ***/voidrtp_session_set_scheduling_mode (RtpSession * session, int yesno){ if (yesno) { RtpScheduler *sched; sched = ortp_get_scheduler (); if (sched != NULL) { rtp_session_set_flag (session, RTP_SESSION_SCHEDULED); session->sched = sched; rtp_scheduler_add_session (sched, session); } else ortp_warning ("rtp_session_set_scheduling_mode: Cannot use scheduled mode because the " "scheduler is not started. Use ortp_scheduler_init() before."); } else rtp_session_unset_flag (session, RTP_SESSION_SCHEDULED);}/** * This function implicitely enables the scheduling mode if yesno is TRUE. * rtp_session_set_blocking_mode() defines the behaviour of the rtp_session_recv_with_ts() and * rtp_session_send_with_ts() functions. If @yesno is TRUE, rtp_session_recv_with_ts() * will block until it is time for the packet to be received, according to the timestamp * passed to the function. After this time, the function returns. * For rtp_session_send_with_ts(), it will block until it is time for the packet to be sent. * If @yesno is FALSE, then the two functions will return immediately. * * @param session a rtp session * @param yesno a boolean**/voidrtp_session_set_blocking_mode (RtpSession * session, int yesno){ if (yesno){ rtp_session_set_scheduling_mode(session,TRUE); rtp_session_set_flag (session, RTP_SESSION_BLOCKING_MODE); }else rtp_session_unset_flag (session, RTP_SESSION_BLOCKING_MODE);}/** * Set the RTP profile to be used for the session. By default, all session are created by * rtp_session_new() are initialized with the AV profile, as defined in RFC 3551. The application * can set any other profile instead using that function. * * @param session a rtp session * @param profile a rtp profile**/voidrtp_session_set_profile (RtpSession * session, RtpProfile * profile){ session->snd.profile = profile; session->rcv.profile = profile; rtp_session_telephone_events_supported(session);}/** * By default oRTP automatically sends RTCP SR or RR packets. If * yesno is set to FALSE, the RTCP sending of packet is disabled. * This functionnality might be needed for some equipments that do not * support RTCP, leading to a traffic of ICMP errors on the network. * It can also be used to save bandwidth despite the RTCP bandwidth is * actually and usually very very low.**/void rtp_session_enable_rtcp(RtpSession *session, bool_t yesno){ session->rtcp.enabled=yesno;}/** * Set the RTP profile to be used for the sending by this session. By default, all session are created by * rtp_session_new() are initialized with the AV profile, as defined in RFC 3551. The application * can set any other profile instead using that function. * @param session a rtp session * @param profile a rtp profile ***/voidrtp_session_set_send_profile (RtpSession * session, RtpProfile * profile){ session->snd.profile = profile; rtp_session_send_telephone_events_supported(session);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -