/*
 *   MediaMVP Server
 *
 *   (C) 2003 Dominic Morris
 *
 *   $Id: transceiver.c,v 1.8 2005/02/06 14:18:42 dom Exp $
 *   $Date: 2005/02/06 14:18:42 $
 *
 *   Transceiver stuff - blatantly stolen from streamdev then changed
 *   a bit..
 */





#include "transceiver.h"
#include "remux/ts2ps.h"
#include "remux/ts2es.h"
#include "setup.h"

#include <vdr/ringbuffer.h>

#include <sys/types.h>
#include <unistd.h>

#include "libmvp.h"

#define VIDEOBUFSIZE MEGABYTE(1)

/* Disable logging if BUFCOUNT buffer overflows occur within BUFOVERTIME
   milliseconds. Enable logging again if there is no error within BUFOVERTIME
   milliseconds. */
#define BUFOVERTIME  5000
#define BUFOVERCOUNT 100

cMediamvpTransceiver::cMediamvpTransceiver(const cChannel *Channel, int Priority, int Socket, cDevice *Device) :
#if VDRVERSNUM >= 10319
		cReceiver(Channel->Ca(), Priority, Channel->Vpid(), Channel->Apids(), Channel->Dpids(), Channel->Spids()) {
#else
                cReceiver(Channel->Ca(), Priority, 7, Channel->Vpid(), Channel->Ppid(),
#if VDRVERSNUM >= 10318
                                Channel->Apid(0), Channel->Apid(1), Channel->Dpid(0), Channel->Dpid(1), 
#else
                                Channel->Apid1(), Channel->Apid2(), Channel->Dpid1(), Channel->Dpid2(), 
#endif
                                Channel->Tpid()) {
#endif
        m_Active = false;
        m_Socket = Socket;
        m_Remux = NULL;
        m_Device = Device;

        m_RingBuffer = new cRingBufferLinear(VIDEOBUFSIZE, TS_SIZE * 2, true);

    /* Select the correct Muxing depending on whether it's video or not */
    if ( Channel->Vpid() == 0 || Channel->Vpid() == 1 || Channel->Vpid() == 0x1FFF ) {
#if VDRVERSNUM >= 10318
        m_Remux = new cTS2ESRemux(Channel->Apid(0));
#else
        m_Remux = new cTS2ESRemux(Channel->Apid1());
#endif
    } else {
#if VDRVERSNUM >= 10318
                m_Remux = new cTS2PSRemux(Channel->Vpid(), Channel->Apid(0), 0, 0, 0, 0);
#else
                m_Remux = new cTS2PSRemux(Channel->Vpid(), Channel->Apid1(), 0, 0, 0, 0);
#endif
    }
    Dprintf(MOO,"Created transceiver at %p, remux @%p ringbuffer %p\n",this,m_Remux,m_RingBuffer);

    /* Suggested by Peter Wagner to assist single DVB card systems */
#ifdef SINGLE_DEVICE
        m_Device->SwitchChannel(Channel, true);
#else
        m_Device->SwitchChannel(Channel, false);
#endif
        Attach();
}

cMediamvpTransceiver::~cMediamvpTransceiver(void) 
{
    Dprintf(MOO,"Deleting transceiver at %p, remux @%p ringbuffer %p\n",this,m_Remux,m_RingBuffer);

        Detach();
        if (m_Remux) 
        delete m_Remux;
    m_Remux = NULL;
    if ( m_RingBuffer)
        delete m_RingBuffer;
    m_RingBuffer = NULL;
}

void cMediamvpTransceiver::Activate(bool On) 
{
        if (On)
                Start();
        else if (m_Active)
                Stop();
}

void cMediamvpTransceiver::Stop(void) 
{
        if (m_Active) {
                m_Active = false;
                usleep(50000);
                Cancel(0);
        }
}

void cMediamvpTransceiver::Receive(uchar *Data, int Length) 
{
        static time_t firsterr = 0;
        static int errcnt = 0;
        static bool showerr = true;

        if (m_Active) {
                int p = m_RingBuffer->Put(Data, Length);
                if (p != Length) {
#if VDRVERSNUM >= 10318
			int now = int(cTimeMs::Now());
#else
			int now = time_ms();
#endif
                        ++errcnt;
                        if (showerr) {
                                if (firsterr == 0)
                                        firsterr = now;
                                else if (firsterr + BUFOVERTIME > now&& errcnt > BUFOVERCOUNT) {
                                        esyslog("ERROR: too many buffer overflows, logging stopped");
                                        showerr = false;
                                        firsterr = now;
                                }
                        } else if (firsterr + BUFOVERTIME < now) {
                                showerr = true;
                                firsterr = 0;
                                errcnt = 0;
                        }

                        if (showerr)
                                esyslog("ERROR: ring buffer overflow (%d bytes dropped)", Length - p);
                        else
                                firsterr = now;
                }
        }
}

void cMediamvpTransceiver::Action(void) 
{
        int max = 0;


        isyslog("Mediamvp: Transceiver thread started (pid=%d)", getpid());


        m_Active = true;

        while (m_Active) {
                int recvd;
                const uchar *block = m_RingBuffer->Get(recvd);

                if (block && recvd > 0) {
                        const uchar *sendBlock;
                        int bytes = 0;
                        int taken = recvd;

            sendBlock = m_Remux->Process(block, taken, bytes);

                        m_RingBuffer->Del(taken);

                        if (bytes > max)
                                max = bytes;

            write(m_Socket,sendBlock,bytes);

                } else
                        usleep(1);
        }

        
        isyslog("Mediamvp: Transceiver thread ended");
}

