⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 rtpsession.c

📁 mediastreamer2是开源的网络传输媒体流的库
💻 C
📖 第 1 页 / 共 4 页
字号:
/*  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 + -