doubango/tinyDAV/src/codecs/g729/tdav_codec_g729.c
c732d49e
 #if HAVE_CRT
 #define _CRTDBG_MAP_ALLOC 
 #include <stdlib.h> 
 #include <crtdbg.h>
 #endif //HAVE_CRT
 /*
74ca6d11
 * Copyright (C) 2020, University of the Basque Country (UPV/EHU)
c732d49e
 * Contact for licensing options: <licensing-mcpttclient(at)mcopenplatform(dot)com>
 *
 * The original file was part of Open Source Doubango Framework
 * Copyright (C) 2010-2011 Mamadou Diop.
 * Copyright (C) 2012 Doubango Telecom <http://doubango.org>
 *
 * 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.
 *
 */
 
 
 /**@file tdav_codec_g729.c
  * @brief G729ab codec.
  * Source from: http://www.itu.int/rec/T-REC-G.729-199610-S!AnnB/en
  *
  * @author Mamadou Diop <diopmamadou(at)doubango.org>
  *
  */
 #include "tinydav/codecs/g729/tdav_codec_g729.h"
 
 #if HAVE_G729
 
 #include "g729b/dtx.h"
 #include "g729b/octet.h"
 
 #include "tsk_string.h"
 #include "tsk_params.h"
 #include "tsk_memory.h"
 #include "tsk_debug.h"
 
 
 #if defined(_MSC_VER)
 #	pragma comment(lib, "../thirdparties/win32/lib/g729b/g729b.a")
 #endif
 
 int16_t bad_lsf;        /* bad LSF indicator   */
 
 #ifndef G729_ENABLE_VAD
 #	define G729_ENABLE_VAD		0 // FIXME: speexJB not prepared for such feature
 #endif
 
 static int16_t bin2int(int16_t no_of_bits, const int16_t *bitstream);
 static void int2bin(int16_t value, int16_t no_of_bits, int16_t *bitstream);
 
 static void unpack_G729(const uint8_t bitstream[], int16_t bits[], int len);
 static void unpack_SID(const uint8_t bitstream[], int16_t bits[]);
 
 static void pack_G729(const int16_t ituBits[], uint8_t bitstream[]);
 static void pack_SID(const int16_t ituBits[], uint8_t bitstream[]);
 
 /* ============ G.729ab Plugin interface ================= */
 
 #define tdav_codec_g729ab_set tsk_null
 
 static int tdav_codec_g729ab_open(tmedia_codec_t* self)
 {
 	tdav_codec_g729ab_t* g729a = (tdav_codec_g729ab_t*)self;
 
 	// Initialize the decoder
 	bad_lsf = 0;
 	g729a->decoder.synth = (g729a->decoder.synth_buf + M);
 
 	Init_Decod_ld8a();
 	Init_Post_Filter();
 	Init_Post_Process();
 	/* for G.729B */
 	Init_Dec_cng();
 	
 	// Initialize the encoder
 	Init_Pre_Process();
 	Init_Coder_ld8a();
 	Set_zero(g729a->encoder.prm, PRM_SIZE + 1);
 	/* for G.729B */
 	Init_Cod_cng();
 	
 
 	return 0;
 }
 
 static int tdav_codec_g729ab_close(tmedia_codec_t* self)
 {
 	tdav_codec_g729ab_t* g729a = (tdav_codec_g729ab_t*)self;	
 
 	(void)(g729a);
 	
 	/* resources will be freed by the dctor() */
 	
 	return 0;
 }
 
 static tsk_size_t tdav_codec_g729ab_encode(tmedia_codec_t* self, const void* in_data, tsk_size_t in_size, void** out_data, tsk_size_t* out_max_size)
 {	
 	tsk_size_t ex_size, out_size = 0;
 	tdav_codec_g729ab_t* g729a = (tdav_codec_g729ab_t*)self;
 	int i, frame_count = (in_size / 160);
 	
 
 	if(!self || !in_data || !in_size || !out_data || (in_size % 160)){
 		TSK_DEBUG_ERROR("Invalid parameter");
 		return 0;
 	}
 	
 	ex_size = (frame_count * 10);
 
 	// allocate new buffer if needed
 	if(*out_max_size <ex_size){
 		if(!(*out_data = tsk_realloc(*out_data, ex_size))){
 			TSK_DEBUG_ERROR("Failed to allocate new buffer");
 			*out_max_size = 0;
 			return 0;
 		}
 		*out_max_size = ex_size;
 	}
 
 	for(i=0; i<frame_count; i++){
 		extern int16_t *new_speech;
 		
 		if(g729a->encoder.frame == 32767){
 			g729a->encoder.frame = 256;
 		}
 		else{
 			g729a->encoder.frame++;
 		}
 		
 		memcpy(new_speech, &((uint8_t*)in_data)[i*L_FRAME*sizeof(int16_t)], sizeof(int16_t)*L_FRAME);
 		
 		Pre_Process(new_speech, L_FRAME);
 		Coder_ld8a(g729a->encoder.prm, g729a->encoder.frame, g729a->encoder.vad_enable);
 		prm2bits_ld8k(g729a->encoder.prm, g729a->encoder.serial);
 		
 		if(g729a->encoder.serial[1] == RATE_8000){
 			pack_G729(&g729a->encoder.serial[2], &((uint8_t*)(*out_data))[out_size]);
 			out_size += 10;
 		}
 		else if(g729a->encoder.serial[1] == RATE_SID_OCTET){
 			pack_SID(&g729a->encoder.serial[2], &((uint8_t*)(*out_data))[out_size]);
 			out_size += 2;
 		}
 		else{ // RATE_0
 			//TSK_DEBUG_INFO("G729_RATE_0 - Not transmitted");
             if (!g729a->encoder.vad_enable) {
                 // silence
                 memset(&((uint8_t*)(*out_data))[out_size], 0, 10);
                 out_size += 10;
             }
 		}
 	}
 
 	return out_size;
 }
 
 static tsk_size_t tdav_codec_g729ab_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)
 {
 	tsk_size_t out_size = 0;
 	int i, frame_count;
 	const uint8_t* data_start = (const uint8_t*)in_data;
 	const uint8_t* data_end;
 	tdav_codec_g729ab_t* g729a = (tdav_codec_g729ab_t*)self;
 
 	if(!self || !in_data || !in_size || !out_data || ((in_size % 10) && (in_size % 10 != 2))){
 		TSK_DEBUG_ERROR("Invalid parameter");
 		return 0;
 	}
 
 	data_end = (data_start + in_size);
 
 	frame_count = (in_size/10) + ((in_size % 10) ? 1 : 0);
 
 	out_size = 160*frame_count;
 
 	/* allocate new buffer if needed */
 	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;
 	}
 
 	for(i=0; i<frame_count; i++){
 		memset(g729a->decoder.synth_buf, 0, M);
 		g729a->decoder.synth = g729a->decoder.synth_buf + M;
 
 		if((data_end - data_start) == 2){
 			unpack_SID(data_start, g729a->decoder.serial);
 			data_start += 2;
 		}
 		else{
 			unpack_G729(data_start, g729a->decoder.serial, 10);
 			data_start += 10;
 		}
 
 		bits2prm_ld8k(&g729a->decoder.serial[1], g729a->decoder.parm);
 
 		/* This part was modified for version V1.3 */
 		/* for speech and SID frames, the hardware detects frame erasures
 		by checking if all bits are set to zero */
 		/* for untransmitted frames, the hardware detects frame erasures
 		by testing serial[0] */
 
 		g729a->decoder.parm[0] = 0;           /* No frame erasure */
 		if(g729a->decoder.serial[1] != 0) {
 			int j;
 			for (j=0; j < g729a->decoder.serial[1]; j++){
 				if (g729a->decoder.serial[j+2] == 0){
 					g729a->decoder.parm[0] = 1;  /* frame erased     */
 					break;
 				}
 			}
 		}
 		else if(g729a->decoder.serial[0] != SYNC_WORD){
 			g729a->decoder.parm[0] = 1;
 		}
 		if(g729a->decoder.parm[1] == 1) {
 			/* check parity and put 1 in parm[5] if parity error */
 			g729a->decoder.parm[5] = Check_Parity_Pitch(g729a->decoder.parm[4], g729a->decoder.parm[5]);
 		}
 
 		Decod_ld8a(g729a->decoder.parm, g729a->decoder.synth, g729a->decoder.Az_dec, g729a->decoder.T2, &g729a->decoder.Vad);
 		Post_Filter(g729a->decoder.synth, g729a->decoder.Az_dec, g729a->decoder.T2, g729a->decoder.Vad);        /* Post-filter */
 		Post_Process(g729a->decoder.synth, L_FRAME);
 
 		memcpy(&((uint8_t*)*out_data)[160*i], g729a->decoder.synth, 160);
 	}
 
 
 	return out_size;
 }
 
 static tsk_bool_t tdav_codec_g729ab_sdp_att_match(const tmedia_codec_t* codec, const char* att_name, const char* att_value)
 {	
 	tdav_codec_g729ab_t* g729a = (tdav_codec_g729ab_t*)codec;
 
 	if(tsk_striequals(att_name, "fmtp")){
 		tsk_params_L_t* params = tsk_null;
 		const char* val_str;
 		if((params = tsk_params_fromstring(att_value, ";", tsk_true))){
 			if((val_str = tsk_params_get_param_value(params, "annexb"))){
                 g729a->encoder.vad_enable &= tsk_strequals(val_str, "yes") ? 1 : 0;
 			}
 			TSK_OBJECT_SAFE_FREE(params);
 		}
 	}
 	return tsk_true;
 }
 
 static char* tdav_codec_g729ab_sdp_att_get(const tmedia_codec_t* codec, const char* att_name)
 {
 	tdav_codec_g729ab_t* g729a = (tdav_codec_g729ab_t*)codec;
 
 	if(tsk_striequals(att_name, "fmtp")){
 		if(g729a->encoder.vad_enable){
 			return tsk_strdup("annexb=yes");
 		}
 		else{
 			return tsk_strdup("annexb=no");
 		}
 	}
 	return tsk_null;
 }
 
 
 
 
 
 
 /* ============ Internal functions ================= */
 
 
 /**
 * Converts from bitstream (ITU bits) to int16_t value
 * @param no_of_bits number of bits to read
 * @param bitstream array containing bits
 * @retval decimal value of bit pattern
 */
 static int16_t bin2int(int16_t no_of_bits, const int16_t *bitstream)
 {
 	int16_t   value, i;
 	int16_t bit;
 	
 	value = 0;
 	for(i = 0; i < no_of_bits; i++){
 		value <<= 1;
 		bit = *bitstream++;
 		if (bit == BIT_1){
 			value += 1;
 		}
 	}
 	return(value);
 }
 
 /*----------------------------------------------------------------------------
  * int2bin convert integer to binary and write the bits bitstream array
  *----------------------------------------------------------------------------
  */
 
 /**
 * Writes int16_t value to bitstream
 * @param value decimal value to write
 * @param no_of_bits number of bits from value to write
 * @param bitstream pointer to the destination stream (ITU bits)
 */
 static void int2bin(int16_t value, int16_t no_of_bits, int16_t *bitstream)
 {
 	int16_t *pt_bitstream;
 	int16_t   i, bit;
 
 	pt_bitstream = bitstream + no_of_bits;
 
 	for (i = 0; i < no_of_bits; i++){
 		bit = value & (int16_t)0x0001;      /* get lsb */
 		if (bit == 0){
 			*--pt_bitstream = BIT_0;
 		}
 		else{
 			*--pt_bitstream = BIT_1;
 		}
 		value >>= 1;
 	}
 }
 
 /**
 * UnPack RTP bitstream as unpacked ITU stream
 * @param bitstream RTP bitstream to unpack
 * @param bits ITU bitstream used as destination (0 - BIT_0, 1 - BIT_1)
 * @param len length of the RTP bitstream
 */
 static void unpack_G729(const uint8_t bitstream[], int16_t bits[], int len)  
 {  
 	int16_t i;
 	*bits++ = SYNC_WORD;     /* bit[0], at receiver this bits indicates BFI */
 	switch(len){
 		case 10:
 			*bits++ = SIZE_WORD;
 			break;
 		case 8: // RATE_6400
 		case 15: //RATE_11800
 		default:
 			TSK_DEBUG_ERROR("%d is an invalid lenght value", len);
 			return;
 	} 
 
 	for(i=0; i<len; i++){
 		int2bin(bitstream[i], 8, &bits[i*8]);
 	}
 }
 
 /**
 * UnPack RTP bitstream containing SID frame as unpacked ITU stream
 * @param bitstream RTP bitstream to unpack
 * @param bits ITU bitstream used as destination (0 - BIT_0, 1 - BIT_1)
 */
 static void unpack_SID(const uint8_t bitstream[], int16_t bits[])
 {  
    *bits++ = SYNC_WORD; 
    *bits++ = RATE_SID_OCTET;
    int2bin((int16_t)bitstream[0], 8, &bits[0]);
    int2bin((int16_t)bitstream[1], 8, &bits[8]);
 }
 
 /**
 * Pack ITU bits into RTP stream
 * @param ituBits ITU stream to pack (80 shorts)
 * @param bitstream RTP bitstream (80 bits, 5 shorts, 10 bytes)
 */
 static void pack_G729(const int16_t ituBits[], uint8_t bitstream[])
 {  
     int16_t word16, i;
     for(i=0; i<5; i++){
         word16 = bin2int(16, (int16_t*)&ituBits[i*16]);
         bitstream[i*2] = word16>>8, bitstream[(i*2)+1] = (word16 & 0xFF);
     }
 }
 
 /**
 * Pack ITU bits containing SID frame as RTP stream
 * @param ituBits ITU stream to pack
 * @param bitstream RTP bitstream (15 bits, 1 short, 2 bytes)
 */
 static void pack_SID(const int16_t ituBits[], uint8_t bitstream[])
 {  
     int16_t word16 = bin2int(16, ituBits);
     bitstream[0] = word16>>8, bitstream[1] = (word16 & 0xFF);
 }  
 
 
 //
 //	g729ab Plugin definition
 //
 
 /* constructor */
 static tsk_object_t* tdav_codec_g729ab_ctor(tsk_object_t * self, va_list * app)
 {
 	tdav_codec_g729ab_t *g729a = self;
 	if(g729a){
 		/* init base: called by tmedia_codec_create() */
 		/* init self */
 		g729a->encoder.vad_enable = G729_ENABLE_VAD; // AnnexB
 	}
 	return self;
 }
 /* destructor */
 static tsk_object_t* tdav_codec_g729ab_dtor(tsk_object_t * self)
 { 
 	tdav_codec_g729ab_t *g729a = self;
 	if(g729a){
 		/* deinit base */
 		tmedia_codec_audio_deinit(g729a);
 		/* deinit self */
 		
 	}
 
 	return self;
 }
 /* object definition */
 static const tsk_object_def_t tdav_codec_g729ab_def_s = 
 {
 	sizeof(tdav_codec_g729ab_t),
 	tdav_codec_g729ab_ctor, 
 	tdav_codec_g729ab_dtor,
 	tmedia_codec_cmp, 
 };
 /* plugin definition*/
 static const tmedia_codec_plugin_def_t tdav_codec_g729ab_plugin_def_s = 
 {
 	&tdav_codec_g729ab_def_s,
 
 	tmedia_audio,
 	tmedia_codec_id_g729ab,
 	"g729",
 	"g729ab Codec (libg729)",
 	TMEDIA_CODEC_FORMAT_G729,
 	tsk_false,
 	8000, // rate
 	
 	{ /* audio */
 		1, // channels
 		0 // ptime @deprecated
 	},
 
 	/* video */
 	{0},
 
 	tdav_codec_g729ab_set,
 	tdav_codec_g729ab_open,
 	tdav_codec_g729ab_close,
 	tdav_codec_g729ab_encode,
 	tdav_codec_g729ab_decode,
 	tdav_codec_g729ab_sdp_att_match,
 	tdav_codec_g729ab_sdp_att_get
 };
 const tmedia_codec_plugin_def_t *tdav_codec_g729ab_plugin_def_t = &tdav_codec_g729ab_plugin_def_s;
 
 #endif /* HAVE_G729 */