#if HAVE_CRT #define _CRTDBG_MAP_ALLOC #include #include #endif //HAVE_CRT /* * Copyright (C) 2020, University of the Basque Country (UPV/EHU) * Contact for licensing options: * * The original file was part of Open Source Doubango Framework * Copyright (C) 2010-2011 Mamadou Diop. * Copyright (C) 2012 Doubango Telecom * * 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 * */ #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 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 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>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 */