/***************************************************************************
                          ts2rtp.cpp  -  description
                             -------------------
    begin                : Mon Feb 3 2003
    copyright            : (C) 2003-2005 by Christophe Thommeret
    email                : hftom@free.fr
    last modified        : $Date: 2005/04/27 19:38:47 $ by $Author: hftom $

    some code from :
		dvbstream (GPL), Copyright (C) Dave Chapman 2001,2002
 ***************************************************************************/

/***************************************************************************
 *                                                                         *
 *   This program is free software; you can redistribute it and/or modify  *
 *   it under the terms of the GNU General Public License as published by  *
 *   the Free Software Foundation; either version 2 of the License, or     *
 *   (at your option) any later version.                                   *
 *                                                                         *
 ***************************************************************************/

#include <sys/time.h>

#include <kmessagebox.h>
#include <klocale.h>

#include "ts2rtp.h"
#include "gdvb.h"

#define TS_SIZE 188



Ts2Rtp::Ts2Rtp() : Sender()
{
	thWrite = 0;
	rtpSocket = 0;
	/* fill in the MPEG-2 TS deefaults */
	/* Note: MPEG-2 TS defines a timestamping base frequency of 90000 Hz. */
	hRtp.b.v=2;
	hRtp.b.p=0;
	hRtp.b.x=0;
	hRtp.b.cc=0;
	hRtp.b.m=0;
	hRtp.b.pt=33;
	hRtp.b.sequence=rand() & 65535;
	hRtp.timestamp=rand();
	hRtp.ssrc=rand();
}



Ts2Rtp::~Ts2Rtp()
{
	stop();
	if ( rtpSocket ) {
		close( rtpSocket );
	}
}



void Ts2Rtp::setSocket( const QString &addr, int m_port, int m_senderPort )
{
	address = addr;
	port = m_port;
	senderPort = m_senderPort;
}



bool Ts2Rtp::addChannel( const QString &name, unsigned int pidv, unsigned int pida, char ac3, unsigned int spid, unsigned int pg, unsigned int an, unsigned int tp, const QString &lg )
{
	if ( !rtpSocket ) if ( !makeSocket() ) return false;

	bchan.append( new BChannel( name, pidv, pida, ac3, spid, pg, an, tp, lg ) );
	return true;
}



void Ts2Rtp::removeChannel( const QString &name )
{
	int i;

	for ( i=0; i<(int)bchan.count(); i++ ) {
		if ( bchan.at(i)->name==name ) {
			bchan.remove( bchan.at(i) );
			break;
		}
	}

	if ( bchan.count()<1 && rtpSocket ) {
		stop();
		close( rtpSocket );
		rtpSocket = 0;
		fprintf( stderr, "rtp socket closed\n" );
		thWrite = 0;
	}
}



bool Ts2Rtp::makeSocket()
{
	int iRet, iLoop = 1;

	if ( !makeSenderSocket( address, senderPort ) ) return false;

	rtpSocket = socket( AF_INET, SOCK_DGRAM, 0 );

	if ( rtpSocket < 0) {
		KMessageBox::error( 0, i18n("Can't open DVB broadcast socket.") );
		rtpSocket = 0;
		closeSender();
		return false;
	}

	rtpAddr.sin_family = AF_INET;
	rtpAddr.sin_port = htons( port );
	rtpAddr.sin_addr.s_addr = inet_addr( address.ascii() );

	iRet = setsockopt( rtpSocket, SOL_SOCKET, SO_BROADCAST, &iLoop, sizeof(iLoop));
	if (iRet < 0) {
		KMessageBox::error( 0, i18n("Can't init DVB broadcast socket.") );
		close( rtpSocket );
		rtpSocket = 0;
		closeSender();
		return false;
	}
	go();
	fprintf( stderr, "rtp socket opened\n" );
	return true;
}



void Ts2Rtp::process( unsigned char *buf, int size )
{
	int i;
	unsigned char *buffer=buf;

	for ( i=0; i<size; i+=TS_SIZE ) {
		memcpy( thBuf+thWrite, buffer, TS_SIZE );
		thWrite+=TS_SIZE;
		if ( thWrite==(TS_SIZE*8 ) ) {
			sendrtp( (char*)thBuf, TS_SIZE*8 );
			thWrite = 0;
		}
		buffer+=TS_SIZE;
	}
}



/* Send a single RTP packet, converting the RTP header to network byte order. */
void Ts2Rtp::sendrtp( char *data, int len )
{
	struct timeval tv;

	gettimeofday( &tv, (struct timezone*) NULL );
	hRtp.timestamp = ((tv.tv_sec%1000000)*1000 + tv.tv_usec/1000)*90;

	char *buf=(char*)alloca(len+72);
	unsigned int intP;
	char* charP = (char*) &intP;
	int headerSize;
	buf[0]  = 0x00;
	buf[0] |= ((((char) hRtp.b.v)<<6)&0xc0);
	buf[0] |= ((((char) hRtp.b.p)<<5)&0x20);
	buf[0] |= ((((char) hRtp.b.x)<<4)&0x10);
	buf[0] |= ((((char) hRtp.b.cc)<<0)&0x0f);
	buf[1]  = 0x00;
	buf[1] |= ((((char) hRtp.b.m)<<7)&0x80);
	buf[1] |= ((((char) hRtp.b.pt)<<0)&0x7f);
	intP = htonl(hRtp.b.sequence);
	memcpy(&buf[2],charP+2,2);
	intP = htonl(hRtp.timestamp);
	memcpy(&buf[4],&intP,4);
	/* SSRC: not implemented */
	buf[8]  = 0x0f;
	buf[9]  = 0x0f;
	buf[10] = 0x0f;
	buf[11] = 0x0f;
	headerSize = 12 + 4*hRtp.b.cc; /* in bytes */
	memcpy(buf+headerSize,data,len);

	hRtp.b.sequence++;
	if ( rtpSocket ) sendto( rtpSocket, buf, len+headerSize, 0, (struct sockaddr *)&rtpAddr, sizeof(rtpAddr) );
}
