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

📄 rtpsession.c

📁 ortp协议栈(实时传输协议)
💻 C
📖 第 1 页 / 共 3 页
字号:
/*  The oRTP LinPhone RTP library intends to provide basics for a RTP 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.h"#include "rtpmod.h"#ifdef TARGET_IS_HPUXKERNEL#else#include <fcntl.h>#include <sys/types.h>#include <errno.h>#include <sys/socket.h>#include <netinet/in.h>#include <arpa/inet.h>#include <stdlib.h>//#include <string.h>#endifvoidrtp_session_init (RtpSession * session, gint mode){	memset (session, 0, sizeof (RtpSession));	session->rtp.max_rq_size = RTP_MAX_RQ_SIZE;	session->rtp.jitt_comp_time = RTP_DEFAULT_JITTER;	session->mode = 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->telephone_events_pt=-1;	/* not defined a priori */	rtp_session_set_profile (session, &av_profile);#ifndef TARGET_IS_HPUXKERNEL	session->rtp.rq = &session->rtp._rq;	session->rtp.wq = &session->rtp._wq;#endif	session->lock = g_mutex_new ();	/* init signal tables */	rtp_signal_table_init (&session->on_ssrc_changed, session);	rtp_signal_table_init (&session->on_payload_type_changed, session);	rtp_signal_table_init (&session->on_telephone_event, session);	rtp_signal_table_init (&session->on_telephone_event_packet, session);#ifdef BUILD_SCHEDULER	session->rtp.wait_for_packet_to_be_sent_mutex = g_mutex_new ();	session->rtp.wait_for_packet_to_be_sent_cond = g_cond_new ();	session->rtp.wait_for_packet_to_be_recv_mutex = g_mutex_new ();	session->rtp.wait_for_packet_to_be_recv_cond = g_cond_new ();#endif	session->max_buf_size = UDP_MAX_SIZE;}/** *rtp_session_new: *@mode: One of the #RtpSessionMode flags. * *	Creates a new rtp session. * *Returns: the newly created rtp session.**/RtpSession *rtp_session_new (gint mode){	RtpSession *session = g_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 1, the rtp session is in *	the scheduled mode: this means that packet input/output for that session *	is done by a thread that is in charge of getting and sending packet at regular time *	interval. This is very usefull for outgoing packets, that have to be sent at a time that *	matches their timestamp. *	If @yesno is zero, then the session is not scheduled. All recv and send operation will *	occur when calling respectively rtp_session_recv_with_ts() and rtp_session_send_with_ts(). ***/voidrtp_session_set_scheduling_mode (RtpSession * session, gint yesno){	if (yesno)	{#ifdef BUILD_SCHEDULER		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			g_warning				("rtp_session_set_scheduling_mode: Cannot use scheduled mode because the "				 "scheduler is not started. Use ortp_scheduler_init() before.");#else		g_warning			("rtp_session_set_scheduling_mode: Cannot use scheduled mode because the "			 "scheduler is not compiled within this oRTP stack.");#endif	}	else		rtp_session_unset_flag (session, RTP_SESSION_SCHEDULED);}/** *rtp_session_set_blocking_mode: *@session: a rtp session *@yesno: a boolean * *	This function defines the behaviour of the rtp_session_recv_with_ts() and  *	rtp_session_send_with_ts() functions. If @yesno is 1, 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 0, then the two functions will return immediately. ***/voidrtp_session_set_blocking_mode (RtpSession * session, gint 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 1890. 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_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 (RFC1833) is received. * *	"telephone-event" : a telephone event has occured. This is a shortcut for "telephone-event_packet". * *	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, char *signal,			    RtpCallback cb, gpointer user_data){	if (strcmp (signal, "ssrc_changed") == 0)	{		return rtp_signal_table_add (&session->on_ssrc_changed, cb,					     user_data);	}	else if (strcmp (signal, "payload_type_changed") == 0)	{		return rtp_signal_table_add (&session->					     on_payload_type_changed, cb,					     user_data);	}	else if (strcmp (signal, "telephone-event")==0)	{		return rtp_signal_table_add (&session->on_telephone_event,cb,user_data);	}	else if (strcmp (signal, "telephone-event_packet")==0)	{		return rtp_signal_table_add (&session->on_telephone_event_packet,cb,user_data);	}	g_warning ("rtp_session_signal_connect: inexistant signal.");	return -EOPNOTSUPP;}/** *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, char *signal,					   RtpCallback cb){	if (strcmp (signal, "ssrc_changed") == 0)	{		return rtp_signal_table_remove_by_callback (&session->							    on_ssrc_changed,							    cb);	}	else if (strcmp (signal, "payload_type_changed") == 0)	{		return rtp_signal_table_remove_by_callback (&session->							    on_payload_type_changed,							    cb);	}	else if (strcmp (signal,"telephone-event")==0){		return rtp_signal_table_remove_by_callback(&session->on_telephone_event,cb);	}	else if (strcmp (signal,"telephone-event_packet")==0){		return rtp_signal_table_remove_by_callback(&session->on_telephone_event_packet,cb);	}	g_warning		("rtp_session_signal_disconnect_by_callback: callback not found.");	return -ENOENT;}/** *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. * *	Specify the local addr to be use to listen for rtp packets or to send rtp packet from. *	In case where the rtp session is send-only, then it is not required to call this function: *	when calling rtp_session_set_remote_addr(), if no local address has been set, then the  *	default INADRR_ANY (0.0.0.0) IP address with a random port will be used. Calling  *	rtp_sesession_set_local_addr() is mandatory when the session is send-only or duplex. * *	Returns: 0 on success.**/#ifdef TARGET_IS_HPUXKERNELgintrtp_session_set_local_addr (RtpSession * session, gchar * addr, gint port){	return EOPNOTSUPP;}#elsegintrtp_session_set_local_addr (RtpSession * session, gchar * addr, gint port){	gint err;	gint optval = 1;	session->rtp.loc_addr.sin_family = AF_INET;	err = inet_aton (addr, &session->rtp.loc_addr.sin_addr);	if (err < 0)	{		g_warning ("Error in socket address:%s.", strerror (errno));		return err;	}	session->rtp.loc_addr.sin_port = htons (port);	session->rtp.socket = socket (PF_INET, SOCK_DGRAM, 0);	g_return_val_if_fail (session->rtp.socket > 0, -1);	/* set non blocking mode */	fcntl (session->rtp.socket, F_SETFL, O_NONBLOCK);	err = bind (session->rtp.socket,		    (struct sockaddr *) &session->rtp.loc_addr,		    sizeof (struct sockaddr_in));	if (err != 0)	{		g_warning ("Fail to bind rtp socket to port %i: %s.", port,			   strerror (errno));		close (session->rtp.socket);		return -1;	}	/* set the address reusable */	err = setsockopt (session->rtp.socket, SOL_SOCKET, SO_REUSEADDR,			  &optval, sizeof (optval));	if (err < 0)	{		g_warning ("Fail to set rtp address reusable: %s.",			   strerror (errno));	}	memcpy (&session->rtcp.loc_addr, &session->rtp.loc_addr,		sizeof (struct sockaddr_in));	session->rtcp.loc_addr.sin_port = htons (port + 1);	session->rtcp.socket = socket (PF_INET, SOCK_DGRAM, 0);	g_return_val_if_fail (session->rtcp.socket > 0, -1);	err = bind (session->rtcp.socket,		    (struct sockaddr *) &session->rtcp.loc_addr,		    sizeof (struct sockaddr_in));	if (err != 0)	{		g_warning ("Fail to bind rtcp socket to port %i: %s.",			   port + 1, strerror (errno));		close (session->rtp.socket);		close (session->rtcp.socket);		return -1;	}	optval = 1;	err = setsockopt (session->rtcp.socket, SOL_SOCKET, SO_REUSEADDR,			  &optval, sizeof (optval));	if (err < 0)	{		g_warning ("Fail to set rtcp address reusable: %s.",			   strerror (errno));	}	FD_ZERO (&session->scanfd);	FD_SET (session->rtp.socket, &session->scanfd);	FD_SET (session->rtcp.socket, &session->scanfd);	if (session->rtcp.socket > session->rtp.socket)		session->highest_fd = session->rtcp.socket + 1;	else		session->highest_fd = session->rtp.socket + 1;	return 0;}#endif/** *rtp_session_set_remote_addr: *@session:		a rtp session freshly created. *@addr:		a local IP address in the xxx.xxx.xxx.xxx form. *@port:		a local port. * *	Sets the remote address of the rtp session, ie the destination address where rtp packet *	are sent. If the session is recv-only or duplex, it sets also the origin of incoming RTP  *	packets. Rtp packets that don't come from addr:port are discarded. * *	Returns: 0 on success.**/#ifdef TARGET_IS_HPUXKERNELgint rtp_session_set_remote_addr(RtpSession *session, struct sockaddr_in *dest){	mblk_t *mproto;	struct T_unitdata_req *req;	/* make a M_PROTO message to be linked with every outgoing rtp packet */	mproto=allocb(sizeof(struct T_unitdata_req)+sizeof(struct sockaddr_in),BPRI_MED);	if (mproto==NULL) return -1;	mproto->b_datap->db_type=M_PROTO;	req=(struct T_unitdata_req*)mproto->b_wptr;	req->PRIM_type=T_UNITDATA_REQ;	req->DEST_length=sizeof(struct sockaddr_in);	req->DEST_offset=sizeof(struct T_unitdata_req);	req->OPT_length=0;	req->OPT_offset=0;	mproto->b_wptr+=sizeof(struct T_unitdata_req);	memcpy((void*)mproto->b_wptr,(void*)dest,sizeof(struct sockaddr_in));	mproto->b_wptr+=sizeof(struct sockaddr_in);	rtp_session_lock(session);	if (session->dest_mproto!=NULL){		freemsg(session->dest_mproto);	}	session->dest_mproto=mproto;	rtp_session_unlock(session);	return 0;}#elsegintrtp_session_set_remote_addr (RtpSession * session, gchar * addr, gint port){	gint err;	if (session->rtp.socket == 0)	{		int retry = 0;		/* the session has not its socket bound, do it */		g_message ("Setting random local addresses.");		while (retry < 10)		{			int localport;			do			{				localport = (rand () + 5000) & 0xfffe;			}			while ((localport < 5000) || (localport > 0xffff));			err = rtp_session_set_local_addr (session, "0.0.0.0",							  localport);			if (err == 0)				break;		}		if (retry == 10)			g_warning				("rtp_session_set_remote_addr: Could not find a random local address for socket !");	}	session->rtp.rem_addr.sin_family = AF_INET;	err = inet_aton (addr, &session->rtp.rem_addr.sin_addr);	if (err < 0)	{		g_warning ("Error in socket address:%s.", strerror (errno));		return err;	}	session->rtp.rem_addr.sin_port = htons (port);	memcpy (&session->rtcp.rem_addr, &session->rtp.rem_addr,		sizeof (struct sockaddr_in));	session->rtcp.rem_addr.sin_port = htons (port + 1);#ifndef NOCONNECT	if (session->mode == RTP_SESSION_SENDONLY)	{		err = connect (session->rtp.socket,			       (struct sockaddr *) &session->rtp.rem_addr,			       sizeof (struct sockaddr_in));		if (err != 0)		{			g_message ("Can't connect rtp socket: %s.",				   strerror (errno));			return err;		}		err = connect (session->rtcp.socket,			       (struct sockaddr *) &session->rtcp.rem_addr,			       sizeof (struct sockaddr_in));		if (err != 0)		{			g_message ("Can't connect rtp socket: %s.",				   strerror (errno));			return err;		}	}#endif	return 0;}#endif#ifdef TARGET_IS_HPUXKERNEL#ifdef WORDS_BIGENDIAN#if 0#define rtp_send(_session,_m) \	do{\		mblk_t *_destmp;\		if ((_session)->dest_mproto!=NULL){\			_destmp=dupb((_session)->dest_mproto);\			_destmp->b_cont=(_m);\			streams_put(putnext,(_session)->rtp.wq,(_destmp),(void*)(_session)->rtp.wq);\		} else {\			g_warning("rtp_send: ERROR - there is no destination addreess !");\			freemsg(_m);\

⌨️ 快捷键说明

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