/* audnet.c
   L. Stewart November 13, 1982  4:32 PM
 */

#include	"Ec.h"
#include	"Env.h"
#include	"Alloc.h"
#include	"Queue.h"
#include	"Pup.h"
#include	"Encrypt.h"
#include	"LarkNet.h"

#define VoiceLowSocket 111
#define VoiceHighSocket 222

/* comm */
extern SendPup();
extern int EtherHost();
extern struct PBI *GetPBI();
extern int OpenLevel1Socket();
extern CloseLevel1Socket();
extern ReleasePBI();

/* runtime */
extern int Swab();
extern MoveBlock();
extern CallSwat();

/* encryption */
extern Encrypt();

struct Port source, dest;
struct PBI *mikePBI;
struct Pup *mikePup;
struct ECB loECB, hiECB, daECB, dbECB;

static int bytesDecrypted;   /* num finished in first pass of wraparound case */

extern int *silval1; /* silence value for buffer 1 */
extern char *inbuf1; /* input buffer 1 */
extern char *obuf1; /* output buffer 1 */
extern int *bufptr;  /* ring buffer pointer */
extern int audioMode;  /* control program */

static int lsoc;	/* saved for CloseSocket */
static int nextIndex;	/* next spot in ringbuffer */
static int silCount;	/* packets since silence started */
static int silLimit;	/* number of silent packets to transmit */
static int silThresh;	/* definition of silence */
static int stayAliveLimit;	/* interval to send empty packets */

static int numSample;	/* number of packets total */
static int numPackets;	/* number of packets transmitted */

static int expSample;	/* expected sample number */
static int expPacket;	/* expected packet number */

static int pktsMissed;	/* number of runs of packets missed */
static int pktsDuped;	/* number of duplicate packets */
static char myKey[8];
extern /* FORWARD */ FromNet();

InitNetStuff()
  {
  SetConstants(5, 16, 4096);
  };

SetConstants(sL, sAL, sT)
  int sL, sAL, sT;
  {
  int i;
  silLimit = sL;
  stayAliveLimit = sAL;
  silThresh = sT;
  for (i=0; i<8; i+=1) myKey[i] = 01;
  };

PrintNetStuff()
  {
  wf2("numSample: %u, numPackets: %u\r", numSample, numPackets);
  wf2("expSample: %u, expPacket: %u\r", expSample, expPacket);
  wf2("pktsMissed: %u, pktsDuped: %u\r", pktsMissed, pktsDuped);
  wf2("silLimit: %u, stayAliveLimit: %u\r", silLimit, stayAliveLimit);
  wf1("silThresh: %u\r", silThresh);
  };

StartNet(dnet, dhost, encb)
  char dnet, dhost;
  int encb;
  {
  char *ek;
  if (encb) ek = myKey;
  else ek = 0;
  nextIndex = 0;
  silCount = 0;
  numSample = 0;
  numPackets = 0;
  expSample = 0;
  expPacket = 0;
  pktsMissed = 0;
  pktsDuped = 0;
  source.net = 0;  /* will be filled in by Open socket */
  source.host = 0;
  source.socket.LS = Swab(VoiceLowSocket);
  source.socket.ms = Swab(VoiceHighSocket);
  dest.net = dnet;
  dest.host = dhost;
  dest.socket.LS = Swab(VoiceLowSocket);
  dest.socket.ms = Swab(VoiceHighSocket);
  loECB.next = 0;
  loECB.kp = ek;
  loECB.srcp = inbuf1;
  loECB.encrypt = true;
  loECB.count = 160;
  loECB.proc = (int) &SendPup;
  hiECB.next = 0;
  hiECB.kp = ek;
  hiECB.srcp = &inbuf1[160];
  hiECB.encrypt = true;
  hiECB.count = 160;
  hiECB.proc = (int) &SendPup;
  daECB.next = 0;
  daECB.kp = ek;
  daECB.encrypt = false;
  dbECB.next = 0;
  dbECB.kp = ek;
  dbECB.dstp = obuf1;
  dbECB.encrypt = false;
  dbECB.proc = (int) &ReleasePBI;
  if (!(lsoc = OpenLevel1Socket(&source, &FromNet, 0))) CallSwat(ecPup1+10);
  SetupPBI();
  };

StopNet()
  {
  if (audioMode == AMNet) {
    CloseLevel1Socket(lsoc);
    audioMode = AMOff;
    if (mikePBI != 0) ReleasePBI(mikePBI);
    mikePBI = 0;
    mikePup = 0;
    wf("talk off\r");
    };
  };
/* other aud net components */

ToNet(h)
  int h;
  {
  if ((silCount < silLimit) || (*silval1 > silThresh)) {
    mikePup->id[0] = Swab(numSample);
    mikePup->id[1] = Swab(numPackets);
    if (h) {
      hiECB.dstp = &mikePup->data;
      hiECB.item = (int) mikePBI;
      Encrypt(&hiECB);
      };
    else {
      loECB.dstp = &mikePup->data;
      loECB.item = (int) mikePBI;
      Encrypt(&loECB);
      };
    numPackets += 1;
    silCount = (*silval1 > silThresh) ? 0 : silCount+1;
    SetupPBI();
    };
  else {
    if (silCount > stayAliveLimit) {
      silCount = silLimit;
      mikePup->id[0] = Swab(numSample);
      mikePup->id[1] = Swab(numPackets);
      mikePup->type = VoiceAliveType;
      mikePup->length = Swab(pupOvBytes);
      SendPup(mikePBI);
      SetupPBI();
      numPackets += 1;
      };
    else silCount += 1;
    };
  numSample += 1;
  };

SetupPBI()
  {
  mikePBI = GetPBI();
  mikePup = mikePBI->pup;
  mikePup->length = Swab(160+pupOvBytes);
  mikePup->transport = 0;
  mikePup->type = VoiceType
  MoveBlock(&mikePup->dPort, &dest, lenPort);
  MoveBlock(&mikePup->sPort, &source, lenPort);
  };

/* with encryption */
FromNet(p)
  struct PBI *p;
  {
  struct Pup *iPup;
  int diff, thisIndex;
  iPup = p->pup;
  diff = Swab(iPup->id[1]) - expPacket;
  if (diff < 0) pktsDuped += 1;
  if (diff > 0) pktsMissed += 1;
  expPacket = Swab(iPup->id[1]) + 1;
  if ((iPup->type == VoiceType) && (diff >= 0) && (diff < 50)) {
    diff = Swab(iPup->id[0]) - expSample;
    expSample = Swab(iPup->id[0]) + 1;
    thisIndex =  (diff == 0) ? nextIndex : *bufptr+80;
    thisIndex &= 0xfff8;
    if (thisIndex >= 320) thisIndex -= 320;
    DecryptFromTo(p, thisIndex);
    nextIndex = thisIndex + 160;
    if (nextIndex >= 320) nextIndex -= 320;
    };
  else ReleasePBI(p);
  };

DecryptFromTo(p, toIndex)
  struct PBI *p;
  int toIndex;
  {
  daECB.srcp = &p->pup->data;
  daECB.dstp = &obuf1[toIndex];
  if (toIndex > 160) {
    daECB.proc = (int) &Encrypt;
    daECB.item = (int) &dbECB;
    daECB.count = bytesDecrypted = 320 - toIndex;
    dbECB.srcp = &p->pup->data.bytes[bytesDecrypted];
    dbECB.count = 160 - bytesDecrypted;
    dbECB.item = (int) p;
    };
  else {
    daECB.proc = (int) &ReleasePBI;
    daECB.count = 160;
    daECB.item = (int) p;
    };
  Encrypt(&daECB);
  };