/*
 *******************************************************************************
 *  Copyright (c) 2010-2022 VATICS(KNERON) Inc. All rights reserved.
 *
 *  +-----------------------------------------------------------------+
 *  | THIS SOFTWARE IS FURNISHED UNDER A LICENSE AND MAY ONLY BE USED |
 *  | AND COPIED IN ACCORDANCE WITH THE TERMS AND CONDITIONS OF SUCH  |
 *  | A LICENSE AND WITH THE INCLUSION OF THE THIS COPY RIGHT NOTICE. |
 *  | THIS SOFTWARE OR ANY OTHER COPIES OF THIS SOFTWARE MAY NOT BE   |
 *  | PROVIDED OR OTHERWISE MADE AVAILABLE TO ANY OTHER PERSON. THE   |
 *  | OWNERSHIP AND TITLE OF THIS SOFTWARE IS NOT TRANSFERRED.        |
 *  |                                                                 |
 *  | THE INFORMATION IN THIS SOFTWARE IS SUBJECT TO CHANGE WITHOUT   |
 *  | ANY PRIOR NOTICE AND SHOULD NOT BE CONSTRUED AS A COMMITMENT BY |
 *  | VATICS(KNERON) INC.                                             |
 *  +-----------------------------------------------------------------+
 *
 *******************************************************************************
 */
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <audio_encoder.h>
#ifdef HAS_HW_AAC_ENC
#include <vmf/audio_aac4enc.h>
#else
#include <fdk-aac/aacenc_lib.h>
#endif


#ifdef GAMR_SUPPORT
#include <opencore/interf_enc.h> //! For GAMR encoder.
#endif

#include <g711/G711SEnc.h>
#include <g726/G726SEnc.h>


typedef int (*Enc_Release) (void** handle);
typedef int (*Enc_EncodeOneFrame) (void* handle, ATK_AUDIOENC_ONEFRAME_CONF_T* conf);
typedef int (*Enc_GetConf) (void* handle, void *conf_buf);

struct ATK_AUDIOENC_HANDLE_T
{

#ifdef HAS_HW_AAC_ENC
	VMF_AAC4ENC_HANDLE_T* handle_; 
#else
	HANDLE_AACENCODER handle_; /**< The handle of audio encoders (FDK). */
#endif

	unsigned int aac_output_channels_;

	int g711_mode_;
	unsigned int gamr_mode_;
	unsigned int step_offset_;

	Enc_Release release_func; /**< The callback function of one encoder for release resource. */
	Enc_EncodeOneFrame enc_func; /**< The callback function of one encoder for encode data. */
	Enc_GetConf getconf_func; /**< The callback function of one encoder for get configuration. */

	unsigned int sample_rate_; /**< Sample rate. */
	unsigned int channels_; /**< The number of channels. */
	unsigned int bit_rate_; /**< The number of channels. */
	unsigned int is_interleaved_; /**< the input data is interleaved or not. */

	unsigned int period_size_in_frames; /**< Distance between interrupts is # frames. */
	void* pcmbuffer;
};



#ifdef HAS_HW_AAC_ENC
/**
 * @brief Function to initialize AAC4 audio encoder.
 *
 * @param[in] aac4enc_handle The handle of AAC4 audio encoder.
 * @param[in] config Initial configuration for audio encoder.
 * @return negative: failed, otherwise: success.
 */
static int ATK_AAC4Enc_Init(ATK_AUDIOENC_HANDLE_T *aac4enc_handle, const ATK_AAC4ENC_CONFIG_T *config)
{
	VMF_AAC4ENC_INITOPT_T tVmfAac4encInit;
	memset(&tVmfAac4encInit, 0, sizeof(VMF_AAC4ENC_INITOPT_T));
	tVmfAac4encInit.dwBitRate = config->dwBitRate;
	tVmfAac4encInit.dwSampleRate = aac4enc_handle->sample_rate_ = config->dwSampleRate;
	tVmfAac4encInit.dwADTS = config->dwAdts; // 0: Raw, 1: ADTS or 2: ADIF
	if( (aac4enc_handle->channels_ == 2) && (aac4enc_handle->is_interleaved_) )
	{
		// stereo
		tVmfAac4encInit.dwChannel = 2;
	}
	else if( (aac4enc_handle->channels_ == 1) || (aac4enc_handle->is_interleaved_ == 0) )
	{
		// mono
		tVmfAac4encInit.dwChannel = 1;
	}
	else
	{
		fprintf(stderr, "[%s, %s]: Unsupport channel number for AAC4 encoder.\n", __FILE__, __func__);
		return -1;
	}

	switch(config->dwStereoMode)
	{
		case 0: // stereo
		case 1: // joint stereo
			if (tVmfAac4encInit.dwChannel == 1)
			{
				fprintf(stderr, "[%s, %s]: The output channels of AAC is large than the input channels.\n", __FILE__, __func__);
				return -1;
			}

			aac4enc_handle->aac_output_channels_ = 2;
			tVmfAac4encInit.dwStereoMode = config->dwStereoMode;
			break;
		case 3: // mono
			aac4enc_handle->aac_output_channels_ = 1;
			tVmfAac4encInit.dwStereoMode = config->dwStereoMode;
			break;
		default:
			fprintf(stderr, "[%s, %s]: Unsupport stereo mode for AAC4 encoder.\n", __FILE__, __func__);
			return -1;
	}

	aac4enc_handle->handle_ = VMF_AAC4ENC_Init(&tVmfAac4encInit);
	if (!aac4enc_handle->handle_) {
		fprintf(stderr, "[%s, %s]: AAC4 init failed.\n", __FILE__, __func__);
		return -1;
	}

	return 0;
}

/**
 * @brief Function to encode one audio frame.
 *
 * @param[in] handle The handle of audio encoder (tk).
 * @param[in] pbyInBuf The input data buffer,
 * @param[out] pbyOutBuf The output encoded data buffer.
 * @param[in] dwOutBufSize The size of output data buffer.
 * @return negative: failed, otherwise: The size of encoded data (bytes).
 */
static int ATK_AAC4Enc_EncodeOneFrame(ATK_AUDIOENC_HANDLE_T *handle, ATK_AUDIOENC_ONEFRAME_CONF_T* conf)
{	
	VMF_AAC4ENC_ONEFRAME_CONF_T tVmfAac4OneFrameConf;
	VMF_AAC4ENC_HANDLE_T *ptAac4encHandle = handle->handle_;
	memset(&tVmfAac4OneFrameConf, 0, sizeof(VMF_AAC4ENC_ONEFRAME_CONF_T));
	tVmfAac4OneFrameConf.pbyInBuf = conf->pbyInBuf;
	tVmfAac4OneFrameConf.pbyOutBuf = conf->pbyOutBuf;
	tVmfAac4OneFrameConf.dwOutBufSize = conf->dwOutBufSize;
	if (0 != VMF_AAC4ENC_SetOptions(ptAac4encHandle, &tVmfAac4OneFrameConf))
	{
		fprintf(stderr, "[%s, %s]: Unable to set options for encoder.\n", __FILE__, __func__);
		return -1;
	}

	if (0 != VMF_AAC4ENC_PorcessOneFrame(ptAac4encHandle))
	{
		fprintf(stderr, "[%s, %s]: AAC4Enc_OneFrame failed.\n", __FILE__, __func__);
		return -1;
	}

	return VMF_AAC4ENC_GetBitStreamSize(ptAac4encHandle);
}

/**
 * @brief Function to get information about the encoder.
 *
 * @param[in] handle The handle of audio encoder (tk).
 * @param[out] conf_buf The buffer which to store the information.
 * @return negative: failed, otherwise: success.
 */
static int ATK_AAC4Enc_GetConf(ATK_AUDIOENC_HANDLE_T *handle, void *conf_buf)
{
	//---header
	//dwDataType (4 bytes)
	//payload len (4 bytes)

	//--paylaod
	//codec_type (4 bytes)
	//sameple rate (4 bytes)
	//channel num (4 bytes)
	//dwProfileLevel (4 bytes)
	//aac header size (4 bytes)
	//aac header data

	unsigned int *values = (unsigned int*) conf_buf;
	uint32_t dwSpecConfSize = 0;
	if (0 != VMF_AAC4ENC_GetConf(handle->handle_, conf_buf, &dwSpecConfSize, values))
	{
		return -1;
	}

	values[0] = FOURCC_CONF;
	values[1] = 20 + dwSpecConfSize;
	values[2] = FOURCC_AAC4;
	values[3] = handle->sample_rate_;
	values[4] = handle->aac_output_channels_;
	values[6] = dwSpecConfSize;

	return 0;
}


#else

/**
 * @brief Function to initialize AAC4 audio encoder.
 *
 * @param[in] aac4enc_handle The handle of AAC4 audio encoder.
 * @param[in] config Initial configuration for audio encoder.
 * @return negative: failed, otherwise: success.
 */
static int ATK_AAC4Enc_Init(ATK_AUDIOENC_HANDLE_T *aac4enc_handle, const ATK_AAC4ENC_CONFIG_T *config)
{

	int format = 0;
	unsigned int AOTmode = 0;

	if (config->dwAdts == 1)
		format = 2;
	else if(config->dwAdts == 2)
		format = 1;
	
	if (config->dwELDMode == 1 ) 
		AOTmode = 39;
	else
		AOTmode = 2;

	switch(config->dwStereoMode)
	{
		case 0: // stereo
		case 1: // joint stereo
			aac4enc_handle->aac_output_channels_ = 2;
			break;
		case 3: // mono
			aac4enc_handle->aac_output_channels_ = 1;
			break;
		default:
			fprintf(stderr, "[%s, %s]: Unsupport stereo mode for AAC4 encoder.\n", __FILE__, __func__);
			return -1;
	}

	// ELD mode only support RAW
	if (config->dwELDMode == 1) {
		printf("check ELD setting\n");
		if( format != 0) {
			fprintf(stderr, "[%s, %s]: Error, ELD mode must use RAW\n", __FILE__, __func__); 		
			return -1;
		}
		if(config->dwSampleRate <= 8000 || config->dwSampleRate > 48000) {
			fprintf(stderr, "[%s, %s]: Error, ELD mode support 16000-48000 sample rate\n", __FILE__, __func__); 		
			return -1;
		}
	} else { //LC mode only suppor ADTS/ADIF
		if( format == 0) {
			fprintf(stderr, "[%s, %s]: Error, LC mode must use ADTS/ADIF\n", __FILE__, __func__); 		
			return -1;
		}
	}


	if (aacEncOpen(&(aac4enc_handle->handle_), 0, aac4enc_handle->channels_) != AACENC_OK) {
		fprintf(stderr, "[%s, %s]: Unable to open encoder.\n", __FILE__, __func__);
		return -1;
	}
	if (aacEncoder_SetParam(aac4enc_handle->handle_, AACENC_AOT, AOTmode ) != AACENC_OK) {
		fprintf(stderr, "Unable to set the AOT\n");		
		return -1;	
	}
	if (aacEncoder_SetParam(aac4enc_handle->handle_, AACENC_SAMPLERATE, config->dwSampleRate) != AACENC_OK) {
		fprintf(stderr, "[%s, %s]: Unable to set the sample rate.\n", __FILE__, __func__);
		return -1;
	}
	if (aacEncoder_SetParam(aac4enc_handle->handle_, AACENC_CHANNELMODE, aac4enc_handle->channels_) != AACENC_OK) {
		fprintf(stderr, "[%s, %s]: Unable to set the channel mode.\n", __FILE__, __func__);
		return -1;
	}
	if (aacEncoder_SetParam(aac4enc_handle->handle_, AACENC_CHANNELORDER, 1) != AACENC_OK) {
		fprintf(stderr, "[%s, %s]: Unable to set the wav channel order.\n", __FILE__, __func__);
		return -1;
	}
	if (aacEncoder_SetParam(aac4enc_handle->handle_, AACENC_BITRATE, config->dwBitRate) != AACENC_OK) {
		fprintf(stderr, "[%s, %s]: Unable to set the bitrate.\n", __FILE__, __func__); //now bitrate is VBR in low level, so this not work. 
		return -1;
	}
	if (aacEncoder_SetParam(aac4enc_handle->handle_, AACENC_TRANSMUX, format) != AACENC_OK) {
		fprintf(stderr, "[%s, %s]: Unable to set the ADTS transmux.\n", __FILE__, __func__); //now bitrate is VBR in low level, so this not work. 		
		return -1;
	}
	if (aacEncEncode(aac4enc_handle->handle_, NULL, NULL, NULL, NULL) != AACENC_OK) {
		fprintf(stderr, "[%s, %s]: Unable to initialize the encoder.\n", __FILE__, __func__); 
		return -1;
	}
	aac4enc_handle->sample_rate_ = config->dwSampleRate;
	
	return 0;
}

/**
 * @brief Function to release encoder.
 *
 * @param[in] ptHandle The handle of AAC encoder.
 * @return Success: 0  Fail: negative integer.
 */
static int ATK_AACEnc_Release(void** handle)
{

	if (aacEncClose((HANDLE_AACENCODER *)handle) != 0) {
		fprintf(stderr, "[%s, %s]: Release the encoder fail.\n", __FILE__, __func__);	
		return -1;
	}
	*handle = NULL;
	return 0;

}

/**
 * @brief Function to get information about the encoder.
 *
 * @param[in] handle The handle of audio encoder (tk).
 * @param[out] conf_buf The buffer which to store the information.
 * @return negative: failed, otherwise: success.
 */
static int ATK_AAC4Enc_GetConf(ATK_AUDIOENC_HANDLE_T *handle, void *conf_buf)
{
	//---header
	//dwDataType (4 bytes)
	//payload len (4 bytes)

	//--paylaod
	//codec_type (4 bytes)
	//sameple rate (4 bytes)
	//channel num (4 bytes)
	//dwProfileLevel (4 bytes)
	//aac header size (4 bytes)
	//aac header data

	AACENC_InfoStruct info;
	memset(&info, 0, sizeof(AACENC_InfoStruct
));
	
	unsigned int *values = (unsigned int*) conf_buf;

	if (aacEncInfo(handle->handle_, &info) != AACENC_OK) {
		fprintf(stderr, "[%s, %s]: Unable to get the encoder info.\n", __FILE__, __func__);
		return -1;
	}
	handle->period_size_in_frames = info.frameLength;
	
	values[0] = FOURCC_CONF;
	values[1] = 20 + info.confSize;
	values[2] = FOURCC_AAC4;
	values[3] = handle->sample_rate_;
	values[4] = handle->aac_output_channels_;
	values[6] = info.confSize;
	memcpy(&values[7], info.confBuf, info.confSize);

	
	return 0;
}

/**
 * @brief Function to encode one audio frame.
 *
 * @param[in] handle The handle of audio encoder (tk).
 * @param[in] pbyInBuf The input data buffer,
 * @param[out] pbyOutBuf The output encoded data buffer.
 * @param[in] dwOutBufSize The size of output data buffer.
 * @return negative: failed, otherwise: The size of encoded data (bytes).
 */
static int ATK_AAC4Enc_EncodeOneFrame(ATK_AUDIOENC_HANDLE_T *handle, ATK_AUDIOENC_ONEFRAME_CONF_T* conf)
{
	
	int input_size = 2*handle->channels_*handle->period_size_in_frames; //16bits * channel * frames (bytes)

	AACENC_BufDesc in_buf = { 0 }, out_buf = { 0 };
	AACENC_InArgs in_args = { 0 };
	AACENC_OutArgs out_args = { 0 };
	int in_identifier = IN_AUDIO_DATA;
	int in_elem_size;
	int out_identifier = OUT_BITSTREAM_DATA;
	int out_size;//, out_elem_size;
	void *in_ptr, *out_ptr;
	AACENC_ERROR err;
	in_ptr = conf->pbyInBuf;
	in_elem_size = 16/8; //16 bits = 2bytes fixed

	in_args.numInSamples = input_size/2;
	in_buf.numBufs = 1;
	in_buf.bufs = &in_ptr;
	in_buf.bufferIdentifiers = &in_identifier;
	in_buf.bufSizes = &input_size;
	in_buf.bufElSizes = &in_elem_size;

	out_ptr = conf->pbyOutBuf;
	out_size = conf->dwOutBufSize;
	out_buf.numBufs = 1;
	out_buf.bufs = &out_ptr;
	out_buf.bufferIdentifiers = &out_identifier;
	out_buf.bufSizes = &out_size;
	out_buf.bufElSizes = (signed int *)&handle->aac_output_channels_;

	if ((err = aacEncEncode(handle->handle_, &in_buf, &out_buf, &in_args, &out_args)) != AACENC_OK) {
		fprintf(stderr, "[%s, %s]: Encoding failed err code 0x%x.\n", __FILE__, __func__,err);
		return -1;
	}

	return out_args.numOutBytes;

}
#endif


#ifdef GAMR_SUPPORT
// ==========================================================================
/**
 * @brief Function to initialize GAMR audio encoder.
 *
 * @param[in] aac4enc_handle The handle of GAMR audio encoder.
 * @param[in] config Initial configuration for audio encoder.
 * @return negative: failed, otherwise: success.
 */
static int ATK_GAMREnc_Init(ATK_AUDIOENC_HANDLE_T *gamrenc_handle, const ATK_GAMRENC_CONFIG_T *config)
{
	gamrenc_handle->sample_rate_ = config->dwSampleRate;
	gamrenc_handle->bit_rate_ = config->dwBitRate;
	gamrenc_handle->gamr_mode_ = config->dwMode;
	gamrenc_handle->handle_ = Encoder_Interface_init(0);//dtx
	return (gamrenc_handle->handle_ != NULL) ? 0 : -1;
}

/**
 * @brief Function to encode one audio frame.
 *
 * @param[in] handle The handle of audio encoder (tk).
 * @param[in] in_buf The input data buffer,
 * @param[out] out_buf The output encoded data buffer.
 * @param[in] out_buf_size The size of output data buffer.
 * @return negative: failed, otherwise: The size of encoded data (bytes).
 */
static int ATK_GAMREnc_EncodeOneFrame(ATK_AUDIOENC_HANDLE_T *handle, ATK_AUDIOENC_ONEFRAME_CONF_T* conf)
{
	size_t outputSize = 0;
	short* pcmbuffer = (short*)handle->pcmbuffer;
	short* tmpIn = (short*)conf->pbyInBuf;
	for (unsigned int i=0; i < handle->period_size_in_frames; i++)
	{
		pcmbuffer[i] = tmpIn[i << 1];
	}

	outputSize = Encoder_Interface_Encode(handle->handle_, handle->gamr_mode_, pcmbuffer, conf->pbyOutBuf, 0);
	return outputSize;
}

/**
 * @brief Function to get information about the encoder.
 *
 * @param[in] handle The handle of audio encoder (tk).
 * @param[out] conf_buf The buffer which to store the information.
 * @return negative: failed, otherwise: success.
 */
static int ATK_GAMREnc_GetConf(ATK_AUDIOENC_HANDLE_T *handle, void *conf_buf)
{
	//---header
	//dwDataType (4 bytes)
	//payload len (4 bytes)

	//--paylaod
	//codec_type (4 bytes)
	//sample rate (4 bytes)

	unsigned int *values = (unsigned int*) conf_buf;
	values[0] = FOURCC_CONF;
	values[1] = 8;
	values[2] = FOURCC_GAMR;
	values[3] = handle->sample_rate_;

	return 0;
}

static int ATK_GAMREnc_Release(void** handle)
{
	Encoder_Interface_exit(*handle);
	*handle = NULL;

	return 0;
}
#endif


static int ATK_G711Enc_ALaw_Encode(ATK_AUDIOENC_HANDLE_T* handle, ATK_AUDIOENC_ONEFRAME_CONF_T* conf)
{
	G711_ALaw_Encode((short*)conf->pbyInBuf, conf->pbyOutBuf, handle->period_size_in_frames, handle->step_offset_);

	return handle->period_size_in_frames;
}

static int ATK_G711Enc_ULaw_Encode(ATK_AUDIOENC_HANDLE_T* handle, ATK_AUDIOENC_ONEFRAME_CONF_T* conf)
{
	G711_ULaw_Encode((short*)conf->pbyInBuf, conf->pbyOutBuf, handle->period_size_in_frames, handle->step_offset_);

	return handle->period_size_in_frames;
}

/**
 * @brief Function to get information about the encoder.
 *
 * @param[in] handle The handle of audio encoder (tk).
 * @param[out] conf_buf The buffer which to store the information.
 * @return negative: failed, otherwise: success.
 */
static int ATK_G711Enc_GetConf(ATK_AUDIOENC_HANDLE_T *handle, void *conf_buf)
{
	//---header
	//dwDataType (4 bytes)
	//payload len (4 bytes)

	//--paylaod
	//codec_type (4 bytes)
	//compression_format [ulaw or alaw] (4 bytes)

	unsigned int *values = (unsigned int*) conf_buf;
	values[0] = FOURCC_CONF;
	values[1] = 8;
	values[2] = FOURCC_G711;
	values[3] = (handle->g711_mode_ == 0) ? FOURCC_ULAW : FOURCC_ALAW;

	return 0;
}

// ==========================================================================
/**
 * @brief Function to initialize G726 audio encoder.
 *
 * @param[in] g726enc_handle The handle of G726 audio encoder.
 * @param[in] config Initial configuration for audio encoder.
 * @return negative: failed, otherwise: success.
 */
static int ATK_G726Enc_Init(ATK_AUDIOENC_HANDLE_T *g726enc_handle, const ATK_G726ENC_CONFIG_T *config)
{
	g726enc_handle->bit_rate_ = config->dwBitRate;
	g726enc_handle->handle_ = (void *)g726_enc_init(g726enc_handle->bit_rate_);

	return (g726enc_handle->handle_ != NULL)? 0:-1;
}

static int ATK_G726Enc_Release(void** handle)
{
	g726_enc_release((g726_enc_handle_t*)(*handle));
	*handle = NULL;

	return 0;
}

/**
 * @brief Function to encode one audio frame.
 *
 * @param[in] handle The handle of audio encoder (tk).
 * @param[in] in_buf The input data buffer,
 * @param[out] out_buf The output encoded data buffer.
 * @param[in] out_buf_size The size of output data buffer.
 * @return negative: failed, otherwise: The size of encoded data (bytes).
 */
static int ATK_G726Enc_EncodeOneFrame(ATK_AUDIOENC_HANDLE_T *handle, ATK_AUDIOENC_ONEFRAME_CONF_T* conf)
{
	return g726_encode_frame((g726_enc_handle_t*)handle->handle_, conf->pbyOutBuf, (const int16_t*) conf->pbyInBuf, handle->period_size_in_frames, handle->step_offset_);
}

/**
 * @brief Function to get information about the encoder.
 *
 * @param[in] handle The handle of audio encoder (tk).
 * @param[out] conf_buf The buffer which to store the information.
 * @return negative: failed, otherwise: success.
 */
static int ATK_G726Enc_GetConf(ATK_AUDIOENC_HANDLE_T *handle, void *conf_buf)
{
	//---header
	//dwDataType (4 bytes)
	//payload len (4 bytes)

	//--paylaod
	//codec_type (4 bytes)
	//dwCodewordBits (4 bytes)

	unsigned int *values = (unsigned int*) conf_buf;

	values[0] = FOURCC_CONF;
	values[1] = 8;
	values[2] = FOURCC_G726;
	values[3] = handle->bit_rate_ / 8000;

	return 0;
}

// ==========================================================================
ATK_AUDIOENC_HANDLE_T* ATK_AudioEnc_Init(const ATK_AUDIOENC_INITOPT_T *ptInitOpt, const void *pConfig)
{
	ATK_AUDIOENC_HANDLE_T *handle = NULL;
	if(pConfig == NULL || ptInitOpt == NULL)
	{
		return NULL;
	}

	handle = (ATK_AUDIOENC_HANDLE_T*) calloc(1, sizeof(ATK_AUDIOENC_HANDLE_T));
	if(handle == NULL)
	{
		return NULL;
	}

	handle->channels_ = ptInitOpt->dwChannels;
	handle->is_interleaved_ = (ptInitOpt->bIsInterleaved > 0)? 1:0;
	handle->period_size_in_frames = ptInitOpt->dwPeriodSizeInFrames;
	int ret = -1;
	switch(ptInitOpt->eType)
	{
		case kAAC4:
#ifdef HAS_HW_AAC_ENC
			handle->release_func = (Enc_Release) VMF_AAC4ENC_Release;
#else
			handle->release_func = (Enc_Release) ATK_AACEnc_Release;
#endif
			handle->enc_func = (Enc_EncodeOneFrame) ATK_AAC4Enc_EncodeOneFrame;
			handle->getconf_func = (Enc_GetConf) ATK_AAC4Enc_GetConf;
			ret = ATK_AAC4Enc_Init(handle, pConfig);
			break;
		case kG711:
			{
				ATK_G711ENC_CONFIG_T* g711_config = (ATK_G711ENC_CONFIG_T*) pConfig;
				if (g711_config->iCompressionMode == 0)
				{
					handle->enc_func = (Enc_EncodeOneFrame) ATK_G711Enc_ULaw_Encode;
					handle->g711_mode_ = 0;
				}
				else
				{
					handle->enc_func = (Enc_EncodeOneFrame) ATK_G711Enc_ALaw_Encode;
					handle->g711_mode_ = 1;
				}
				handle->getconf_func = (Enc_GetConf) ATK_G711Enc_GetConf;
				ret = 0;
			}
			break;
		case kG726:
			handle->release_func = (Enc_Release)ATK_G726Enc_Release;
			handle->enc_func = (Enc_EncodeOneFrame) ATK_G726Enc_EncodeOneFrame;
			handle->getconf_func = (Enc_GetConf) ATK_G726Enc_GetConf;
			ret = ATK_G726Enc_Init(handle, pConfig);
			break;
		case kGAMR:
#ifdef GAMR_SUPPORT
			handle->release_func = (Enc_Release) ATK_GAMREnc_Release;//GAMREnc_Release;
			handle->enc_func = (Enc_EncodeOneFrame) ATK_GAMREnc_EncodeOneFrame;
			handle->getconf_func = (Enc_GetConf) ATK_GAMREnc_GetConf;
			handle->pcmbuffer = malloc(handle->period_size_in_frames * sizeof(short));

			if(handle->pcmbuffer != NULL)
			{
				ret = ATK_GAMREnc_Init(handle, pConfig);
				if(ret < 0)
				{
					free(handle->pcmbuffer);
					handle->pcmbuffer = NULL;
				}
			}
			else
			{
				fprintf(stderr, "[%s, %s]: Unable to allocate buffer.\n", __FILE__, __func__);
			}
#endif
			break;
		default:
			break;
	}

	if(ret < 0)
	{
		free(handle);
		return NULL;
	}
	handle->step_offset_ = ((handle->is_interleaved_) && (handle->channels_ > 1)) ? (handle->channels_) : 1;

	return handle;
}

int ATK_AudioEnc_Release(ATK_AUDIOENC_HANDLE_T *ptHandle)
{
	if(!ptHandle)
		return -1;

	if(ptHandle->handle_)
	{
		void* phandle = (void *)ptHandle->handle_;
#ifdef HAS_HW_AAC_ENC
	if(ptHandle->release_func && (ptHandle->release_func(&(phandle)) != 0))
		{
#else
	if(ptHandle->release_func && (ptHandle->release_func(&(phandle)) != 0))
		{
#endif 		
		
			fprintf(stderr, "[%s, %s]: Release encoder failed.\n", __FILE__, __func__);
		}
		ptHandle->handle_ = NULL;
	}

	if(ptHandle->pcmbuffer)
	{
		free(ptHandle->pcmbuffer);
		ptHandle->pcmbuffer = NULL;
	}

	free(ptHandle);

	return 0;
}

int ATK_AudioEnc_EncodeOneFrame(ATK_AUDIOENC_HANDLE_T *ptHandle, ATK_AUDIOENC_ONEFRAME_CONF_T* ptConf)
{
	return ptHandle->enc_func(ptHandle, ptConf);
}

int ATK_AudioEnc_GetConf(ATK_AUDIOENC_HANDLE_T *ptHandle, void *pConfBuf)
{
	return ptHandle->getconf_func(ptHandle, pConfBuf);
}

