rtpsession.c

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

C
1,957
字号
 * *	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 recv-only or duplex. * *	Returns: 0 on success.**/intrtp_session_set_local_addr (RtpSession * session, const char * addr, int port){	ortp_socket_t sock;	int sockfamily;	if (session->rtp.socket>=0){		/* don't rebind, but close before*/		rtp_session_release_sockets(session);	}	/* try to bind the rtp port */	if (port>0)		sock=create_and_bind(addr,port,&sockfamily);	else		sock=create_and_bind_random(addr,&sockfamily,&port);	if (sock>=0){		session->rtp.sockfamily=sockfamily;		session->rtp.socket=sock;		session->rtp.loc_port=port;		/*try to bind rtcp port */		sock=create_and_bind(addr,port+1,&sockfamily);		if (sock>=0){			session->rtcp.sockfamily=sockfamily;			session->rtcp.socket=sock;		}else{			ortp_warning("Could not create and bind rtcp socket.");		}		return 0;	}	return -1;}/** *rtp_session_get_local_port: *@session:	a rtp session for which rtp_session_set_local_addr() or rtp_session_set_remote_addr() has been called * *	This function can be useful to retrieve the local port that was randomly choosen by  *	rtp_session_set_remote_addr() when rtp_session_set_local_addr() was not called. * *	Returns: the local port used to listen for rtp packets, -1 if not set.**/int rtp_session_get_local_port(const RtpSession *session){	return (session->rtp.loc_port>0) ? session->rtp.loc_port : -1;}static char * ortp_inet_ntoa(struct sockaddr *addr, int addrlen, char *dest, int destlen){#ifdef ORTP_INET6	int err;	dest[0]=0;	err=getnameinfo(addr,addrlen,dest,destlen,NULL,0,NI_NUMERICHOST);	if (err!=0){		ortp_warning("getnameinfo error: %s",gai_strerror(err));	}#else	char *tmp=inet_ntoa(((struct sockaddr_in*)addr)->sin_addr);	strncpy(dest,tmp,destlen);	dest[destlen-1]='\0';#endif	return dest;}/** *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 also sets the origin of incoming RTP  *	packets. Rtp packets that don't come from addr:port are discarded. * *	Returns: 0 on success.**/intrtp_session_set_remote_addr (RtpSession * session, const char * addr, int port){	int err;#ifdef ORTP_INET6	struct addrinfo hints, *res0, *res;	char num[8];	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) {		ortp_warning ("Error in socket address: %s", gai_strerror(err));		return -1;	}#endif	if (session->rtp.socket == -1){		/* the session has not its socket bound, do it */		ortp_message ("Setting random local addresses.");#ifdef ORTP_INET6		/* bind to an address type that matches the destination address */		if (res0->ai_addr->sa_family==AF_INET6)			err = rtp_session_set_local_addr (session, "::", -1);		else err=rtp_session_set_local_addr (session, "0.0.0.0", -1);#else		err = rtp_session_set_local_addr (session, "0.0.0.0", -1);#endif		if (err<0) return -1;	}#ifdef ORTP_INET6	err=1;	for (res = res0; res; res = res->ai_next) {		/* set a destination address that has the same type as the local address */		if (res->ai_family==session->rtp.sockfamily ) {			memcpy( &session->rtp.rem_addr, res->ai_addr, res->ai_addrlen);			session->rtp.rem_addrlen=res->ai_addrlen;		  	err=0;		  	break;		}	}	freeaddrinfo(res0);	if (err) {		ortp_warning("Could not set destination for RTP socket to %s:%i.",addr,port);		return -1;	}		memset(&hints, 0, sizeof(hints));	hints.ai_family = PF_UNSPEC;	hints.ai_socktype = SOCK_DGRAM;	snprintf(num, sizeof(num), "%d", (port + 1));	err = getaddrinfo(addr, num, &hints, &res0);	if (err) {		ortp_warning ("Error: %s", gai_strerror(err));		return err;	}	err=1;	for (res = res0; res; res = res->ai_next) {		/* set a destination address that has the same type as the local address */		if (res->ai_family==session->rtp.sockfamily ) {		  	err=0;		  	memcpy( &session->rtcp.rem_addr, res->ai_addr, res->ai_addrlen);			session->rtcp.rem_addrlen=res->ai_addrlen;		  	break;		}	}	freeaddrinfo(res0);	if (err) {		ortp_warning("Could not set destination for RCTP socket to %s:%i.",addr,port+1);		return -1;	}#else	session->rtp.rem_addrlen=sizeof(session->rtp.rem_addr);	session->rtp.rem_addr.sin_family = AF_INET;	err = inet_aton (addr, &session->rtp.rem_addr.sin_addr);	if (err < 0)	{		ortp_warning ("Error in socket address:%s.", getSocketError());		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);	session->rtcp.rem_addrlen=sizeof(session->rtp.rem_addr);#endif	return 0;}void rtp_session_set_sockets(RtpSession *session, int rtpfd, int rtcpfd){	if (rtpfd>=0) set_non_blocking_socket(rtpfd);	if (rtcpfd>=0) set_non_blocking_socket(rtcpfd);	session->rtp.socket=rtpfd;	session->rtcp.socket=rtcpfd;	session->flags|=RTP_SESSION_USING_EXT_SOCKETS;}/** *rtp_session_flush_sockets: *@session: a rtp session * * Flushes the sockets for all pending incoming packets. * This can be usefull if you did not listen to the stream for a while * and wishes to start to receive again. During the time no receive is made * packets get bufferised into the internal kernel socket structure. ***/void rtp_session_flush_sockets(RtpSession *session){	char trash[4096];#ifdef ORTP_INET6	struct sockaddr_storage from;#else	struct sockaddr from;#endif	socklen_t fromlen=sizeof(from);	if (session->rtp.socket>=0){		while (recvfrom(session->rtp.socket,trash,sizeof(trash),0,(struct sockaddr *)&from,&fromlen)>0){};	}	if (session->rtcp.socket>=0){		while (recvfrom(session->rtcp.socket,trash,sizeof(trash),0,(struct sockaddr*)&from,&fromlen)>0){};	}}/** *rtp_session_set_seq_number: *@session:		a rtp session freshly created. *@addr:			a 16 bit unsigned number. * * sets the initial sequence number of a sending session. ***/void rtp_session_set_seq_number(RtpSession *session, uint16_t seq){	session->rtp.snd_seq=seq;}uint16_t rtp_session_get_seq_number(RtpSession *session){	return session->rtp.snd_seq;}#ifdef USE_SENDMSG #define MAX_IOV 10static int rtp_sendmsg(int sock,mblk_t *m, struct sockaddr *rem_addr, int addr_len){	int error;	struct msghdr msg;	struct iovec iov[MAX_IOV];	int iovlen;	for(iovlen=0; iovlen<MAX_IOV && m!=NULL; m=m->b_cont,iovlen++){		iov[iovlen].iov_base=m->b_rptr;		iov[iovlen].iov_len=m->b_wptr-m->b_rptr;	}	msg.msg_name=(void*)rem_addr;	msg.msg_namelen=addr_len;	msg.msg_iov=&iov[0];	msg.msg_iovlen=iovlen;	msg.msg_control=NULL;	msg.msg_controllen=0;	msg.msg_flags=0;		error=sendmsg(sock,&msg,0);	return error;}#endif	static intortp_rtp_send (RtpSession * session, mblk_t * m){	int error;	int i;	rtp_header_t *hdr;	hdr = (rtp_header_t *) m->b_rptr;	/* perform host to network conversions */	hdr->ssrc = htonl (hdr->ssrc);	hdr->timestamp = htonl (hdr->timestamp);	hdr->seq_number = htons (hdr->seq_number);	for (i = 0; i < hdr->cc; i++)		hdr->csrc[i] = htonl (hdr->csrc[i]);	#ifdef USE_SENDMSG	if (session->flags & RTP_SESSION_USING_EXT_SOCKETS){		error=rtp_sendmsg(session->rtp.socket,m,(struct sockaddr *)NULL,0);	}else {		error=rtp_sendmsg(session->rtp.socket,m,(struct sockaddr *) &session->rtp.rem_addr,		session->rtp.rem_addrlen);	}#else	if (m->b_cont!=NULL){		msgpullup(m,-1);	}	if (session->flags & RTP_SESSION_USING_EXT_SOCKETS){		error=send(session->rtp.socket, m->b_rptr, (int) (m->b_wptr - m->b_rptr),0);	}else error = sendto (session->rtp.socket, m->b_rptr,		(int) (m->b_wptr - m->b_rptr), 0,		(struct sockaddr *) &session->rtp.rem_addr,		session->rtp.rem_addrlen);#endif	if (error < 0){		if (session->on_network_error.count>0){			rtp_signal_table_emit3(&session->on_network_error,(long)"Error sending RTP packet",INT_TO_POINTER(getSocketErrorCode()));		}else ortp_warning ("Error sending rtp packet: %s ; socket=%i", getSocketError(), session->rtp.socket);	}	freemsg (m);	return error;}intortp_rtcp_send (RtpSession * session, mblk_t * m){	int error=0;	bool_t using_ext_socket=(session->flags & RTP_SESSION_USING_EXT_SOCKETS)!=0;	if ( (using_ext_socket && session->rtcp.socket>0 ) || session->rtcp.rem_addrlen>0){		#ifndef USE_SENDMSG		if (m->b_cont!=NULL){			msgpullup(m,-1);		}#endif		if (using_ext_socket &&  session->rtcp.socket>0 ){#ifdef USE_SENDMSG			error=rtp_sendmsg(session->rtcp.socket,m,(struct sockaddr *)NULL,0);#else			error=send(session->rtcp.socket, m->b_rptr, (int) (m->b_wptr - m->b_rptr),0);#endif		}else {#ifdef USE_SENDMSG			error=rtp_sendmsg(session->rtcp.socket,m,(struct sockaddr *) &session->rtcp.rem_addr,			session->rtcp.rem_addrlen);#else			error = sendto (session->rtcp.socket, m->b_rptr,			(int) (m->b_wptr - m->b_rptr), 0,			(struct sockaddr *) &session->rtcp.rem_addr,			session->rtcp.rem_addrlen);#endif		}			if (error < 0){			char host[50];			if (session->on_network_error.count>0){				rtp_signal_table_emit3(&session->on_network_error,(long)"Error sending RTCP packet",INT_TO_POINTER(getSocketErrorCode()));			}else ortp_warning ("Error sending rtcp packet: %s ; socket=%i; addr=%s", getSocketError(), session->rtcp.socket, ortp_inet_ntoa((struct sockaddr*)&session->rtcp.rem_addr,session->rtcp.rem_addrlen,host,sizeof(host)) );		}	}else ortp_warning("Cannot send rtcp report because I don't know the remote address.");	freemsg (m);	return error;}/** *rtp_session_set_ssrc: *@session: a rtp session. *@ssrc: an unsigned 32bit integer representing the synchronisation source identifier (SSRC). * *	Sets the SSRC for the outgoing stream. *  If not done, a random ssrc is used. ***/voidrtp_session_set_ssrc (RtpSession * session, uint32_t ssrc){	session->send_ssrc = ssrc;}void rtp_session_update_payload_type(RtpSession *session, int paytype){	/* check if we support this payload type */	PayloadType *pt=rtp_profile_get_payload(session->profile,paytype);	session->hw_recv_pt=paytype;	if (pt!=0){		ortp_message ("payload type changed to %i(%s) !",				 paytype,pt->mime_type);		payload_type_changed(session,pt);	}else{		ortp_warning("Receiving packet with unknown payload type %i.",paytype);	}}/** *rtp_session_set_send_payload_type: *@session: a rtp session *@paytype: the payload type * *	Sets the payload type of the rtp session. It decides of the payload types written in the *	of the rtp header for the outgoing stream, if the session is SENDRECV or SENDONLY. *	For payload type in incoming packets, the application can be informed by registering *	for the "payload_type_changed" signal, so that it can make the necessary changes *	on the downstream decoder that deals with the payload of the packets. * *Returns: 0 on success, -1 if the payload is not defined.**/intrtp_session_set_send_payload_type (RtpSession * session, int paytype){	session->send_pt=paytype;	return 0;}/** *rtp_session_get_send_payload_type: *@session: a rtp session * *	Returns: the payload type currently used in outgoing rtp packets**/int rtp_session_get_send_payload_type(const RtpSession *session){	return session->send_pt;}/** *rtp_session_set_recv_payload_type: *@session: a rtp session *@paytype: the payload type * *	Sets the expected payload type for incoming packets. *	If the actual payload type in incoming packets is different that this expected payload type, thus *	the "payload_type_changed" signal is emitted. * *Returns: 0 on success, -1 if the payload is not defined.**/intrtp_session_set_recv_payload_type (RtpSession * session, int paytype){	PayloadType *pt;	session->recv_pt=paytype;	session->hw_recv_pt=paytype;	pt=rtp_profile_get_payload(session->profile,paytype);	if (pt!=NULL){		payload_type_changed(session,pt);	}	return 0;}/** *rtp_session_get_recv_payload_type: *@session: a rtp session * *	Returns: the payload type currently used in incoming rtp packets**/int rtp_session_get_recv_payload_type(const RtpSession *session){	return session->recv_pt;}/** *rtp_session_set_payload_type: *@session: a rtp session *@paytype: the payload type * *	Sets the expected payload type for incoming packets and payload type to be used for outgoing packets. *	If the actual payload type in incoming packets is different that this expected payload type, thus *	the "payload_type_changed" signal is emitted. * *Returns: 0 on success, -1 if the payload is not defined.**/int rtp_session_set_payload_type(RtpSession *session, int pt){	if (rtp_session_set_send_payload_type(session,pt)<0) return -1;	if (rtp_session_set_recv_payload_type(session,pt)<0) return -1;	return 0;}/** *rtp_session_create_packet: *@session:		a rtp session. *@header_size:	the rtp header size. For standart size (without extensions), it is #RTP_FIXED_HEADER_SIZE *@payload		:data to be copied into the rtp packet. *@payload_size	: size of data carried by the rtp packet. * *	Allocates a new rtp packet. In the header, ssrc and payload_type according to the session's *	context. Timestamp and seq number are not set, there will be set when the packet is going to be *	sent with rtp_session_sendm_with_ts(). *	If payload_size is zero, thus an empty packet (just a RTP header) is returned. * *Returns: a rtp packet in a mblk_t (message block) structure.**/mblk_t * rtp_session_create_packet(RtpSession *session,int header_size, const char *payload, int payload_size){	mblk_t *mp;	int msglen=header_size+payload_size;	rtp_header_t *rtp;		mp=allocb(msglen,BPRI_MED);	rtp=(rtp_header_t*)mp->b_rptr;	rtp->version = 2;	rtp->padbit = 0;	rtp->extbit = 0;	rtp->markbit= 0;	rtp->cc = 0;	rtp->paytype = session->send_pt;	rtp->ssrc = session->send_ssrc;	rtp->timestamp = 0;	/* set later, when packet is sended */	rtp->seq_number = 0; /*set later, when packet is sended */	/*copy the payload, if any */	mp->b_wptr+=header_size;	if (payload_size){		memcpy(mp->b_wptr,payload,payload_size);		mp->b_wptr+=payload_size;	}	return mp;}

⌨️ 快捷键说明

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