// ****************** Copyright (c) 2013 by Gigaset Communications GmbH ******
// Filename : tdav_codec_l16_256.c
// Owner    : Mohammed Hasan [STC]
//-------------------------------------------------------------------------
// Defintion : L16-256 codec plugin uses uncompressed 16-bit linear PCM coding sampled at
// 16 kHz and having a bit rate of 256 kbit/s. The L16-256 coder shall use 16-bit
// signed representation with 65535 equally divided steps between minimum and maximum
// signal level from -32768 to 32767.
//-------------------------------------------------------------------------
// 02-08-2013, Gigaset Communications GmbH
// Added L16-256 codec plugin to Doubango Framework
//*************************************************************************

/*
* This file is part of Open Source Doubango Framework.
*
* DOUBANGO is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* DOUBANGO 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with DOUBANGO.
*
*/

#include "tinydav/codecs/l16_256/tdav_codec_l16_256.h"

#include "tsk_memory.h"
#include "tsk_debug.h"
#include <android/log.h>
#include <netinet/in.h>
#include <stdio.h>
#include <stdlib.h>
/* ============ L16_256 Plugin interface ================= */

#define tdav_codec_l16_256_open tsk_null
#define tdav_codec_l16_256_close tsk_null
#define tdav_codec_l16_256_sdp_att_get tsk_null

static tsk_size_t tdav_codec_l16_256_encode(tmedia_codec_t* self, const void* in_data, tsk_size_t in_size, void** out_data, tsk_size_t* out_max_size)
{
    __android_log_print("STC", "l16_256", "L16: encode in_size %d, out_max_size %d", in_size, *out_max_size);
	tsk_size_t i;
	int16_t* pout_data;
	int16_t* pin_data;
        int16_t* pin_data_end;
	tsk_size_t out_size, size;

	if(!self || !in_data || !in_size || !out_data){
		TSK_DEBUG_ERROR("Invalid parameter");
		return 0;
	}

	out_size = in_size;

	if(*out_max_size <out_size){
		if(!(*out_data = tsk_realloc(*out_data, out_size))){
			TSK_DEBUG_ERROR("Failed to allocate new buffer");
			*out_max_size = 0;
			return 0;
		}
		*out_max_size = out_size;
	}

	pout_data = (int16_t*)*out_data;
	pin_data = (int16_t*)in_data;
        size = in_size / sizeof(int16_t);
        pin_data_end = pin_data + size;

        while (pin_data != pin_data_end) {
            *pout_data++ = htons(*pin_data++);
        }

	return out_size;
}

static tsk_size_t tdav_codec_l16_256_decode(tmedia_codec_t* self, const void* in_data, tsk_size_t in_size, void** out_data, tsk_size_t* out_max_size, const tsk_object_t* proto_hdr)
{
    __android_log_print("STC", "l16_256", "L16 :decode in_size %d, out_max_size %d", in_size, *out_max_size);
	tsk_size_t i;
        int16_t* pout_data;
        int16_t* pin_data;
        int16_t* pin_data_end;
	tsk_size_t out_size, size;
	if(!self || !in_data || !in_size || !out_data){
		TSK_DEBUG_ERROR("Invalid parameter");
		return 0;
	}

	out_size = in_size;

	/* allocate new buffer */
	if(*out_max_size<out_size){
                __android_log_print("STC", "l16_256", "L16 :decode allocating buf");
		if(!(*out_data = tsk_realloc(*out_data, out_size))){
			TSK_DEBUG_ERROR("Failed to allocate new buffer");
			*out_max_size = 0;
			return 0;
		}
		*out_max_size = out_size;
	}
        // L16 Codec
        pout_data = (int16_t*)*out_data;
        pin_data = (int16_t*)in_data;
        size = in_size / sizeof(int16_t);
        pin_data_end = pin_data + size;

        while (pin_data != pin_data_end) {
            *pout_data++ = ntohs(*pin_data++);
        }

	return out_size;
}

static tsk_bool_t tdav_codec_l16_256_sdp_att_match(const tmedia_codec_t* codec, const char* att_name, const char* att_value)
{	/* always match */
	return tsk_true;
}

//
//	L16-256 Plugin definition
//

/* constructor */
static tsk_object_t* tdav_codec_l16_256_ctor(tsk_object_t * self, va_list * app)
{
	tdav_codec_l16_256_t *l16_256 = self;
	if(l16_256){
		/* init base: called by tmedia_codec_create() */
		/* init self */
	}
	return self;
}
/* destructor */
static tsk_object_t* tdav_codec_l16_256_dtor(tsk_object_t * self)
{ 
	tdav_codec_l16_256_t *l16_256 = self;
	if(l16_256){
		/* deinit base */
		tmedia_codec_audio_deinit(l16_256);
		/* deinit self */
	}

	return self;
}
/* object definition */
static const tsk_object_def_t tdav_codec_l16_256_def_s =
{
	sizeof(tdav_codec_l16_256_t),
	tdav_codec_l16_256_ctor,
	tdav_codec_l16_256_dtor,
	tmedia_codec_cmp,
};
/* plugin definition*/
static const tmedia_codec_plugin_def_t tdav_codec_l16_256_plugin_def_s =
{
	&tdav_codec_l16_256_def_s,

	tmedia_audio,
	tmedia_codec_id_l16_256,
	"L16-256",
	"L16-256 codec",
	TMEDIA_CODEC_FORMAT_L16_256,
	tsk_false,
	16000, // rate

	{ /* audio */
		1, // channels
		20 // ptime
	},

	/* video */
	{0},

	tsk_null, // set()
	tdav_codec_l16_256_open,
	tdav_codec_l16_256_close,
	tdav_codec_l16_256_encode,
	tdav_codec_l16_256_decode,
	tdav_codec_l16_256_sdp_att_match,
	tdav_codec_l16_256_sdp_att_get
};
const tmedia_codec_plugin_def_t *tdav_codec_l16_256_plugin_def_t = &tdav_codec_l16_256_plugin_def_s;
