/* 
 * Copyright (C) 2000-2001 Computer & Communications Research Laboratories,
 *			   Industrial Technology Research Institute
 */
/*
 * cclRtp.c
 *
 * $Id: cclRtp.c,v 1.8 2001/06/21 02:56:09 hcc Exp $
 */

#define _POSIX_C_SOURCE 199309L /* struct timespec */

#include <stdio.h>

#if defined(UNIX)
#include <time.h>
#include <sys/types.h>
#endif

#include "cclrtp.h"
#include "thread.h"
#include "osdep.h"

#define		DEFAULT_READ_BUFFER_SIZ	512

RTP**		rtp = NULL;
RTCP**		rtcp = NULL;
int*		RTP_PACKET_SIZ;
int		MAX_RTP_CHANS = 0;
thread		hthreadRead = NULL;
int		threadReadON = 0;
int		(*rtp_read_cb)(int channel, const char* buff, int len);

void*		_threadRead(void* data)
{
	fd_set		rtpfdset;
	SOCKET		rtpsock;
	rtp_pkt_t	pkt_recv;
	rtp_pkt_param_t	param;
	UINT32		maxfd = 0;
	struct timeval	timeout;
	int		i = 0;
	int		read_buff_siz = DEFAULT_READ_BUFFER_SIZ;
	
	rtp_pkt_init(&pkt_recv, read_buff_siz );
	memset(&param, 0, sizeof(param));

	while(threadReadON) {
		int ready;

		FD_ZERO(&rtpfdset);
		for( i = 0; i<MAX_RTP_CHANS; i++) {
			if( !rtp[i] )
				continue;

			rtpsock = rtp_getsocket(rtp[i]);
			FD_SET(rtpsock, &rtpfdset);
			if( maxfd<(int)rtpsock )
				maxfd = rtpsock;
		}
		timeout.tv_sec = 1;
		timeout.tv_usec = 0;

		ready = select( maxfd+1, &rtpfdset, (fd_set *) 0,
				(fd_set *) 0, &timeout);
		
		if( ready<=0 ) {
			/* no rtp sock is open, just continue */
			sleeping(10);
			continue;
		}

		if( rtp_read_cb==NULL )
			continue;
		for( i = 0; i<MAX_RTP_CHANS; i++) {
			if( !rtp[i] )
				continue;
			if( RTP_PACKET_SIZ[i]>(read_buff_siz/2) ) {
				rtp_pkt_free(&pkt_recv);
				read_buff_siz = RTP_PACKET_SIZ[i] * 2;
				rtp_pkt_init(&pkt_recv, read_buff_siz );
			}

			rtpsock = rtp_getsocket(rtp[i]);
			if (FD_ISSET(rtpsock, &rtpfdset)) {
				int	rlen = 0;
				/* receive RTP packets */
				rlen = rtp_read(rtp[i], &pkt_recv);
				if( rlen<=0 )
					continue;

				rtp_read_cb(i, pkt_recv.data, pkt_recv.datalen);
			}
		}
	}
	rtp_pkt_free(&pkt_recv);

	return NULL;
}

RETCODE	cclRTPStartup(int maxRtpChans)
{
	int	ret = 0;
	int	i = 0;

	if( rtp )
		return -1;

	ret = rtp_startup();
	if( ret!=0 )
		return -1;

	MAX_RTP_CHANS = maxRtpChans;

	RTP_PACKET_SIZ = (int*)malloc( (MAX_RTP_CHANS * sizeof(int)) );
	rtp = (RTP**)malloc( (MAX_RTP_CHANS * sizeof(void*)) );
	rtcp = (RTCP**)malloc( (MAX_RTP_CHANS * sizeof(void*)) );
	for( i=0; i<MAX_RTP_CHANS; i++) {
		RTP_PACKET_SIZ[i] = 240;
		rtp[i] = NULL;
		rtcp[i] = NULL;
	}

	return 0;
}

void	cclRTPCleanup(void)
{
	int i;

	if( !rtp )
		return;
	if( hthreadRead ) {
		threadReadON = 0;
		threadJoin(hthreadRead);
		hthreadRead = NULL;
	}

	for( i=0; i<MAX_RTP_CHANS; i++) {
		if( rtp[i]!=NULL ) 
			cclRTPClose(i);
	}
	
	rtp_cleanup();

	MAX_RTP_CHANS = 0;
}

RETCODE	cclRTPOpen(int channel, int rtpPacketSiz)
{
	if( channel<0 || channel>=MAX_RTP_CHANS )
		return -1;
	if( rtp[channel] ) {
		RTP_PACKET_SIZ[channel] = rtpPacketSiz;
		return 1;
	}

	rtp[channel] = rtp_open(0,0);
	if( !rtp[channel] )
		return -1;
	rtcp[channel] = rtcp_open(0,0);
	if( !rtcp[channel] )
		return -1;

	return 0;
}

RETCODE	cclRTPClose(int channel)
{
	int	ret = 0;
	RTP*	rtp_temp;
	RTCP*	rtcp_temp;

	if( channel<0 || channel>=MAX_RTP_CHANS )
		return -1;
	if( !rtp[channel] )
		return 0;

	rtp_temp = rtp[channel];	rtcp_temp = rtcp[channel];
	rtp[channel] = NULL;		rtcp[channel] = NULL;

	ret = rtp_close(rtp_temp);
	if( ret!=0 )
		return -1;
	ret = rtcp_close(rtcp_temp);
	if( ret!=0 )
		return -1;

	return 0;
}

UINT32	cclRTPGetPort(int channel)
{
	if( channel<0 || channel>=MAX_RTP_CHANS )
		return -1;

	return (rtp[channel])?ntohs(rtp[channel]->laddr.sin_port):0;
}

RETCODE	cclRTPGetRR(int channel, rtcp_rr_t* rr)
{
	if( channel<0 || channel>=MAX_RTP_CHANS )
		return -1;

	return 0;
}

void	cclRTPSetEventHandler( int(*rtpReadCB)(int,const char*,int) )
{
	rtp_read_cb = rtpReadCB;

	if( hthreadRead ) {
		threadReadON = 0;
		threadJoin(hthreadRead);
		hthreadRead = NULL;
	}
	threadReadON = 1;
	hthreadRead = threadCreate(_threadRead,NULL);
}

unsigned long gettickcount()
{
#ifdef	UNIX		/* [ for UNIX ] */
	struct timeval	tv;
	gettimeofday(&tv, NULL);
	return (tv.tv_sec * 1000 + tv.tv_usec / 1000);
#elif	defined(WIN32)  /* [ for Windows ] */
	return GetTickCount();
#endif			/* [ #ifdef UNIX ] */
}

int	cclRTPWrite(int channel, const char* buff, int len)
{
	rtp_pkt_t	pkt;
	rtp_pkt_param_t	param;
	int		retlen = 0;

	if( channel<0 || channel>=MAX_RTP_CHANS || 
	    !rtp[channel] || len <0 )
		return -1;

	rtp_pkt_init(&pkt, len * 2);
	pkt.datalen = len;
	memset(&param, 0, sizeof(param));

	param.ts = gettickcount() * 8;
	param.pt = 1;
	rtp_pkt_setparam(&pkt, &param);
	memcpy(pkt.data,(void*)buff,len);
	
	retlen = rtp_write(rtp[channel], &pkt);
	if( retlen>(int)pkt.datalen ) 
		retlen = pkt.datalen;
	
	rtp_pkt_free(&pkt);

	return retlen;
}

RETCODE	cclRTPSetPeerAddr(int channel, char* addr, int port)
{
	int ret = 0;

	if( channel<0 || channel>=MAX_RTP_CHANS || 
	    !rtp[channel] || !addr || port<0 )
		return -1;

	ret = rtp_setpeeraddr(rtp[channel],addr,port);
	if( ret!=0 )
		return -1;
	ret = rtcp_setpeeraddr(rtcp[channel],addr,port+1);

	return ret;
}

