rtpsession.c

来自「linphone源码-1.3.5.tar.gz,linphone源码-1.3.5」· C语言 代码 · 共 1,957 行 · 第 1/4 页

C
1,957
字号
/*  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 "ortp/telephonyevents.h"#include "rtpmod.h"#include "jitterctl.h"#include "scheduler.h"#include "utils.h"#include "ortp-config.h"#if defined(HAVE_POLL_H)#include <poll.h>#elif defined(HAVE_SYS_POLL_H)#include <sys/poll.h>#endif#ifdef HAVE_SYS_UIO_H#include <sys/uio.h>#define USE_SENDMSG 1#endif/* 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);}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);static uint32_t uint32_t_random(){	return random();}voidrtp_session_init (RtpSession * session, int mode){	memset (session, 0, sizeof (RtpSession));	ortp_mutex_init(&session->lock,NULL);	session->rtp.max_rq_size = 100;/* maximum number of packet allowed to be queued */	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);		rtp_session_set_flag (session, RTP_SESSION_SEND_SYNC);		session->send_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->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;	qinit(&session->rtp.rq);	qinit(&session->rtp.tev_rq);	qinit(&session->contributing_sources);	/* 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->send_wp);	wait_point_init(&session->recv_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);	rtp_session_set_jitter_compensation(session,RTP_DEFAULT_JITTER_TIME);	rtp_session_enable_adaptive_jitter_compensation(session,FALSE);	rtp_session_set_time_jump_limit(session,5000);	session->recv_buf_size = UDP_MAX_SIZE;	session->symmetric_rtp = 0;}/** *rtp_session_new: *@mode: One of the #RtpSessionMode flags. * *	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. * *Returns: 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;}/** *rtp_session_set_scheduling_mode: *@session: a rtp session. *@yesno:	a boolean to indicate the scheduling mode. * *	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. ***/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);}/** *rtp_session_set_blocking_mode: *@session: a rtp session *@yesno: a boolean * *	Using this function implies that you previously enabled scheduled mode on the session *  (see rtp_session_set_scheduling_mode() ). *	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. ***/voidrtp_session_set_blocking_mode (RtpSession * session, int yesno){	if (yesno)		rtp_session_set_flag (session, RTP_SESSION_BLOCKING_MODE);	else		rtp_session_unset_flag (session, RTP_SESSION_BLOCKING_MODE);}/** *rtp_session_set_profile: *@session: a rtp session *@profile: a rtp profile * *	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. * ***/voidrtp_session_set_profile (RtpSession * session, RtpProfile * profile){	session->profile = profile;	rtp_session_telephone_events_supported(session);}/** *rtp_session_get_profile: *@session: a rtp session * *	Returns current profile. ***/RtpProfile *rtp_session_get_profile(RtpSession *session){	return session->profile;}/** *rtp_session_set_recv_buf_size: *@session: a rtp session *@bufsize: buffer size in bytes for receiving packets * *	The default value is 65535 bytes, a big value which is working for everyone. *	However if your application can make assumption on the MTU, it can be interesting *	to set it to a lower value in order to save memory. ***/void rtp_session_set_recv_buf_size(RtpSession *session, int bufsize){	session->recv_buf_size=bufsize;}/** *rtp_session_signal_connect: *@session: 	a rtp session *@signal:		the name of a signal *@cb:			a #RtpCallback *@user_data:	a pointer to any data to be passed when invoking the callback. * *	This function provides the way for an application to be informed of various events that *	may occur during a rtp session. @signal is a string identifying the event, and @cb is  *	a user supplied function in charge of processing it. The application can register *	several callbacks for the same signal, in the limit of #RTP_CALLBACK_TABLE_MAX_ENTRIES. *	Here are name and meaning of supported signals types: * *	"ssrc_changed" : the SSRC of the incoming stream has changed. * *	"payload_type_changed" : the payload type of the incoming stream has changed. * *	"telephone-event_packet" : a telephone-event rtp packet (RFC2833) is received. * *	"telephone-event" : a telephone event has occured. This is a high-level shortcut for "telephone-event_packet". * *	"network_error" : a network error happened on a socket. Arguments of the callback functions are *						a const char * explaining the error, an int errno error code and the user_data as usual. * *	"timestamp_jump" : we have received a packet with timestamp in far future compared to last timestamp received. *						The farness of far future is set by rtp_sesssion_set_time_jump_limit() *  "rtcp_bye": we have received a RTCP bye packet. Arguments of the callback *              functions are a const char * containing the leaving reason and *              the user_data. *  *	Returns: 0 on success, -EOPNOTSUPP if the signal does not exists, -1 if no more callbacks *	can be assigned to the signal type.**/intrtp_session_signal_connect (RtpSession * session, const char *signal,			    RtpCallback cb, unsigned long user_data){	OList *elem;	for (elem=session->signal_tables;elem!=NULL;elem=o_list_next(elem)){		RtpSignalTable *s=(RtpSignalTable*) elem->data;		if (strcmp(signal,s->signal_name)==0){			return rtp_signal_table_add(s,cb,user_data);		}	}	ortp_warning ("rtp_session_signal_connect: inexistant signal %s",signal);	return -1;}/** *rtp_session_signal_disconnect_by_callback: *@session: a rtp session *@signal:	a signal name *@cb:		a callback function. * *	Removes callback function @cb to the list of callbacks for signal @signal. * *Returns: 0 on success, -ENOENT if the callbacks was not found.**/intrtp_session_signal_disconnect_by_callback (RtpSession * session, const char *signal,					   RtpCallback cb){	OList *elem;	for (elem=session->signal_tables;elem!=NULL;elem=o_list_next(elem)){		RtpSignalTable *s=(RtpSignalTable*) elem->data;		if (strcmp(signal,s->signal_name)==0){			return rtp_signal_table_remove_by_callback(s,cb);		}	}	ortp_warning ("rtp_session_signal_connect: inexistant signal %s",signal);	return -1;}static ortp_socket_t create_and_bind(const char *addr, int port, int *sock_family){	int err;	int optval = 1;	ortp_socket_t sock=-1;#ifdef ORTP_INET6	char num[8];	struct addrinfo hints, *res0, *res;#else	struct sockaddr_in saddr;#endif	#ifdef ORTP_INET6		memset(&hints, 0, sizeof(hints));	hints.ai_family = PF_UNSPEC;	hints.ai_socktype = SOCK_DGRAM;	snprintf(num, sizeof(num), "%d",port);	err = getaddrinfo(addr,num, &hints, &res0);	if (err!=0) {		ortp_warning ("Error: %s", gai_strerror(err));		return -1;	}		for (res = res0; res; res = res->ai_next) {		sock = socket(res->ai_family, res->ai_socktype, 0);		if (sock < 0)		  continue;                		err = setsockopt (sock, SOL_SOCKET, SO_REUSEADDR,				  (SOCKET_OPTION_VALUE)&optval, sizeof (optval));		if (err < 0)		{			ortp_warning ("Fail to set rtp address reusable: %s.", getSocketError());		}		*sock_family=res->ai_family;		err = bind (sock, res->ai_addr, res->ai_addrlen);		if (err != 0)		  {		    ortp_warning ("Fail to bind rtp socket to %s:%i : %s.", addr,port, getSocketError());		    close_socket (sock);			sock=-1;		    continue;		  }#ifndef __hpux		switch (res->ai_family)		  {		    case AF_INET:		      if (IN_MULTICAST(ntohl(((struct sockaddr_in *) res->ai_addr)->sin_addr.s_addr)))			{		          struct ip_mreq mreq;			  mreq.imr_multiaddr.s_addr = ((struct sockaddr_in *) res->ai_addr)->sin_addr.s_addr;			  mreq.imr_interface.s_addr = INADDR_ANY;			  err = setsockopt(sock, IPPROTO_IP, IP_ADD_MEMBERSHIP, (SOCKET_OPTION_VALUE) &mreq, sizeof(mreq));			  if (err < 0)			    {			      ortp_warning ("Fail to join address group: %s.", getSocketError());			      close_socket (sock);					sock=-1;			      continue;			    }			}		      break;		    case AF_INET6:		      if (IN6_IS_ADDR_MULTICAST(&(((struct sockaddr_in6 *) res->ai_addr)->sin6_addr)))			{			  struct ipv6_mreq mreq;			  mreq.ipv6mr_multiaddr = ((struct sockaddr_in6 *) res->ai_addr)->sin6_addr;			  mreq.ipv6mr_interface = 0;			  err = setsockopt(sock, IPPROTO_IPV6, IPV6_JOIN_GROUP, (SOCKET_OPTION_VALUE)&mreq, sizeof(mreq));			  if (err < 0)			    {			      ortp_warning ("Fail to join address group: %s.", getSocketError());			      close_socket (sock);					sock=-1;			      continue;			    }			}		      break;		  }#endif /*hpux*/		break;	}	freeaddrinfo(res0);#else	saddr.sin_family = AF_INET;	*sock_family=AF_INET;	err = inet_aton (addr, &saddr.sin_addr);	if (err < 0)	{		ortp_warning ("Error in socket address:%s.", getSocketError());		return err;	}	saddr.sin_port = htons (port);	sock = socket (PF_INET, SOCK_DGRAM, 0);		if (sock<0) return -1;		err = setsockopt (sock, SOL_SOCKET, SO_REUSEADDR,			  (SOCKET_OPTION_VALUE)&optval, sizeof (optval));	if (err < 0)	{		ortp_warning ("Fail to set rtp address reusable: %s.",getSocketError());	}	err = bind (sock,		    (struct sockaddr *) &saddr,		    sizeof (saddr));	if (err != 0)	{		ortp_warning ("Fail to bind rtp socket to port %i: %s.", port, getSocketError());		close_socket (sock);		return -1;	}#endif	if (sock>=0) set_non_blocking_socket (sock);	return sock;}static ortp_socket_t create_and_bind_random(const char *localip, int *sock_family, int *port){	int retry;	ortp_socket_t sock = -1;	for (retry=0;retry<100;retry++)	{		int localport;		do		{			localport = (rand () + 5000) & 0xfffe;		}		while ((localport < 5000) || (localport > 0xffff));		sock = create_and_bind(localip, localport, sock_family);		if (sock>=0) {			*port=localport;			return sock;		}	}	ortp_warning("create_and_bind_random: Could not find a random port for %s !",localip);	return -1;}/** *rtp_session_set_local_addr: *@session:		a rtp session freshly created. *@addr:		a local IP address in the xxx.xxx.xxx.xxx form. *@port:		a local port or -1 to let oRTP choose the port randomly

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?