/*
 * FILE:    codec_encoder.c
 * PROGRAM: RAT
 * AUTHOR:  I.Kouvelas + V.J.Hardman
 * 
 * $Revision: 1.1.1.1 $
 * $Date: 1998/08/15 19:16:48 $
 *
 * Copyright (c) 1995,1996 University College London
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, is permitted, for non-commercial use only, provided
 * that the following conditions are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 * 3. All advertising materials mentioning features or use of this software
 *    must display the following acknowledgement:
 *      This product includes software developed by the Computer Science
 *      Department at University College London
 * 4. Neither the name of the University nor of the Department may be used
 *    to endorse or promote products derived from this software without
 *    specific prior written permission.
 * Use of this software for commercial purposes is explicitly forbidden
 * unless prior written permission is obtained from the authors.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
 * ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 */

#include "bat_include.h"

static void
l16_encoding(sample *data, coded_unit *c)
{
  	int i;
	sample *d;

	d = (sample *)(c->data = (char *)block_alloc(SAMPLES_PER_UNIT * BYTES_PER_SAMPLE));
	c->data_len = SAMPLES_PER_UNIT * BYTES_PER_SAMPLE;
  	for (i=0; i < SAMPLES_PER_UNIT; i++) {
		*d++ = htons(*data);
		data++;
	}
}

static void
pcm_encoding(sample *data, coded_unit *c)
{
	u_char *p;
	int i;

	p = c->data = block_alloc(SAMPLES_PER_UNIT);
	c->data_len = SAMPLES_PER_UNIT;
	for (i = 0; i < SAMPLES_PER_UNIT; i++)
		*p++ = lintomulaw[(unsigned short)*data++];
}

static void
dvi_encoding(sample *data, coded_unit *c, struct adpcm_state *state)
{
	c->state = block_alloc(DVI_UNIT_SIZE + DVI_STATE_SIZE);
	memcpy(c->state, state, sizeof(struct adpcm_state));
	((struct adpcm_state*)c->state)->valprev = htons(((struct adpcm_state*)c->state)->valprev);
	c->state_len = DVI_STATE_SIZE;
	c->data = c->state + DVI_STATE_SIZE;
	c->data_len = DVI_UNIT_SIZE;
	adpcm_coder(data, c->data, SAMPLES_PER_UNIT, state);
}

static void
lpc_encoding(sample *data, coded_unit *c)
{
	c->data = block_alloc(LPCRECSIZE);
	c->data_len  = LPCRECSIZE;
	lpc_analyze(data, (lpcparams_t *)c->data);
	((lpcparams_t *)c->data)->period = htons(((lpcparams_t *)c->data)->period);
}

static void
gsm_encoding(sample *data, coded_unit *c)
{
	static gsm tx_gsm_state = NULL;

	if (tx_gsm_state == NULL)
		tx_gsm_state = gsm_create();

	/* 33 is fixed in definition of GSM standard */
	c->data = block_alloc(33 * sizeof(gsm_byte));
	c->data_len = 33;

	/* Strictly GSM takes 13 bit samples not 16
	 * Should check GSM internals sometime [oth] 
	 */
	gsm_encode(tx_gsm_state, data, (gsm_byte *)c->data); 
}

void
encoder(session_struct *sp, sample *data, int coding, coded_unit *c)
{
	c->state       = NULL;
	c->state_len   = 0;
	c->data        = NULL;
	c->data_len    = 0;
	c->coding_type = -1;

	switch (coding) {
	case L16:
		l16_encoding(data, c);
		break;
	case PCM:
		pcm_encoding(data, c);
		break;
	case DVI:
		dvi_encoding(data, c, &sp->adpcm_state);
		break;
	case LPC:
		lpc_encoding(data, c);
		break;
	case GSM:
		gsm_encoding(data, c);
		break;
	default:
		return;
	}
	c->coding_type = coding;
}

char *
get_coding_name(int coding)
{
	switch (coding) {
	case L16:
		return "16-bit linear";
	case WBS:
		return "WBS";
	case PCM:
		return "PCM (mu-law)";
	case DVI:
		return "DVI";
	case LPC:
		return "LPC";
	case GSM:
		return "GSM";
	default:
#ifdef DEBUG
		printf("get_coding_name: coding %d unknown\n", coding);
#endif
		return "Unknown";
	}
}
