/*

				 VAT packet interconversion routines

*/

#include "netfone.h"
#include "vat.h"

#define bcopy(s, d, l)	memcpy(d, s, l)
#define bzero(d, l)		memset(d, 0, l)

static audio_descr_t adt[] = {
/* enc	   sample ch */
  {AE_PCMU,  8000, 1},	/*	0 PCMU */
  {AE_MAX,	 8000, 1},	/*	1 1016 */
  {AE_MAX,		0, 1},	/*	2 G721 32 kb/s CCITT ADPCM */
  {AE_GSM,	 8000, 1},	/*	3 GSM */
  {AE_MAX,		0, 1},	/*	4 G723 24 kb/s CCITT ADPCM */
  {AE_MAX,		0, 1},	/*	5 unassigned */
  {AE_MAX,		0, 1},	/*	6 unassigned */
  {AE_MAX,		0, 1},	/*	7 unassigned */
  {AE_MAX,		0, 1},	/*	8 unassigned */
  {AE_MAX,		0, 1},	/*	9 unassigned */
  {AE_MAX,		0, 1},	/* 10 unassigned */
  {AE_MAX,		0, 1},	/* 11 unassigned */
  {AE_MAX,		0, 1},	/* 12 unassigned */
  {AE_MAX,		0, 1},	/* 13 unassigned */
  {AE_MAX,		0, 1},	/* 14 unassigned */
  {AE_MAX,		0, 1},	/* 15 unassigned */
  {AE_MAX,		0, 1},	/* 16 unassigned */
  {AE_MAX,		0, 1},	/* 17 unassigned */
  {AE_MAX,		0, 1},	/* 18 unassigned */
  {AE_MAX,		0, 1},	/* 19 unassigned */
  {AE_MAX,		0, 1},	/* 20 unassigned */
  {AE_MAX,		0, 1},	/* 21 unassigned */
  {AE_MAX,		0, 1},	/* 22 unassigned */
  {AE_MAX,		0, 1},	/* 23 unassigned */
  {AE_MAX,		0, 1},	/* 24 unassigned */
  {AE_MAX,		0, 1},	/* 25 unassigned */
  {AE_MAX,		0, 1},	/* 26 L16, 16000 samples/sec */
  {AE_MAX,		0, 1},	/* 27 L16, 44100 samples/sec, 2 channels */
  {AE_LPC,	 8000, 1},	/* 28 LPC, 4 frames */
  {AE_LPC,	 8000, 1},	/* 29 LPC, 1 frame */
  {AE_IDVI,  8000, 1},	/* 30 32 kb/s Intel DVI ADPCM */
  {AE_MAX,		0, 1},	/* 31 unassigned */
};

/*	ISVAT  --  Determine if this is a parseable VAT format packet.
			   If so, convert it to an equivalent sound buffer.  */

int isvat(unsigned char *pkt, int len)
{
	int findex = pkt[1] & VATHF_FMTMASK;
	soundbuf *s = (soundbuf *) pkt;

	/* Validate (as much as possible) whether this is a VAT packet
       that we're able to translate. */
       
	if (((pkt[0] & 0xC0) == 0) && ((pkt[1] & 0x60) == 0) /* &&
		(adt[findex].encoding != AE_MAX) */
	) {

		unsigned char *payload;
		int paylen;
#define sb	ebuf		

/*fprintf(stderr, "VAT Ver = %d, nsid = %d, ts = %d, format = %d confid = %d, tstamp = %ld\n",
	pkt[0] >> 6, pkt[0] & NSID_MASK, !!(pkt[1] & VATHF_NEWTS), findex,
	(((unsigned int) pkt[2]) << 8) | pkt[3],
	(((unsigned long) pkt[4]) << 24) |
	(((unsigned long) pkt[5]) << 16) |
	(((unsigned long) pkt[6]) <<  8) |
	(((unsigned long) pkt[7]) <<  0));
*/

		payload = pkt + (8 + 4 * (pkt[0] & NSID_MASK)); /* Payload start */
		paylen = len - ((8 + 4 * (pkt[0] & NSID_MASK))); /* Payload length */
		sb.compression = fProtocol;
		sb.buffer.buffer_len = 0;

#ifdef NEEDED
		/* Fake a VAT unique host name from the conference identifier. */

        sprintf(sb.sendinghost, ".VAT:%02X%02X",
			pkt[2], pkt[3]);
#else
        strcpy(sb.sendinghost, ".VAT");
#endif

		switch (adt[findex].encoding) {

			case AE_PCMU:
				sb.buffer.buffer_len = paylen;
				bcopy(payload, sb.buffer.buffer_val, paylen);
				break;

			case AE_GSM:
				sb.buffer.buffer_len = paylen + sizeof(short);
				bcopy(payload, sb.buffer.buffer_val + 2, paylen);
				*((short *) sb.buffer.buffer_val) =
					htons((short) ((((long) paylen) * 160) / 33));
				sb.compression |= fCompGSM;
				break;

			case AE_IDVI:
				bcopy(payload + 4, sb.buffer.buffer_val, paylen - 4);
				bcopy(payload, sb.buffer.buffer_val + (paylen - 4), 3);
				sb.buffer.buffer_len = paylen - 1;
				if (adt[findex].sample_rate == 8000) {
					sb.compression |= fCompADPCM;
				} else {
#ifdef NEEDED

					/* Bogus attempt to convert sampling rate.	We
                       really need to do this in linear mode, which isn't
					   supported on all SPARCs.  This is better than
					   nothing, though. */

					int inc = adt[findex].sample_rate / 8000, i;
					unsigned char *in = (unsigned char *) sb.buffer.buffer_val,
								  *out = (unsigned char *) sb.buffer.buffer_val;

					adpcmdecomp(&sb);
					for (i = 0; i < (paylen - 4) / inc; i++) {
						*out++ = *in;
						in += inc;
					}
					sb.buffer.buffer_len /= inc;
#endif
				}
				break;

			case AE_LPC:
				sb.buffer.buffer_len = paylen + sizeof(short);
				{	int i;
					unsigned char *in = payload,
								  *out = (unsigned char *) sb.buffer.buffer_val + 2;

					for (i = 0; i < paylen / 14; i++) {
						bcopy(in, out, 3);
						out[3] = 0;
						bcopy(in + 3, out + 4, 10);
						in += 14;
						out += 14;
					}
				}
				*((short *) sb.buffer.buffer_val) =
					htons((short) ((((long) paylen) * LPC_FRAME_SIZE) / 14));
				sb.compression |= fCompLPC;
				break;

			case AE_L16:
				if (adt[findex].channels == 1) {
					int i, j, k;
				
					for (i = j = k = 0; i < (paylen / 8); i++) {
						if ((k & 3) != 2  && ((i % 580) != 579)) {
							sb.buffer.buffer_val[j++] =
								audio_s2u((((unsigned short *) payload)[i * 4]));
						}
						k = (k + 1) % 11;
					}
					sb.buffer.buffer_len = j;
				} else if (adt[findex].channels == 2) {
					int i, j, k;
				
					for (i = j = k = 0; i < (paylen / 16); i++) {
						if ((k & 3) != 2  && ((i % 580) != 579)) {
							sb.buffer.buffer_val[j++] =
								audio_s2u(((((unsigned short *) payload)[i * 8]) +
										   (((unsigned short *) payload)[i * 8 + 1])) / 2);
						}
						k = (k + 1) % 11;
					}
					sb.buffer.buffer_len = j;
				}
				break;

			default:
				/* Unknown compression type. */
				sb.buffer.buffer_len = 0;
				break;
		}
		bcopy((char *) &sb, (char *) pkt, (int) (((sizeof sb - BUFL)) + sb.buffer.buffer_len));
//xd(pkt, (int) ((sizeof sb - BUFL) + sb.buffer.buffer_len), TRUE);
		return TRUE;
#undef sb		
	}
	return FALSE;
}

/*	VATOUT	--	Convert a sound buffer into a VAT packet, given the
				timestamp for the next packet sent to this connection.	*/

LONG vatout(soundbuf *sb, unsigned long ssrc_i, unsigned long timestamp_i, int spurt)
{
#define rp ebuf
	char *pkt = (char *) &rp;
	LONG pl = 0;

	pkt[0] = 0;

	pkt[1] = spurt ? 0x80 : 0;

	pkt[2] = (char) (ssrc_i & 0xFF);
	pkt[3] = (char) ((ssrc_i >> 8) & 0xFF);

	*((long *) (pkt + 4)) = htonl(timestamp_i);

	if (sb->compression & fCompGSM) {
		pkt[1] |= VAT_AUDF_GSM;
		bcopy((char *) sb->buffer.buffer_val + 2, pkt + 8,
				  (int) sb->buffer.buffer_len - 2);
		pl = (sb->buffer.buffer_len - 2) + 8;

	} else if (sb->compression & fCompADPCM) {
		pkt[1] |= VAT_AUDF_IDVI;
		bcopy((char *) sb->buffer.buffer_val, pkt + 8 + 4,
				  (int) sb->buffer.buffer_len - 3);
		bcopy(sb->buffer.buffer_val + ((int) sb->buffer.buffer_len - 3),
				  pkt + 8, 3);
		pkt[8 + 3] = 0;
		pl = (sb->buffer.buffer_len + 1) + 8;

	} else if (sb->compression & fCompLPC) {
		int n = (int) ((sb->buffer.buffer_len - 2) / 14);
		int i;
		char *cp = pkt + 8, *sp = sb->buffer.buffer_val + 2;

		pkt[1] |= VAT_AUDF_LPC4;
		pl = 8;
		for (i = 0; i < n; i++) {
			bcopy(sp, cp, 3);
			bcopy(sp + 4, cp + 3, 10);
			sp += 14;
			cp += 14;
			pl += 14;
		}

	} else {	/* Uncompressed PCMU samples */
#if (VAT_AUDF_MULAW8 != 0)
		pkt[1] |= VAT_AUDF_MULAW8;
#endif
		bcopy(sb->buffer.buffer_val, pkt + 8,
				(int) sb->buffer.buffer_len);
		pl = (int) sb->buffer.buffer_len + 8;
	}
	if (pl > 0) {
		bcopy(pkt, (char *) sb, (int) pl);
	}
	return pl;
#undef rp	
}

/*	MAKEVATID  --  Create VAT ID packet.  */

int makeVATid(char **vp, unsigned long ssrc_i)
{
	char s[256];
	int l = 0;
	char *cp, *sp = lwl_s_fullname;
    
    if (*sp == 0) {
    	sp = lwl_s_email;
    }
    
    if (*sp == 0) {
    	char hn[256];
    	
    	sp = s;
    	gethostname(hn, sizeof hn);
    	sprintf(s, "someuser@%s", hn);
    }
	if (sp != NULL) {
		cp = malloc(4 + strlen(sp) + 1);
		if (cp != NULL) {
			cp[0] = 0;
			cp[1] = 1;
			cp[2] = (char) (ssrc_i & 0xFF);
			cp[3] = (char) ((ssrc_i >> 8) & 0xFF);
			strcpy(cp + 4, sp);
			l = 4 + strlen(sp) + 1;
		}
	}
	*vp = cp;
	return l;
}

/*  MAKEVATDONE  --  Create VAT "DONE" packet.  */

int makevatdone(unsigned char *v, unsigned long ssrc_i) 
{
	v[0] = 0;
	v[1] = 2;
	v[2] = (char) (ssrc_i & 0xFF);
	v[3] = (char) ((ssrc_i >> 8) & 0xFF);
	return 4;
}
