/**
 *  GraphTFT plugin for the Video Disk Recorder 
 * 
 *  transfer.c - A plugin for the Video Disk Recorder
 *
 *  (c) 2004 Lars Tegeler, Sascha Volkenandt  
 *
 * This code is distributed under the terms and conditions of the
 * GNU GENERAL PUBLIC LICENSE. See the file COPYING for details.
 *
 * $Id: transfer.c,v 1.2 2007/06/16 08:50:07 root Exp $
 *
 **/

#include <transfer.h>

cGraphTFTTransfer::cGraphTFTTransfer(Renderer* renderer, const cChannel* Channel)
#if APIVERSNUM >= 10500
   : cReceiver(Channel->GetChannelID(), 0,
#else
   : cReceiver(Channel->Ca(), 0,
#endif
               Channel->Vpid(), 
               Channel->Apids(), 
               Channel->Dpids()),
     cThread("GraphTFT transfer")

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

  _remux = new cRemux(Channel->Vpid(), 
                      Channel->Apids(), Channel->Dpids(), 
                      Channel->Spids());

  _canToggleAudioTrack = false;
  _audioTrack = 0xC0;
  _gotBufferReserve = false;
  _active = false;
  _render = renderer;
}

cGraphTFTTransfer::~cGraphTFTTransfer()
{
  cReceiver::Detach();
  delete _remux;
  delete _ringBuffer;
}

void cGraphTFTTransfer::Activate(bool On)
{
   if (On) 
   {
      if (!_active)
         Start();
   }
   else if (_active) 
   {
      _active = false;
      Cancel(3);
   }
}

void cGraphTFTTransfer::Receive(uchar *Data, int Length)
{
   int i = 0;
   
   while (_active && Length > 0) 
   {
      if (i++ > 10) 
      {
         _ringBuffer->ReportOverflow(Length);
         break;
      }

      int p = _ringBuffer->Put(Data, Length);

      Length -= p;
      Data += p;
   }
}

void cGraphTFTTransfer::Action()
{
   int PollTimeouts = 0;

   _active = true;
  
   while (_active) 
   {
      int r;
      const uchar* b = _ringBuffer->Get(r);

      // Play the data:

      if (b) 
      {
         int Count = r, Result;
         // uchar* p = _remux->Process(b, Count, Result);

         uchar* p = 0;

         _ringBuffer->Del(Count);

         if (p) 
         {
            StripAudioPackets(p, Result, _audioTrack);

            while (Result > 0 && _active) 
            {
               cPoller Poller;

               if (_render->devicePoll(Poller, 100)) 
               {
                  int w = _render->playVideo(p, Result);

                  PollTimeouts = 0;

                  if (w > 0) 
                  {
                     p += w;
                     Result -= w;
                  }
                  else if (w < 0 && FATALERRNO) 
                  {
                     LOG_ERROR;
                     break;
                  }
               }
               else 
               {
                  PollTimeouts++;

                  if (PollTimeouts == POLLTIMEOUTS_BEFORE_DEVICECLEAR) 
                  {
                     dsyslog("clearing device because of consecutive poll timeouts");
                     _render->deviceClear();
                  }
               }
            }
         }
      }
      else
         usleep(1);
   }
}

void cGraphTFTTransfer::StripAudioPackets(uchar *b, int Length, uchar Except)
{
   for (int i = 0; i < Length - 6; i++) 
   {
      if (b[i] == 0x00 && b[i + 1] == 0x00 && b[i + 2] == 0x01) 
      {
         uchar c = b[i + 3];
         int l = b[i + 4] * 256 + b[i + 5] + 6;

         switch (c) 
         {
            case 0xBD:               // dolby
               if (Except)
                  //render->playAudio(&b[i], l);
                  // continue with deleting the data - otherwise it disturbs DVB replay
                  case 0xC0 ... 0xC1: // audio
                  if (c == 0xC1)
                     _canToggleAudioTrack = true;
               if (!Except || c != Except)
                  memset(&b[i], 0x00, min(l, Length-i));

               break;

            case 0xE0 ... 0xEF:       // video
               break;

            default:
               //esyslog("ERROR: unexpected packet id %02X", c);
               l = 0;
         }

         if (l)
            i += l - 1; // the loop increments, too!
      }

      /*
        else
        esyslog("ERROR: broken packet header");
      */
   }
}

int cGraphTFTTransfer::NumAudioTracks() const
{
   return _canToggleAudioTrack ? 2 : 1;
}

const char **cGraphTFTTransfer::GetAudioTracks(int *CurrentTrack) const
{
   if (NumAudioTracks()) 
   {
      if (CurrentTrack)
         *CurrentTrack = (_audioTrack == 0xC0) ? 0 : 1;

      static const char *audioTracks1[] = { "Audio 1", NULL };
      static const char *audioTracks2[] = { "Audio 1", "Audio 2", NULL };

      return NumAudioTracks() > 1 ? audioTracks2 : audioTracks1;
   }

   return 0;
}

// void cGraphTFTTransfer::SetAudioTrack(eTrackType Type, const tTrackId* TrackId)
// {
//    if ((_audioTrack == 0xC0) != (TrackId == 0)) 
//    {
//       _audioTrack = (TrackId == 1) ? 0xC1 : 0xC0;
//       _render->deviceClear();
//    }
// }
