www.pudn.com > RTP通用开发库(for Linux).rar > rtpopen.c


/*-------------------------------------------------------------------------
 * rtpopen.c - rtpopen, rtpopensockets
 *-------------------------------------------------------------------------
 */

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 

/*------------------------------------------------------------------------
 * rtpopen - open a new RTP session, allocate resources and create state
 *------------------------------------------------------------------------
 */
struct session *
rtpopen(struct in_addr session, int port, int bpbufsz, int bpbufcnt)
{

	struct session *psn;
	int            rv, packetsneeded;

	psn = (struct session *) malloc(sizeof(struct session));
	if (psn == NULL)
		return NULL;
  
	memset(psn, 0, sizeof(struct session));

	psn->sn_rtpfd = psn->sn_rtcpfd = -1;

	psn->sn_ssrcs = htnew(RTP_SSRCHTSZ, hashunsignedint, unsignedinteq, NULL, (void(*)(void *)) rtpdestroystream);
	psn->sn_cnames = htnew(RTP_CNAMEHTSZ, hashstring, (int(*)(unsigned int, unsigned int))strcasecmp, (void(*)(unsigned int))free, (void(*)(void *))free);

	psn->sn_cyclesources = (ssrc_t *) malloc(sizeof(ssrc_t) * RTCP_RRMAXRBLOCKS);
	packetsneeded = RTCP_RRMAXRBLOCKS / RTCP_MAXRBLOCKS + ((RTCP_RRMAXRBLOCKS % RTCP_MAXRBLOCKS) != 0);
	psn->sn_cyclebuf = (char *) malloc(RTCP_RRMAXRBLOCKS * sizeof(struct rblock) + packetsneeded * (RTCP_HEADERSZ + sizeof(ssrc_t)));
	rv = bufpoolinit(&psn->sn_bpool, bpbufsz, bpbufcnt);
  
	pthread_cond_init(&psn->sn_cond, NULL);
	pthread_mutex_init(&psn->sn_mutex, NULL);
	pthread_mutex_init(&psn->sn_getstreammutex, NULL);
	pthread_mutex_init(&psn->sn_cnamemutex, NULL);
	pthread_mutex_init(&psn->sn_rtpthrmutex, NULL);
	pthread_mutex_init(&psn->sn_rtcpthrmutex, NULL);
	pthread_mutex_init(&psn->sn_rtcpcyclethrmutex, NULL);

	psn->sn_addr = session;
	psn->sn_port = port;
	psn->sn_bw = RTP_DEFAULT_SESSIONBW;
	psn->sn_ssrc = rtpmkssrc(NULL);
	psn->sn_autocleanup = TRUE;

	if (rtpopensockets(psn, session, port) == ERROR ||
	    psn->sn_ssrcs == NULL ||
	    psn->sn_cnames == NULL ||
	    psn->sn_cyclesources == NULL ||
	    psn->sn_cyclebuf == NULL ||
	    rv == ERROR) {
		rtpclose(psn);
		return NULL;
	}
  
	return psn;
}

/*------------------------------------------------------------------------
 * rtpopensockets - open socket for RTP and RTCP datagrams
 *------------------------------------------------------------------------
 */
int
rtpopensockets(struct session *psn, struct in_addr session, int port)
{

	struct sockaddr_in	saddr;
	struct ip_mreq	        mreq;
	unsigned char		loop;
	int			reuse;
	unsigned char		ttl;

	psn->sn_rtpfd = socket(AF_INET, SOCK_DGRAM, 0);
	psn->sn_rtcpfd = socket(AF_INET, SOCK_DGRAM, 0);
  
	if (psn->sn_rtpfd < 0 || psn->sn_rtcpfd < 0) {
		return ERROR;
	}

	memset(&saddr, 0, sizeof(struct sockaddr_in));
	saddr.sin_family = AF_INET;

	if(IN_CLASSD(ntohl(session.s_addr))) {
		saddr.sin_addr = session;
	}
	else {
		saddr.sin_addr.s_addr = htonl(INADDR_ANY);
	}

	if (IN_CLASSD(ntohl(session.s_addr))) {
		reuse = 1;
		if (setsockopt(psn->sn_rtpfd, SOL_SOCKET, SO_REUSEADDR, (char *) &reuse, sizeof(reuse)) < 0) {
			close(psn->sn_rtpfd);
			close(psn->sn_rtcpfd);
			return ERROR;
		}
    
		if (setsockopt(psn->sn_rtcpfd, SOL_SOCKET, SO_REUSEADDR, (char *) &reuse, sizeof(reuse)) < 0) {
			close(psn->sn_rtpfd);
			close(psn->sn_rtcpfd);
			return ERROR;
		}
	}
  
	saddr.sin_port = htons(port);  
	if (bind(psn->sn_rtpfd, (struct sockaddr *) &saddr, sizeof(struct sockaddr_in)) < 0) {
		close(psn->sn_rtpfd);
		close(psn->sn_rtcpfd);
		return ERROR;
	}
  
	saddr.sin_port = htons(port + 1);
	if (bind(psn->sn_rtcpfd, (struct sockaddr *) &saddr, sizeof(struct sockaddr_in)) < 0) {
		close(psn->sn_rtpfd);
		close(psn->sn_rtcpfd);
		return ERROR;
	}

	psn->sn_rtcpto = saddr;
	if (!IN_CLASSD(ntohl(session.s_addr)))
		psn->sn_rtcpto.sin_addr.s_addr = RTP_INADDRUNINITIALIZED;

	if (IN_CLASSD(ntohl(session.s_addr))) {
		mreq.imr_multiaddr = session;
		mreq.imr_interface.s_addr = htonl(INADDR_ANY);
    
		if (setsockopt(psn->sn_rtpfd, IPPROTO_IP, IP_ADD_MEMBERSHIP, (char *) &mreq, sizeof(struct ip_mreq)) < 0) {
			close(psn->sn_rtpfd);
			close(psn->sn_rtcpfd);
			return ERROR;
		}

		if (setsockopt(psn->sn_rtcpfd, IPPROTO_IP, IP_ADD_MEMBERSHIP, (char *) &mreq, sizeof(struct ip_mreq)) < 0) {
			close(psn->sn_rtpfd);
			close(psn->sn_rtcpfd);
			return ERROR;
		}

		/*
		 * Disable loopback on RTCP socket so we don't want to hear ourselves.
		 * This isn't done for the RTP socket because this implementation
		 * assumes no sending.
		 */
		loop = 0;
		if (setsockopt(psn->sn_rtcpfd, IPPROTO_IP, IP_MULTICAST_LOOP, 
			       (char *) &loop, sizeof(loop)) < 0) {
			close(psn->sn_rtpfd);
			close(psn->sn_rtcpfd);
			return ERROR;
		}
    
		/* 
		 * Set TTL.
		 * This isn't done for the RTP socket because this implementation
		 * assumes no sending.
		 */
		ttl = RTP_DEFAULT_SESSIONTTL;
		if (setsockopt(psn->sn_rtcpfd, IPPROTO_IP, IP_MULTICAST_TTL, 
			       (char *) &ttl, sizeof(ttl)) < 0) {
			close(psn->sn_rtpfd);
			close(psn->sn_rtcpfd);
			return ERROR;
		}
	}
	return OK;
}