/*---------------------------------------------------------------------------*\

	FILE....: tecsix.cpp
	TYPE....: C Program
	AUTHOR..: Ben Kramer
	DATE....: 25/06/03


\*--------------------------------------------------------------------------*/

/*--------------------------------------------------------------------------*\

         Voicetronix Voice Processing Board (VPB) Software

         Copyright (C) 1999-2003 Voicetronix www.voicetronix.com.au

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

         This library is distributed in the hope that it will be useful,
         but WITHOUT ANY WARRANTY; without even the implied warranty of
         MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
         Lesser General Public License for more details.

         You should have received a copy of the GNU Lesser General Public
         License along with this library; if not, write to the Free Software
         Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307
	 USA

\*---------------------------------------------------------------------------*/

#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <pthread.h>
#include <string.h>
#include "vpbapi.h"

//#define	BUF_SIZE        160	// size of processing frame (samples) (20ms)
#define	BUF_SIZE        5*8	// size of processing frame (samples) (5ms)
//#define PEC		6	// Ports of Echo Cancelation
#define PEC		4	// Ports of Echo Cancelation

// local functions
void *event_thread(void *pv);
void *conf_thread(void *pv);
int kbhit();
void add(short c[], short a[], short b[]);
int arg_exists(int argc, char *argv[], char *arg);

int finish;
 
int main(int argc, char *argv[])
{
	pthread_t	ev_thread;
	pthread_t	c_thread[PEC];
	int		baseport=0,i;
	int		lines[PEC];

	if (argc < 2) {
		printf("usage: tecsix <base port> \n");
		exit(0);
	}
	baseport=atoi(argv[1]);
	printf("Using base port %d\n",baseport);

	// initialise 

	for (i=0;i<PEC;i++){
		lines[i] = vpb_open(0,(baseport+i));
	}
	printf("Setting up EC...\n");
	//vpb_hostecho_opt(lines[0]);
	for (i=0;i<PEC;i++){
		vpb_hostecho_on(lines[i]);
	}


	// start main processing loop ---------------------------
		
	finish = 0;
	pthread_create(&ev_thread, NULL, event_thread, NULL);
	       

	for (i=0;i<PEC;i++){
		vpb_record_buf_start(lines[i], VPB_LINEAR);
		vpb_play_buf_start(lines[i], VPB_LINEAR);
	}
	for (i=0;i<PEC/2;i++){
		pthread_create(&(c_thread[i]), NULL, conf_thread, (void *)(lines[2*i]));
	}
//	pthread_create(&(c_thread[1]), NULL, conf_thread, (void *)(lines[2]));
//	pthread_create(&(c_thread[2]), NULL, conf_thread, (void *)(lines[4]));


	while(!kbhit()) {
		vpb_sleep(100);
	}

	for(i=0;i<PEC;i++){
		vpb_record_buf_finish(lines[i]);
		vpb_play_buf_finish(lines[i]);
		vpb_hostecho_off(lines[i]);
		vpb_sethook_sync(lines[i],VPB_ONHOOK);
	}

	finish = 1;
	
	// clean up and finish 

	return 0;
}	

void *conf_thread(void *pv) {
	short	buf1[BUF_SIZE],buf2[BUF_SIZE];
	int	line1,line2;
	line1=(long)pv;
	line2=line1+1;
	printf("Conf Thread for %d and %d started ...\n",line1,line2);
	do {
		vpb_record_buf_sync(line1, (char*)buf1,sizeof(short)*BUF_SIZE);
		vpb_record_buf_sync(line2, (char*)buf2,sizeof(short)*BUF_SIZE);
		vpb_play_buf_sync(line1, (char*)(buf2),sizeof(short)*BUF_SIZE);
		vpb_play_buf_sync(line2, (char*)(buf1),sizeof(short)*BUF_SIZE);
	} while(!finish);
	return NULL;
}

void *event_thread(void *pv) {
	char	  s[VPB_MAX_STR];
        VPB_EVENT e;
	int busy[PEC];
	int i;
	for (i=0;i<PEC;i++){
		busy[i]=0;
	}

	do {
		// check for events from VPB

		while(vpb_get_event_async(&e) == VPB_OK) {
			vpb_translate_event(&e, s);
			printf(s);

			// take channels off-hook on ring
			if (e.type == VPB_RING) {
				vpb_sethook_sync(e.handle, VPB_OFFHOOK);
			}
			if (e.type == VPB_TONEDETECT){
				if ((e.data == VPB_BUSY)||(e.data == VPB_BUSY_308)){
					busy[e.handle]++;
					if(busy[e.handle]>5){
						vpb_sethook_sync(e.handle, VPB_ONHOOK);
						busy[e.handle]=0;
					}
				}
			}
		}
		vpb_sleep(10);

	} while(!finish);

	return NULL;
}

void add(short c[], short a[], short b[]) {
	int   i;
	float sam;

	for(i=0; i<BUF_SIZE; i++) {
		sam = a[i] + b[i];
		if (sam > 32767) sam = 32767;
		if (sam < -32767) sam = 32767;
		c[i] = (short)sam;
	}
}

int arg_exists(int argc, char *argv[], char *arg) {
  int i;

  for(i=0; i<argc; i++)
    if (strcmp(argv[i],arg) == 0)
      return i;

  return 0;
}
