Initial empty repository

Change-Id: I82a7c934369c8674b511651fd3d301b496ba98c3
diff --git a/utils/Android.mk b/utils/Android.mk
new file mode 100755
index 0000000..1d5a2f9
--- /dev/null
+++ b/utils/Android.mk
@@ -0,0 +1,52 @@
+LOCAL_PATH:= $(call my-dir)
+
+include $(CLEAR_VARS)
+
+#LOCAL_CFLAGS += -DAML_CONFIG_SUPPORT_READ_ONLY
+
+LOCAL_C_INCLUDES +=                      \
+    hardware/libhardware/include \
+    $(TOPDIR)system/core/include        \
+    $(LOCAL_PATH)/include       \
+    $(TOPDIR)external/tinyalsa/include   \
+    $(TOPDIR)system/media/audio_utils/include \
+    $(LOCAL_PATH)/ini/include
+
+LOCAL_SRC_FILES  +=               \
+    aml_buffer_provider.c         \
+    aml_dump_debug.c              \
+    aml_audio_resampler.c         \
+    aml_ringbuffer.c              \
+    aml_alsa_mixer.c              \
+    aml_hw_profile.c              \
+    aml_android_utils.c           \
+    aml_data_utils.c              \
+    aml_configs/aml_conf_loader.c \
+    aml_configs/aml_conf_parser.c \
+    aml_audio_mixer.c             \
+    SPDIFEncoderAD.cpp            \
+    spdifenc_wrap.cpp             \
+    aml_volume_utils.c            \
+    ini/ini.cpp                   \
+    ini/IniParser.cpp             \
+    ac3_parser_utils.c
+
+LOCAL_MODULE := libamaudioutils
+
+ifeq ($(shell test $(PLATFORM_SDK_VERSION) -ge 26 && echo OK),OK)
+    LOCAL_PROPRIETARY_MODULE := true
+endif
+
+LOCAL_SHARED_LIBRARIES += \
+    libc                  \
+    libcutils             \
+    libutils              \
+    liblog                \
+    libtinyalsa           \
+    libaudioutils         \
+    libdroidaudiospdif
+
+LOCAL_MODULE_TAGS := optional
+LOCAL_CFLAGS += -DBUILD_IN_ANDROID
+
+include $(BUILD_SHARED_LIBRARY)
diff --git a/utils/SPDIFEncoderAD.cpp b/utils/SPDIFEncoderAD.cpp
new file mode 100755
index 0000000..97b754a
--- /dev/null
+++ b/utils/SPDIFEncoderAD.cpp
@@ -0,0 +1,168 @@
+/*
+ * Copyright (C) 2010 Amlogic Corporation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "SPDIFEncoderAD"
+#include <stdint.h>
+#include <utils/Log.h>
+#include <system/audio.h>
+#include <audio_utils/spdif/SPDIFEncoder.h>
+#include <tinyalsa/asoundlib.h>
+#include <cutils/properties.h>
+#include "SPDIFEncoderAD.h"
+#include "aml_android_utils.h"
+
+extern "C"
+{
+//#include "audio_hw_utils.h"
+}
+
+
+namespace android
+{
+class SPDIFEncoderAD : public SPDIFEncoder
+{
+public:
+    SPDIFEncoderAD(audio_format_t format, const void *output, size_t max_output_size)
+        : SPDIFEncoder(format)
+        , mTotalBytes(0)
+        //, eac3_frame(0)
+        //, mformat(format)
+        , outBuf(output)
+        , outBufSize(max_output_size)
+        , outBufCurrentPos(0)
+    {
+        ALOGI("%s() format %#x outBuf %p outBufSize %zu\n", __FUNCTION__, format, outBuf, outBufSize);
+    };
+    virtual ssize_t writeOutput(const void* buffer, size_t bytes)
+    {
+//        int ret = -1;
+        ALOGV("write size %zu , outBufCurrentPos %zu\n", bytes, outBufCurrentPos);
+
+        // ret = pcm_write(buffer, bytes);
+        char *iec61937_buffer = (char *)outBuf + outBufCurrentPos;
+        size_t actual_write_size =
+            ((outBufSize - outBufCurrentPos) > bytes) ? (bytes) : (outBufSize - outBufCurrentPos);
+        if (outBuf && (actual_write_size > 0))
+            memcpy((void *)iec61937_buffer, (const void*)buffer, actual_write_size);
+        else
+            return -1;
+        if (actual_write_size > 0) {
+            outBufCurrentPos += actual_write_size;
+            mTotalBytes += actual_write_size;
+            ALOGV("%s() actual_write_size %zu outBufCurrentPos %zu\n", __FUNCTION__, actual_write_size, outBufCurrentPos);
+#if 1
+            if (aml_getprop_bool("media.audiohal.outdump")) {
+                FILE *fp1 = fopen("/data/audio_out/enc_output.spdif", "a+");
+                if (fp1) {
+                    int flen = fwrite((char *)iec61937_buffer, 1, actual_write_size, fp1);
+                    ALOGV("%s iec61937_buffer %p write_size %d\n", __FUNCTION__, iec61937_buffer, flen);
+                    fclose(fp1);
+                } else {
+                    //ALOGD("could not open file:/data/hdmi_audio_out.pcm");
+                }
+            }
+#endif
+            return actual_write_size;
+        }
+        else
+            return -1;
+    }
+    /*
+     *@brief get current iec61937 data size
+     */
+    virtual size_t getCurrentIEC61937DataSize(void) {
+        return outBufCurrentPos;
+    }
+    /*
+     *@brief flush output iec61937 data current position to zero!
+     */
+    virtual void flushOutputCurrentPosition() {
+        outBufCurrentPos = 0;
+    }
+    /*
+     *@brief get total tytes that through the spdif encoder
+     */
+    virtual uint64_t total_bytes()
+    {
+        return mTotalBytes;
+    }
+protected:
+
+private:
+    uint64_t mTotalBytes;
+//    uint64_t eac3_frame;
+//    audio_format_t mformat;
+    const void *outBuf;
+    size_t outBufSize;
+    size_t outBufCurrentPos;
+
+};
+static SPDIFEncoderAD *spdif_encoder_ad = NULL;
+extern "C" int spdif_encoder_ad_init(audio_format_t format, const void *output, int max_output_size)
+{
+    if (spdif_encoder_ad) {
+        delete spdif_encoder_ad;
+        spdif_encoder_ad = NULL;
+    }
+    spdif_encoder_ad = new SPDIFEncoderAD(format, output, max_output_size);
+    if (spdif_encoder_ad == NULL) {
+        ALOGE("init SPDIFEncoderAD failed \n");
+        return  -1;
+    }
+    ALOGI("init SPDIFEncoderAD done\n");
+    return 0;
+}
+extern "C" int spdif_encoder_ad_write(const void *buffer, size_t numBytes)
+{
+#if 1
+    if (aml_getprop_bool("media.audiohal.outdump")) {
+        FILE *fp1 = fopen("/data/audio_out/enc_input.spdif", "a+");
+        if (fp1) {
+            fwrite((char *)buffer, 1, numBytes, fp1);
+            fclose(fp1);
+        }
+    }
+#endif
+    return spdif_encoder_ad->write(buffer, numBytes);
+}
+extern "C" uint64_t spdif_encoder_ad_get_total()
+{
+    return spdif_encoder_ad->total_bytes();
+}
+/*
+ *@brief get current iec61937 data size
+ */
+extern "C" size_t spdif_encoder_ad_get_current_position(void)
+{
+    return spdif_encoder_ad->getCurrentIEC61937DataSize();
+}
+/*
+ *@brief flush output iec61937 data current position to zero!
+ */
+extern "C" void spdif_encoder_ad_flush_output_current_position(void)
+{
+    return spdif_encoder_ad->flushOutputCurrentPosition();
+}
+
+extern "C" void spdif_encoder_ad_reset(void)
+{
+    return spdif_encoder_ad->reset();
+}
+
+}
diff --git a/utils/ac3_parser_utils.c b/utils/ac3_parser_utils.c
new file mode 100755
index 0000000..95c6a7b
--- /dev/null
+++ b/utils/ac3_parser_utils.c
@@ -0,0 +1,289 @@
+/*
+ * Copyright (C) 2017 Amlogic Corporation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "libamaudioutils"
+// #define LOG_NDEBUG 0
+
+#include <errno.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <time.h>
+#include <sys/prctl.h>
+#include <cutils/log.h>
+#include <string.h>
+
+
+#include "ac3_parser_utils.h"
+
+
+#define BYTE_REV(a) ((((uint16_t)a) & 0xff) << 8 | ((uint16_t)a) >> 8)
+
+/*====================*/
+/*merge from ffmpeg begin====*/
+
+/**
+ * Possible frame sizes.
+ * from ATSC A/52 Table 5.18 Frame Size Code Table.
+ */
+const uint16_t ff_ac3_frame_size_tab[38][3] = {
+    { 64,   69,   96   },
+    { 64,   70,   96   },
+    { 80,   87,   120  },
+    { 80,   88,   120  },
+    { 96,   104,  144  },
+    { 96,   105,  144  },
+    { 112,  121,  168  },
+    { 112,  122,  168  },
+    { 128,  139,  192  },
+    { 128,  140,  192  },
+    { 160,  174,  240  },
+    { 160,  175,  240  },
+    { 192,  208,  288  },
+    { 192,  209,  288  },
+    { 224,  243,  336  },
+    { 224,  244,  336  },
+    { 256,  278,  384  },
+    { 256,  279,  384  },
+    { 320,  348,  480  },
+    { 320,  349,  480  },
+    { 384,  417,  576  },
+    { 384,  418,  576  },
+    { 448,  487,  672  },
+    { 448,  488,  672  },
+    { 512,  557,  768  },
+    { 512,  558,  768  },
+    { 640,  696,  960  },
+    { 640,  697,  960  },
+    { 768,  835,  1152 },
+    { 768,  836,  1152 },
+    { 896,  975,  1344 },
+    { 896,  976,  1344 },
+    { 1024, 1114, 1536 },
+    { 1024, 1115, 1536 },
+    { 1152, 1253, 1728 },
+    { 1152, 1254, 1728 },
+    { 1280, 1393, 1920 },
+    { 1280, 1394, 1920 },
+};
+
+/**
+ * Map audio coding mode (acmod) to number of full-bandwidth channels.
+ * from ATSC A/52 Table 5.8 Audio Coding Mode
+ */
+const uint8_t ff_ac3_channels_tab[8] = {
+    2, 1, 2, 3, 3, 4, 4, 5
+};
+/** Channel mode (audio coding mode) */
+typedef enum {
+    AC3_CHMODE_DUALMONO = 0,
+    AC3_CHMODE_MONO,
+    AC3_CHMODE_STEREO,
+    AC3_CHMODE_3F,
+    AC3_CHMODE_2F1R,
+    AC3_CHMODE_3F1R,
+    AC3_CHMODE_2F2R,
+    AC3_CHMODE_3F2R
+} AC3ChannelMode;
+
+/**
+ * Table for center mix levels
+ * reference: Section 5.4.2.4 cmixlev
+ */
+//static const uint8_t center_levels[4] = { 4, 5, 6, 5 };
+
+/**
+ * Table for surround mix levels
+ * reference: Section 5.4.2.5 surmixlev
+ */
+//static const uint8_t surround_levels[4] = { 4, 6, 7, 6 };
+/*=====merge from ffmpeg end*/
+/*====================*/
+
+/*
+ *@brief check_ac3_syncword: seek sync words for dd/ddp
+ */
+static int check_ac3_syncword (const unsigned char *ptr, int size)
+{
+    if (size < 2)
+        return 0;
+    if (ptr[0] == 0x0b && ptr[1] == 0x77)
+        return 1;
+    if (ptr[0] == 0x77 && ptr[1] == 0x0b)
+        return 2;
+
+    return 0;
+}
+
+/*
+ *parse frame header[ATSC Standard,Digital Audio Compression (AC-3, E-AC-3)]
+ */
+int parse_dolby_frame_header
+(const unsigned char *frameBuf
+ , int length
+ , int *frame_offset
+ , int *frame_size
+ , int *channel_num
+ , int *numblks
+ , int *timeslice_61937
+ , int *framevalid_flag)
+{
+    int acmod = 0;
+    int lfeOn = 0;
+    int nIsEc3 = 0;
+    int frame_size_code = 0;
+    int sr_code = 0;
+    int substreamid = 0;
+    int numblk_per_frame;
+    char inheader[12] = {0};
+    int offset = 0;
+    int header = 0;
+    int i = 0;
+    *channel_num = 2;
+
+    /*TODO, used to correct iec61937 packet*/
+    *timeslice_61937 = 0;
+    *framevalid_flag = 0;
+
+    for (i = 0; i < length; ++i) {
+        if ( (header = check_ac3_syncword (&frameBuf[i], length - i) ) > 0) {
+            offset = i;
+            break;
+        }
+    }
+    /*step 1, frame header 0x0b77/0x770b*/
+    if (header == 0) {
+        //ALOGE("locate frame header 0x0b77/0x770b failed\n");
+        goto error;/*no frame header, maybe need more data*/
+    }
+
+    /*step 2, copy 12bytes to inheader,  find one frame*/
+    if (length-offset < 12) {
+        /*
+         *find the sync word 0x0b77/0x770b,
+         *but we need 12bytes which will copy to inheader[12], need more data
+         */
+        ALOGE ("data less than one frame!!!\n");
+        goto error;
+    } else {
+        memcpy ( (void *) inheader, (const void *) (frameBuf+offset), 12);
+    }
+
+    if (header == 2) {
+        int16_t *p_data = (int16_t *) inheader;
+        unsigned int idx;
+        unsigned int inheader_len = 12;
+        unsigned int top = inheader_len / 2;
+        for (idx = 0; idx < top; idx++) {
+            p_data[idx] = (int16_t) BYTE_REV (p_data[idx]);
+        }
+    }
+
+    if (length < 12) {
+        ALOGE ("%s len %d\n",__FUNCTION__, length);
+        goto error;
+    } else {
+        //ALOGV("dolby head:0x%x 0x%x 0x%x 0x%x 0x%x 0x%x \n",
+        //    inheader[0],inheader[1],inheader[2], inheader[3],inheader[4],inheader[5]);
+        int bsid = (inheader[5] >> 3) & 0x1f;//bitstream_id,bit[40,44]
+        if (bsid > 16)
+            goto error;//invalid bitstream_id
+        if (bsid <= 8)
+            nIsEc3 = 0;
+        else if ( (bsid <= 16) && (bsid > 10) )
+            nIsEc3 = 1;
+
+        if (nIsEc3 == 0) {
+            int use_bits = 0;
+
+            substreamid = 0;
+            sr_code = inheader[4]>>6;
+            if (sr_code == 3) {
+                ALOGE ("%s error *sr_code %d", __FUNCTION__, sr_code);
+                goto error;
+            }
+            frame_size_code = inheader[4]&0x3F;
+            if (frame_size_code > 37) {
+                ALOGE ("%s error frame_size_code %d", __FUNCTION__, frame_size_code);
+                goto error;
+            }
+            acmod = (inheader[6] >> 5) & 0x7;// 3bits
+            use_bits = use_bits+3;
+            if (acmod == AC3_CHMODE_STEREO) {
+                //int dolby_surround_mode = (inheader[6] >> 3) &0x3; // 2bits
+                use_bits = use_bits +2;
+            } else {
+                if ( (acmod & 1)  &&  (acmod != AC3_CHMODE_MONO) ) {
+                    //int center_mix_level =  center_levels[ (inheader[6] >> 3) &0x3]; // 2bits
+                    use_bits = use_bits + 2;
+                }
+                if (acmod & 4) {
+                    //int surround_mix_level = surround_levels[ (inheader[6] >> 1) &0x3]; // 2bits
+                    use_bits = use_bits + 2;
+                }
+            }
+            lfeOn = (inheader[6] >> (8 - use_bits -1) ) &0x1; // 1bit
+            *frame_size = ff_ac3_frame_size_tab[frame_size_code][sr_code] * 2;
+            numblk_per_frame = 6;
+            *numblks = numblk_per_frame;
+            *timeslice_61937 = 1;
+            *framevalid_flag = 1;
+        } else {
+            int numblkscod = 0;
+            int strmtyp = (inheader[2] >> 6) & 0x3;
+            int substreamid = (inheader[2]>>3) &0x7;
+            *frame_size = ( (inheader[2]&0x7) *0x100 + inheader[3] + 1) << 1;
+            sr_code = inheader[4]>>6;
+            acmod = (inheader[4] >> 1) & 0x7;
+            lfeOn = inheader[4] &0x1;
+            numblkscod = (sr_code == 0x3) ? 0x3 : ( (inheader[4] >> 4) & 0x3);
+            numblk_per_frame = (numblkscod == 0x3) ? 6 : (numblkscod + 1);
+
+            if (substreamid == 0 && strmtyp == 0) {
+                if (*framevalid_flag == 0) {
+                    *timeslice_61937 = 0;
+                    *numblks += numblk_per_frame;
+                    *framevalid_flag = 1;
+                } else if (*framevalid_flag == 1) {
+                    if (*numblks  == 6) {
+                        *timeslice_61937 = 1;
+                        *numblks = numblk_per_frame;
+                    } else if (*numblks  > 6) {
+                        *timeslice_61937 = 2;
+                        *numblks = numblk_per_frame;
+                    } else {
+                        *timeslice_61937 = 0;
+                        *numblks += numblk_per_frame;
+                    }
+                }
+            } else if (strmtyp == 1) {
+                *timeslice_61937 = 3;
+            }
+
+        }
+        // ALOGV("%s acmod %d lfeOn %d\n", nIsEc3==0?"ac3":"ec3",acmod, lfeOn);
+        *channel_num = ff_ac3_channels_tab[acmod] + lfeOn;
+    }
+    *frame_offset = offset;
+    ALOGV ("%s frame_offset %d frame_size %d channel_num %d numblks %d timeslice_61937 %d framevalid_flag %d\n",
+           __FUNCTION__, *frame_offset, *frame_size, *channel_num, *numblks, *timeslice_61937, *framevalid_flag);
+
+    return 0;
+error:
+    *frame_offset = 0;
+    return 1;
+}
diff --git a/utils/aml_alsa_mixer.c b/utils/aml_alsa_mixer.c
new file mode 100644
index 0000000..6156aec
--- /dev/null
+++ b/utils/aml_alsa_mixer.c
@@ -0,0 +1,256 @@
+/*
+ * Copyright (C) 2017 Amlogic Corporation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ ** aml_alsa_mixer.c
+ **
+ ** This program is APIs for read/write mixers of alsa.
+ ** author: shen pengru
+ **
+ */
+#include <stdlib.h>
+#include <stdint.h>
+#include <unistd.h>
+#include <errno.h>
+#include <cutils/log.h>
+#include <fcntl.h>
+#include <tinyalsa/asoundlib.h>
+#include <aml_hw_profile.h>
+#include <aml_alsa_mixer.h>
+
+#undef  LOG_TAG
+#define LOG_TAG "audio_alsa_mixer"
+
+static struct aml_mixer_list gAmlMixerList[] = {
+    /* for i2s out status */
+    {AML_MIXER_ID_I2S_MUTE,             "Audio i2s mute"},
+    /* for spdif out status */
+    {AML_MIXER_ID_SPDIF_MUTE,           "Audio spdif mute"},
+    /* for HDMI TX status */
+    {AML_MIXER_ID_HDMI_OUT_AUDIO_MUTE,  "Audio hdmi-out mute"},
+    /* for HDMI ARC status */
+    {AML_MIXER_ID_HDMI_ARC_AUDIO_ENABLE, "HDMI ARC Switch"},
+    {AML_MIXER_ID_AUDIO_IN_SRC,         "Audio In Source"},
+    {AML_MIXER_ID_I2SIN_AUDIO_TYPE,     "I2SIN Audio Type"},
+    {AML_MIXER_ID_SPDIFIN_AUDIO_TYPE,   "SPDIFIN Audio Type"},
+    {AML_MIXER_ID_HW_RESAMPLE_ENABLE,   "Hardware resample enable"},
+    {AML_MIXER_ID_OUTPUT_SWAP,          "Output Swap"},
+    /* for HDMI RX status */
+    {AML_MIXER_ID_HDMI_IN_AUDIO_STABLE, "HDMIIN audio stable"},
+    {AML_MIXER_ID_HDMI_IN_SAMPLERATE,   "HDMIIN audio samplerate"},
+    {AML_MIXER_ID_HDMI_IN_CHANNELS,     "HDMIIN audio channels"},
+    {AML_MIXER_ID_HDMI_IN_FORMATS,      "HDMIIN audio format"},
+    {AML_MIXER_ID_HDMI_ATMOS_EDID,      "HDMI ATMOS EDID Switch"},
+    /* for ATV status */
+    {AML_MIXER_ID_ATV_IN_AUDIO_STABLE,  "ATV audio stable"},
+    {AML_MIXER_ID_SPDIF_FORMAT,         "Audio spdif format"},
+    /* for AV status */
+    {AML_MIXER_ID_AV_IN_AUDIO_STABLE,   "AV audio stable"},
+    /* for Speaker master volume */
+    {AML_MIXER_ID_EQ_MASTER_VOLUME,     "EQ master volume"},
+    /* ARCIN and SPDIFIN switch*/
+    {AML_MIXER_ID_SPDIFIN_ARCIN_SWITCH, "AudioIn Switch"}
+};
+
+static char *_get_mixer_name_by_id(int mixer_id)
+{
+    int i;
+    int cnt_mixer = sizeof(gAmlMixerList) / sizeof(struct aml_mixer_list);
+
+    for (i = 0; i < cnt_mixer; i++) {
+        if (gAmlMixerList[i].id == mixer_id) {
+            return gAmlMixerList[i].mixer_name;
+        }
+    }
+
+    return NULL;
+}
+
+static struct mixer *_open_mixer_handle(void)
+{
+    int card = 0;
+    struct mixer *pmixer = NULL;
+
+    card = aml_get_sound_card_main();
+    if (card < 0) {
+        ALOGE("[%s:%d] Failed to get sound card\n", __FUNCTION__, __LINE__);
+        return NULL;
+    }
+
+    pmixer = mixer_open(card);
+    if (NULL == pmixer) {
+        ALOGE("[%s:%d] Failed to open mixer\n", __FUNCTION__, __LINE__);
+        return NULL;
+    }
+
+    return pmixer;
+}
+
+static int _close_mixer_handle(struct mixer *pmixer)
+{
+    if (NULL != pmixer) {
+        mixer_close(pmixer);
+    }
+
+    return 0;
+}
+
+static struct mixer_ctl *_get_mixer_ctl_handle(struct mixer *pmixer, int mixer_id)
+{
+    struct mixer_ctl *pCtrl = NULL;
+
+    if (_get_mixer_name_by_id(mixer_id) != NULL) {
+        pCtrl = mixer_get_ctl_by_name(pmixer,
+                                      _get_mixer_name_by_id(mixer_id));
+    }
+
+    return pCtrl;
+}
+
+int aml_mixer_ctrl_get_int(int mixer_id)
+{
+    struct mixer     *pMixer;
+    struct mixer_ctl *pCtrl;
+    int value = -1;
+
+    pMixer = _open_mixer_handle();
+    if (pMixer == NULL) {
+        ALOGE("[%s:%d] Failed to open mixer\n", __FUNCTION__, __LINE__);
+        return -1;
+    }
+
+    pCtrl = _get_mixer_ctl_handle(pMixer, mixer_id);
+    if (pCtrl == NULL) {
+        ALOGE("[%s:%d] Failed to open mixer %s\n", __FUNCTION__, __LINE__,
+              _get_mixer_name_by_id(mixer_id));
+        _close_mixer_handle(pMixer);
+        return -1;
+    }
+
+    value = mixer_ctl_get_value(pCtrl, 0);
+
+    _close_mixer_handle(pMixer);
+    return value;
+}
+
+int aml_mixer_ctrl_get_enum_str_to_int(int mixer_id, int *ret)
+{
+    struct mixer     *pMixer;
+    struct mixer_ctl *pCtrl;
+    const char *string = NULL;
+    int value = -1;
+
+    pMixer = _open_mixer_handle();
+    if (pMixer == NULL) {
+        ALOGE("[%s:%d] Failed to open mixer\n", __FUNCTION__, __LINE__);
+        return -1;
+    }
+
+    pCtrl = _get_mixer_ctl_handle(pMixer, mixer_id);
+    if (pCtrl == NULL) {
+        ALOGE("[%s:%d] Failed to open mixer %s\n", __FUNCTION__, __LINE__,
+              _get_mixer_name_by_id(mixer_id));
+        _close_mixer_handle(pMixer);
+        return -1;
+    }
+
+    value = mixer_ctl_get_value(pCtrl, 0);
+    string = mixer_ctl_get_enum_string(pCtrl, value);
+    _close_mixer_handle(pMixer);
+    if (string) {
+        *ret = atoi(string);
+        return 0;
+    } else {
+        return -1;
+    }
+}
+
+#if 0
+int aml_mixer_ctrl_get_str(int mixer_id, char *value)
+{
+    struct mixer     *pMixer;
+    struct mixer_ctl *pCtrl;
+
+    pMixer = _open_mixer_handle();
+    if (pMixer == NULL) {
+        ALOGE("[%s:%d] Failed to open mixer\n", __FUNCTION__, __LINE__);
+        return -1;
+    }
+
+    pCtrl = _get_mixer_ctl_handle(pMixer, mixer_id);
+    if (pCtrl == NULL) {
+        ALOGE("[%s:%d] Failed to open mixer %s\n", __FUNCTION__, __LINE__,
+              _get_mixer_name_by_id(mixer_id));
+        _close_mixer_handle(pMixer);
+        return -1;
+    }
+
+    strcpy(value, mixer_ctl_get_value(pctl, 0));
+
+    _close_mixer_handle(pMixer);
+    return 0;
+}
+#endif
+
+int aml_mixer_ctrl_set_int(int mixer_id, int value)
+{
+    struct mixer     *pMixer;
+    struct mixer_ctl *pCtrl;
+
+    pMixer = _open_mixer_handle();
+    if (pMixer == NULL) {
+        ALOGE("[%s:%d] Failed to open mixer\n", __FUNCTION__, __LINE__);
+        return -1;
+    }
+
+    pCtrl = _get_mixer_ctl_handle(pMixer, mixer_id);
+    if (pCtrl == NULL) {
+        ALOGE("[%s:%d] Failed to open mixer %s\n", __FUNCTION__, __LINE__,
+              _get_mixer_name_by_id(mixer_id));
+        _close_mixer_handle(pMixer);
+        return -1;
+    }
+
+    mixer_ctl_set_value(pCtrl, 0, value);
+
+    _close_mixer_handle(pMixer);
+    return 0;
+}
+
+int aml_mixer_ctrl_set_str(int mixer_id, char *value)
+{
+    struct mixer     *pMixer;
+    struct mixer_ctl *pCtrl;
+
+    pMixer = _open_mixer_handle();
+    if (pMixer == NULL) {
+        ALOGE("[%s:%d] Failed to open mixer\n", __FUNCTION__, __LINE__);
+        return -1;
+    }
+
+    pCtrl = _get_mixer_ctl_handle(pMixer, mixer_id);
+    if (pCtrl == NULL) {
+        ALOGE("[%s:%d] Failed to open mixer %s\n", __FUNCTION__, __LINE__,
+              _get_mixer_name_by_id(mixer_id));
+        _close_mixer_handle(pMixer);
+        return -1;
+    }
+
+    mixer_ctl_set_enum_by_string(pCtrl, value);
+
+    _close_mixer_handle(pMixer);
+    return 0;
+}
diff --git a/utils/aml_android_utils.c b/utils/aml_android_utils.c
new file mode 100755
index 0000000..7b24564
--- /dev/null
+++ b/utils/aml_android_utils.c
@@ -0,0 +1,195 @@
+/*
+ * Copyright (C) 2017 Amlogic Corporation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ ** aml_android_utils.c
+ **
+ ** This program is APIs for get/set android property, get/set sys fs point.
+ ** author: shen pengru
+ **
+ */
+#include <stdlib.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <errno.h>
+#include <string.h>
+#include <cutils/log.h>
+#include <fcntl.h>
+#include <cutils/log.h>
+#include <cutils/str_parms.h>
+#include <cutils/properties.h>
+#include <aml_android_utils.h>
+
+#undef  LOG_TAG
+#define LOG_TAG "audio_android_utils"
+
+/*
+ * Android Property
+ */
+int aml_getprop_bool(const char * path)
+{
+	char buf[PROPERTY_VALUE_MAX];
+	int ret = -1;
+
+	ret = property_get(path, buf, NULL);
+	if (ret > 0) {
+		if (strcasecmp(buf, "true") == 0 || strcmp(buf, "1") == 0)
+			return eAML_BOOL_TRUE;
+	}
+
+	return eAML_BOOL_FALSE;
+}
+
+int aml_getprop_int(const char *path)
+{
+	char buf[PROPERTY_VALUE_MAX];
+	int ret = -1;
+	int value = 0;
+
+	ret = property_get(path, buf, NULL);
+	if (ret > 0) {
+		sscanf(buf, "%d", &value);
+	}
+
+	return value;
+}
+
+/*
+* Linux Sys Fs Set/Get Interface
+*/
+int aml_sysfs_get_int (const char *path)
+{
+	int val = 0;
+	int fd = open (path, O_RDONLY);
+	if (fd >= 0) {
+		char bcmd[16];
+		read (fd, bcmd, sizeof (bcmd));
+		val = strtol (bcmd, NULL, 10);
+		close (fd);
+	} else {
+		ALOGE("%s: open %s node failed! return 0, err: %s\n", __func__, path, strerror(errno));
+	}
+
+	return val;
+}
+
+int aml_sysfs_get_int16(const char *path,unsigned *value)
+{
+	int fd;
+	char valstr[64];
+	unsigned  val = 0;
+
+	fd = open(path, O_RDONLY);
+	if (fd >= 0) {
+		memset(valstr, 0, 64);
+		read(fd, valstr, 64 - 1);
+		valstr[strlen(valstr)] = '\0';
+		close(fd);
+	} else {
+		ALOGE("%s: unable to open file %s, err: %s\n", __func__, path, strerror(errno));
+		return -1;
+	}
+	if (sscanf(valstr, "0x%x", &val) < 1) {
+		ALOGE("%s: unable to get pts from: %s, err: %s\n", __func__, valstr, strerror(errno));
+		return -1;
+	}
+	*value = val;
+
+	return 0;
+}
+
+int aml_sysfs_get_str(const char *path, char *buf, int count)
+{
+	int fd, len;
+	int i , j;
+
+	if ( NULL == buf ) {
+		ALOGE("buf is NULL");
+		return -1;
+	}
+
+	if ((fd = open(path, O_RDONLY)) < 0) {
+		ALOGE("readSys, open %s error(%s)", path, strerror (errno));
+		return -1;
+	}
+
+	len = read(fd, buf, count);
+	if (len < 0) {
+		ALOGE("read %s error, %s\n", path, strerror(errno));
+		goto exit;
+	}
+
+	for (i = 0, j = 0; i <= len -1; i++) {
+		//change '\0' to 0x20(spacing), otherwise the string buffer will be cut off ,if the last char is '\0' should not replace it
+		if (0x0 == buf[i] && i < len - 1) {
+			buf[i] = 0x20;
+		}
+		/* delete all the character of '\n' */
+		if (0x0a != buf[i]) {
+			buf[j++] = buf[i];
+		}
+	}
+
+	buf[j] = 0x0;
+
+exit:
+	close(fd);
+
+	return len;
+}
+
+int aml_sysfs_set_str(const char *path, const char *val)
+{
+	int fd;
+	int bytes;
+
+	fd = open(path, O_CREAT | O_RDWR | O_TRUNC, 0644);
+	if (fd >= 0) {
+		bytes = write(fd, val, strlen(val));
+		close(fd);
+		return 0;
+	} else {
+		ALOGE("%s: unable to open file %s,err: %s\n", __func__, path, strerror(errno));
+	}
+
+	return -1;
+}
+
+/*
+* Aml private strstr
+*/
+int aml_strstr(char *mystr,char *substr) {
+	int i=0;
+	int j=0;
+	int score = 0;
+	int substrlen = 0;
+	int ok = 0;
+
+	substrlen = strlen(substr);
+	for (i =0;i < 1024 - substrlen;i++) {
+		for (j = 0;j < substrlen;j++) {
+			score += (substr[j] == mystr[i+j])?1:0;
+		}
+		if (score == substrlen) {
+			ok = 1;
+			break;
+		}
+		score = 0;
+	}
+
+	return ok;
+}
diff --git a/utils/aml_audio_mixer.c b/utils/aml_audio_mixer.c
new file mode 100755
index 0000000..56e0a0b
--- /dev/null
+++ b/utils/aml_audio_mixer.c
@@ -0,0 +1,410 @@
+/*
+ * Copyright (C) 2017 Amlogic Corporation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "aml_audio_mixer"
+//#define LOG_NDEBUG 0
+
+#include <cutils/log.h>
+#include <errno.h>
+#include <pthread.h>
+#include <sys/prctl.h>
+#include <stdlib.h>
+
+#include <aml_audio_mixer.h>
+
+struct ring_buf_desc {
+    struct ring_buffer *buffer;
+    struct pcm_config cfg;
+    int period_time;
+    int valid;
+};
+
+//simple mixer support: 2 in , 1 out
+struct aml_audio_mixer {
+    struct ring_buf_desc main_in_buf;
+    struct ring_buf_desc aux_in_buf;
+    unsigned int internal_main : 1;
+    unsigned int internal_aux : 1;
+    struct pcm_config mixer_cfg;
+    int period_time;
+    void *out_buffer;
+    void *aux_buffer;
+    int out_buffer_size;
+    pthread_t out_mixer_tid;
+    //pthread_mutex_t lock;
+    //pthread_cond_t cond;
+    int running : 1;
+    int init_ok : 1;
+    void *priv_data;
+    int (*mixer_out_write) (void *buffer, void *priv_data, size_t size);
+};
+
+static void aml_dump_audio_pcm_config (struct pcm_config cfg)
+{
+    ALOGI ("\t-format:%#x, rate:%d, channels:%d", cfg.format, cfg.rate, cfg.channels);
+    ALOGI ("\t-period_size:%d, period_count:%d", cfg.period_size, cfg.period_count);
+
+}
+
+static void aml_dump_audio_ring_buf_desc (struct ring_buf_desc *buf_desc)
+{
+    aml_dump_audio_pcm_config (buf_desc->cfg);
+    ALOGI ("\t-period_time:%d, valid:%d", buf_desc->period_time, buf_desc->valid);
+    ring_buffer_dump (buf_desc->buffer);
+}
+
+void aml_dump_audio_mixer (struct aml_audio_mixer *audio_mixer)
+{
+    ALOGI ("+dump audio mixer out config:");
+    aml_dump_audio_pcm_config (audio_mixer->mixer_cfg);
+    ALOGI ("\tperiod_time:%d, out_buffer_size:%d", audio_mixer->period_time, audio_mixer->out_buffer_size);
+    aml_dump_audio_ring_buf_desc (&audio_mixer->main_in_buf);
+    aml_dump_audio_ring_buf_desc (&audio_mixer->aux_in_buf);
+}
+
+static inline int aml_audio_mixer_check_status (struct aml_audio_mixer *audio_mixer)
+{
+    if (audio_mixer->init_ok) {
+        return 1;
+    } else if (audio_mixer->main_in_buf.valid && audio_mixer->aux_in_buf.valid) {
+        audio_mixer->init_ok = 1;
+        return 1;
+    }
+    return 0;
+}
+
+static inline unsigned int calc_config_frame_size (struct pcm_config config)
+{
+    return config.channels * (pcm_format_to_bits (config.format) >> 3);
+}
+
+static inline unsigned int bytes_to_frames (struct pcm_config config, size_t bytes)
+{
+    return bytes / calc_config_frame_size (config);
+}
+
+struct aml_audio_mixer *new_aml_audio_mixer (struct pcm_config out_config)
+{
+    struct aml_audio_mixer *audio_mixer = NULL;
+
+    audio_mixer = calloc (1, sizeof (*audio_mixer) );
+    if (!audio_mixer)
+        return NULL;
+
+    audio_mixer->mixer_cfg = out_config;
+    audio_mixer->period_time = out_config.period_size * 1000 / out_config.rate;
+    //pthread_mutex_init(&audio_mixer->lock, NULL);
+    //pthread_cond_init(&audio_mixer->cond, NULL);
+    return audio_mixer;
+}
+
+void aml_delete_audio_mixer (struct aml_audio_mixer *audio_mixer)
+{
+    if (audio_mixer) {
+        //pthread_mutex_destroy(&audio_mixer->lock);
+        //pthread_cond_destroy(&audio_mixer->cond);
+        free (audio_mixer);
+    }
+}
+
+static void main_aux_buffer_mix (struct aml_audio_mixer *audio_mixer __unused)
+{
+    //TODO: do nothing now, only ouput main buffer data;
+    //add mixing methods latter.
+    return;
+}
+
+static void *out_mixer_threadloop (void *data)
+{
+    struct aml_audio_mixer *audio_mixer = data;
+    struct ring_buf_desc *main_desc = &audio_mixer->main_in_buf;
+    struct ring_buf_desc *aux_desc = &audio_mixer->aux_in_buf;
+    struct ring_buffer *main_buffer = main_desc->buffer;
+    struct ring_buffer *aux_buffer = aux_desc->buffer;
+    // calc write block size
+    struct pcm_config *cfg = &main_desc->cfg;
+    int period_byte = audio_mixer->out_buffer_size;
+    //int ready = 0;
+    // sleep half period
+    int msleep_time = cfg->period_size * 400 / cfg->rate;
+
+    if (!audio_mixer->mixer_out_write)
+        return NULL;
+
+    audio_mixer->running = 1;
+    prctl (PR_SET_NAME, "aml_audio_mixer");
+    ALOGI ("%s start", __func__);
+    while (audio_mixer->running) {
+        //pthread_mutex_lock(&audio_mixer->lock);
+        if (get_buffer_read_space (main_buffer) >= period_byte) {
+            ring_buffer_read (main_buffer, audio_mixer->out_buffer, period_byte);
+            if (get_buffer_read_space (aux_buffer) >= period_byte) {
+                ring_buffer_read (aux_buffer, audio_mixer->aux_buffer, period_byte);
+                main_aux_buffer_mix (audio_mixer);
+            }
+            audio_mixer->mixer_out_write (audio_mixer->out_buffer, audio_mixer->priv_data, period_byte);
+        } else {
+            //pthread_cond_wait(&audio_mixer->cond, &audio_mixer->lock);
+            //ALOGV("%s main mixer sleeping time %d", __func__, msleep_time);
+            // Not enough data, wait for half period
+            usleep (msleep_time * 1000);
+        }
+        //pthread_mutex_unlock(&audio_mixer->lock);
+    }
+
+    ALOGI ("%s", __func__);
+    return NULL;
+}
+
+int aml_start_audio_mixer (struct aml_audio_mixer *audio_mixer)
+{
+    struct ring_buf_desc *main_desc = NULL;
+    int period_byte = 0;
+
+    if (audio_mixer == NULL && !aml_audio_mixer_check_status (audio_mixer) )
+        return -EINVAL;
+
+    main_desc = &audio_mixer->main_in_buf;
+    period_byte = main_desc->cfg.period_size * calc_config_frame_size (main_desc->cfg);
+
+    audio_mixer->out_buffer = malloc (period_byte);
+    if (!audio_mixer->out_buffer)
+        return -ENOMEM;
+
+    audio_mixer->aux_buffer = malloc (period_byte);
+    if (!audio_mixer->aux_buffer) {
+        free (audio_mixer->out_buffer);
+        return -EINVAL;
+    }
+    audio_mixer->out_buffer_size = period_byte;
+
+    return pthread_create (&audio_mixer->out_mixer_tid, NULL, out_mixer_threadloop, audio_mixer);
+}
+
+int aml_stop_audio_mixer (struct aml_audio_mixer *audio_mixer)
+{
+    if (audio_mixer == NULL)
+        return -EINVAL;
+
+    audio_mixer->running = 0;
+    //pthread_cond_signal(&audio_mixer->cond);
+    pthread_join (audio_mixer->out_mixer_tid, NULL);
+    ALOGI ("%s", __func__);
+    if (audio_mixer->out_buffer) {
+        free (audio_mixer->out_buffer);
+        audio_mixer->out_buffer = NULL;
+    }
+
+    return 0;
+}
+
+static int aml_malloc_internal_ring_buffer (struct ring_buf_desc *buf_desc,
+        struct pcm_config cfg)
+{
+    struct ring_buffer *ringbuf = NULL;
+    int buffer_size, frame_size;
+    int ret = 0;
+
+    frame_size = calc_config_frame_size (cfg);
+    buffer_size = cfg.period_size * cfg.period_count * frame_size;
+    ringbuf = calloc (1, sizeof (*ringbuf) );
+    if (!ringbuf) {
+        ALOGE ("no memory");
+        return -ENOMEM ;
+    }
+    ret = ring_buffer_init (ringbuf, buffer_size);
+    if (ret) {
+        ALOGE ("init ring buffer fail, buffer_size = %d", buffer_size);
+        goto exit;
+    }
+    buf_desc->buffer = ringbuf;
+    buf_desc->valid = 1;
+
+    return 0;
+
+exit:
+    free (ringbuf);
+    return -EINVAL;
+}
+
+static void aml_free_internal_ring_buffer (struct ring_buf_desc *buf_desc)
+{
+    ring_buffer_release (buf_desc->buffer);
+    free (buf_desc->buffer);
+    buf_desc->buffer = NULL;
+    buf_desc->valid = 0;
+}
+
+int aml_register_mixer_main_in_buffer (struct aml_audio_mixer *audio_mixer,
+                                       struct ring_buffer *ringbuffer, struct pcm_config cfg)
+{
+    struct ring_buf_desc *main_inbuf = NULL;
+    int ret;
+
+    if (audio_mixer == NULL)
+        return -EINVAL;
+
+    main_inbuf = &audio_mixer->main_in_buf;
+    if (ringbuffer) {
+        main_inbuf->buffer = ringbuffer;
+        audio_mixer->internal_main = 0;
+    } else {
+        ret = aml_malloc_internal_ring_buffer (main_inbuf, cfg);
+        if (ret < 0)
+            return ret;
+
+        audio_mixer->internal_main = 1;
+    }
+
+    main_inbuf->cfg = cfg;
+    main_inbuf->period_time = cfg.period_size * 1000 / cfg.rate;
+
+    return 0;
+}
+
+int aml_release_main_in_buffer (struct aml_audio_mixer *audio_mixer)
+{
+    struct ring_buf_desc *main_inbuf = NULL;
+//    int ret;
+
+    if (audio_mixer == NULL)
+        return -EINVAL;
+
+    main_inbuf = &audio_mixer->main_in_buf;
+
+    aml_free_internal_ring_buffer (main_inbuf);
+    return 0;
+}
+
+int aml_register_mixer_aux_in_buffer (struct aml_audio_mixer *audio_mixer,
+                                      struct ring_buffer *ringbuffer, struct pcm_config cfg)
+{
+    struct ring_buf_desc *aux_inbuf = NULL;
+    int ret;
+
+    if (audio_mixer == NULL)
+        return -EINVAL;
+
+    aux_inbuf = &audio_mixer->aux_in_buf;
+    if (ringbuffer) {
+        aux_inbuf->buffer = ringbuffer;
+        audio_mixer->internal_aux = 0;
+    } else {
+        ret = aml_malloc_internal_ring_buffer (aux_inbuf, cfg);
+        if (ret < 0) {
+            return ret;
+        }
+
+        audio_mixer->internal_aux = 1;
+    }
+
+    aux_inbuf->cfg = cfg;
+    aux_inbuf->period_time = cfg.period_size * 1000 / cfg.rate;
+
+    return 0;
+}
+
+int aml_release_aux_in_buffer (struct aml_audio_mixer *audio_mixer)
+{
+    struct ring_buf_desc *aux_inbuf = NULL;
+//    int ret;
+
+    if (audio_mixer == NULL)
+        return -EINVAL;
+
+    aux_inbuf = &audio_mixer->aux_in_buf;
+
+    aml_free_internal_ring_buffer (aux_inbuf);
+    return 0;
+}
+
+int aml_write_mixer_main_in_buf (struct aml_audio_mixer *audio_mixer, void *buffer, size_t size)
+{
+    struct ring_buf_desc *main_inbuf = NULL;
+    struct ring_buffer *rbuffer = NULL;
+    int frames = 0;
+    int msleep_time = 0;
+ //   int ret = 0;
+
+    if (audio_mixer == NULL)
+        return -EINVAL;
+
+    main_inbuf = &audio_mixer->main_in_buf;
+    if (!main_inbuf->valid)
+        return -ENOENT;
+
+    rbuffer = main_inbuf->buffer;
+    frames = bytes_to_frames (main_inbuf->cfg, size);
+    // wait half time of the data size
+    msleep_time = main_inbuf->period_time / 8;
+    if (get_buffer_write_space (rbuffer) >= (int) size) {
+        ring_buffer_write (rbuffer, buffer, size, UNCOVER_WRITE);
+        //ALOGV("%s ...filling in buffer", __func__);
+        //pthread_cond_signal(&audio_mixer->cond);
+    } else {
+        ALOGI ("%s ... in buffer sleep %dms", __func__, msleep_time);
+        usleep (1000 * msleep_time);
+        return -EAGAIN;
+    }
+
+    return 0;
+}
+
+int aml_write_mixer_aux_in_buf (struct aml_audio_mixer *audio_mixer, void *buffer, size_t size)
+{
+    struct ring_buf_desc *aux_inbuf = NULL;
+    struct ring_buffer *rbuffer = NULL;
+//    int ret;
+
+    if (audio_mixer == NULL)
+        return -EINVAL;
+
+    aux_inbuf = &audio_mixer->aux_in_buf;
+    if (!aux_inbuf->valid)
+        return -ENOENT;
+
+    rbuffer = aux_inbuf->buffer;
+    // for aux in, just overwrite data if no enough space
+    ring_buffer_write (rbuffer, buffer, size, COVER_WRITE);
+    //if (get_buffer_write_space(rbuffer) > (int)size)
+    //    ring_buffer_write(rbuffer, buffer, size, UNCOVER_WRITE);
+    //else
+    //    return -EAGAIN;
+
+    return 0;
+}
+
+int aml_register_audio_mixer_callback (struct aml_audio_mixer *audio_mixer,
+                                       mixer_write_callback cbk, void *priv_data)
+{
+    if (audio_mixer == NULL)
+        return -EINVAL;
+
+    audio_mixer->mixer_out_write = cbk;
+    audio_mixer->priv_data = priv_data;
+    return 0;
+}
+
+int aml_release_audio_mixer_callback (struct aml_audio_mixer *audio_mixer)
+{
+    if (audio_mixer == NULL)
+        return -EINVAL;
+
+    audio_mixer->mixer_out_write = NULL;
+    audio_mixer->priv_data = NULL;
+    return 0;
+}
+
diff --git a/utils/aml_audio_resampler.c b/utils/aml_audio_resampler.c
new file mode 100644
index 0000000..e801840
--- /dev/null
+++ b/utils/aml_audio_resampler.c
@@ -0,0 +1,106 @@
+/*
+ * Copyright (C) 2017 Amlogic Corporation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <math.h>
+#include <cutils/log.h>
+#include <aml_audio_resampler.h>
+
+#undef  LOG_TAG
+#define LOG_TAG "aml_audio_resampler"
+
+//Clip from 16.16 fixed-point to 0.15 fixed-point.
+inline static short clip(int x) {
+    if (x < -32768) {
+        return -32768;
+    } else if (x > 32767) {
+        return 32767;
+    } else {
+        return x;
+    }
+}
+
+int resampler_init(struct resample_para *resample) {
+
+    ALOGD("%s, Init Resampler: input_sr = %d, output_sr = %d \n",
+        __FUNCTION__,resample->input_sr,resample->output_sr);
+
+    static const double kPhaseMultiplier = 1L << 28;
+    unsigned int i;
+
+    if (resample->channels > MAX_RESAMPLE_CHANNEL) {
+        ALOGE("Error: %s, max support channels: %d\n",
+        __FUNCTION__, MAX_RESAMPLE_CHANNEL);
+        return -1;
+    }
+
+    resample->FractionStep = (unsigned int) (resample->input_sr * kPhaseMultiplier
+                            / resample->output_sr);
+    resample->SampleFraction = 0;
+    for (i = 0; i < resample->channels; i++)
+        resample->lastsample[i] = 0;
+
+    return 0;
+}
+
+int resample_process(struct resample_para *resample, unsigned int in_frame,
+        int16_t* input, int16_t* output) {
+    unsigned int inputIndex = 0;
+    unsigned int outputIndex = 0;
+    unsigned int FractionStep = resample->FractionStep;
+    int16_t last_sample[MAX_RESAMPLE_CHANNEL];
+    unsigned int i;
+    unsigned int channels = resample->channels;
+
+    static const unsigned int kPhaseMask = (1LU << 28) - 1;
+    unsigned int frac = resample->SampleFraction;
+
+    for (i = 0; i < channels; i++)
+        last_sample[i] = resample->lastsample[i];
+
+
+    while (inputIndex == 0) {
+        for (i = 0; i < channels; i++) {
+            *output++ = clip((int) last_sample[i] +
+                ((((int) input[i] - (int) last_sample[i]) * ((int) frac >> 13)) >> 15));
+        }
+
+        frac += FractionStep;
+        inputIndex += (frac >> 28);
+        frac = (frac & kPhaseMask);
+        outputIndex++;
+    }
+
+    while (inputIndex < in_frame) {
+        for (i = 0; i < channels; i++) {
+            *output++ = clip((int) input[channels * (inputIndex - 1) + i] +
+                ((((int) input[channels * inputIndex + i]
+                - (int) input[channels * (inputIndex - 1) + i]) * ((int) frac >> 13)) >> 15));
+        }
+
+        frac += FractionStep;
+        inputIndex += (frac >> 28);
+        frac = (frac & kPhaseMask);
+        outputIndex++;
+    }
+
+    resample->SampleFraction = frac;
+
+    for (i = 0; i < channels; i++)
+        resample->lastsample[i] = input[channels * (in_frame - 1) + i];
+
+    return outputIndex;
+}
+
diff --git a/utils/aml_buffer_provider.c b/utils/aml_buffer_provider.c
new file mode 100755
index 0000000..02aa162
--- /dev/null
+++ b/utils/aml_buffer_provider.c
@@ -0,0 +1,120 @@
+/*
+ * hardware/amlogic/audio/utils/aml_buffer_provider.c
+ *
+ * Copyright (C) 2017 Amlogic, Inc. All rights reserved.
+ *
+ * This source code is subject to the terms and conditions defined in the
+ * file 'LICENSE' which is part of this source code package.
+ *
+ */
+
+#define LOG_TAG "buffer_provider"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <pthread.h>
+#include <errno.h>
+#include <string.h>
+#include <aml_ringbuffer.h>
+
+#define LPCM_BUFFER_SIZE       (2048*8*2)
+
+#define GENERAL_BUFFER_SIZE    (LPCM_BUFFER_SIZE*96) //in byte
+
+#define DDP_BUFFER_SIZE        16384 //in byte
+#define DD_61937_BUFFER_SIZE   16384
+
+
+struct ring_buffer general_buffer;
+struct ring_buffer DDP_out_buffer;
+struct ring_buffer DD_61937_buffer;
+
+/*************************************************
+Function: init_buffer_provider
+Description: initialize the buffers
+Input:
+Output:
+Return: 0 for success, otherwise fail
+*************************************************/
+int init_buffer_provider()
+{
+    memset(&general_buffer, 0, sizeof(struct ring_buffer));
+    memset(&DDP_out_buffer, 0, sizeof(struct ring_buffer));
+    memset(&DD_61937_buffer, 0, sizeof(struct ring_buffer));
+
+    pthread_mutex_init(&general_buffer.lock, NULL);
+    ring_buffer_init(&general_buffer, GENERAL_BUFFER_SIZE);
+
+    pthread_mutex_init(&DDP_out_buffer.lock, NULL);
+    ring_buffer_init(&DDP_out_buffer, DDP_BUFFER_SIZE);
+
+    pthread_mutex_init(&DD_61937_buffer.lock, NULL);
+    ring_buffer_init(&DD_61937_buffer, DD_61937_BUFFER_SIZE);
+
+    return 0;
+}
+
+/*************************************************
+Function: release_buffer_provider
+Description: release the buffers
+Input:
+Output:
+Return: 0 for success, otherwise fail
+*************************************************/
+int release_buffer_provider()
+{
+    ring_buffer_release(&general_buffer);
+    pthread_mutex_destroy(&general_buffer.lock);
+
+    ring_buffer_release(&DDP_out_buffer);
+    pthread_mutex_destroy(&DDP_out_buffer.lock);
+
+    ring_buffer_release(&DD_61937_buffer);
+    pthread_mutex_destroy(&DD_61937_buffer.lock);
+
+    return 0;
+}
+
+/*************************************************
+Function: get_general_buffer
+Description: get the general ring buffer
+Input:
+Output:
+Return: general ring buffer
+*************************************************/
+struct ring_buffer *get_general_buffer()
+{
+    return &general_buffer;
+}
+
+/*************************************************
+Function: get_DDP_buffer
+Description: get the DDP ring buffer
+Input:
+Output:
+Return: DDP ring buffer
+*************************************************/
+struct ring_buffer *get_DDP_buffer()
+{
+    return &DDP_out_buffer;
+}
+
+/*************************************************
+Function: get_DD_61937_buffer
+Description: get the DD ring buffer
+Input:
+Output:
+Return: DD ring buffer
+*************************************************/
+struct ring_buffer *get_DD_61937_buffer()
+{
+    return &DD_61937_buffer;
+}
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/utils/aml_configs/aml_conf_loader.c b/utils/aml_configs/aml_conf_loader.c
new file mode 100755
index 0000000..ea6d1b7
--- /dev/null
+++ b/utils/aml_configs/aml_conf_loader.c
@@ -0,0 +1,221 @@
+/*
+ * Copyright (C) 2017 Amlogic Corporation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ ** loader.c
+ **
+ ** This program is designed for load the config of product in HAL.
+ ** author: shen pengru
+ **
+ */
+#define LOG_TAG "aml_parser"
+
+#define LOG_NDEBUG 0
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <cutils/log.h>
+#include <aml_conf_loader.h>
+#include <aml_conf_parser.h>
+
+/*************************************************
+* TODO: this lib will be used in tvserver or
+* mediaserver so how to protect the *.conf
+* file here?
+*************************************************/
+
+
+/*************************************************
+Function: config_load()
+Description: load the config file of product
+Input:
+    file_name: the path of config file
+Output:
+Return: parser
+*************************************************/
+struct parser *aml_config_load(const char *file_name)
+{
+    struct parser *pParser = NULL;
+    int ret = 0;
+
+    pParser = malloc(sizeof(struct parser));
+    ret = parser_init(pParser);
+    if (ret) {
+       ALOGD("%s: parser_init fail\n", __func__);
+       goto init_fail;
+    }
+    ret = parser_load_from_file(pParser, file_name);
+    if (ret) {
+       ALOGD("%s: parser_load_from_file fail\n", __func__);
+       goto init_fail;
+    }
+    return pParser;
+
+init_fail:
+    if (pParser)
+        free(pParser);
+    return NULL;
+}
+
+/*************************************************
+Function: config_unload()
+Description: free memory for the config
+Input: null
+Output: null
+Return: 0 if success
+*************************************************/
+int aml_config_unload(struct parser *pParser)
+{
+    if (pParser != NULL) {
+        parser_delete(pParser);
+        free(pParser);
+    }
+    return 0;
+}
+
+/*************************************************
+Function:     aml_config_get_str()
+Description:  get value of index "key", in string
+Input:
+       pParser:
+       section:
+       key:       config index
+       def_value: default value to return
+Output:
+Return:
+*************************************************/
+const char *aml_config_get_str(struct parser *pParser, const char *section,  const char *key, const char *def_value)
+{
+    if (pParser == NULL) {
+        return def_value;
+    }
+    return parser_get_string(pParser, section, key, def_value);
+}
+
+/*************************************************
+Function:     aml_config_get_int()
+Description:  get value of index "key", in int
+Input:
+       pParser:
+       section:
+       key:       config index
+       def_value: default value to return
+Output:
+Return:
+*************************************************/
+int aml_config_get_int(struct parser *pParser, const char *section, const char *key, const int def_value)
+{
+    if (pParser == NULL) {
+        return def_value;
+    }
+    return parser_get_int(pParser, section, key, def_value);
+}
+
+/*************************************************
+Function:     aml_config_get_float()
+Description:  get value of index "key", in float
+Input:
+       pParser:
+       section:
+       key:       config index
+       def_value: default value to return
+Output:
+Return:
+*************************************************/
+float aml_config_get_float(struct parser *pParser, const char *section, const char *key, const float def_value)
+{
+    if (pParser == NULL) {
+        return def_value;
+    }
+    return parser_get_float(pParser, section, key, def_value);
+}
+
+/*************************************************
+Function:     aml_config_dump()
+Description:  dump valid content of the config file
+Input:
+       pParser:
+Output:       config content list
+Return:       0 if success
+*************************************************/
+int aml_config_dump(struct parser *pParser, const char *section)
+{
+    if (pParser == NULL) {
+        return -1;
+    }
+	return parser_dump(pParser, section);
+}
+
+#ifndef AML_CONFIG_SUPPORT_READ_ONLY
+/*************************************************
+Function:     aml_config_set_str()
+Description:  set key value
+Input:
+       pParser:
+       section:
+       key:
+       value:
+Output:
+Return:        0 if success
+*************************************************/
+int aml_config_set_str(struct parser *pParser, const char *section,  const char *key, const char *value)
+{
+    if (pParser == NULL) {
+        return -1;
+    }
+    return parser_set_string(pParser, section, key, value);
+}
+
+/*************************************************
+Function:     aml_config_set_int()
+Description:  set key value
+Input:
+       pParser:
+       section:
+       key:
+       value:
+Output:
+Return:        0 if success
+*************************************************/
+int aml_config_set_int(struct parser *pParser, const char *section,  const char *key, int value)
+{
+    if (pParser == NULL) {
+        return -1;
+    }
+    return parser_set_int(pParser, section, key, value);
+}
+
+/*************************************************
+Function:     aml_config_set_float()
+Description:  set key value
+Input:
+       pParser:
+       section:
+       key:
+       value:
+Output:
+Return:        0 if success
+*************************************************/
+int aml_config_set_float(struct parser *pParser, const char *section,  const char *key, float value)
+{
+    if (pParser == NULL) {
+        return -1;
+    }
+    return parser_set_float(pParser, section, key, value);
+}
+#endif
diff --git a/utils/aml_configs/aml_conf_parser.c b/utils/aml_configs/aml_conf_parser.c
new file mode 100755
index 0000000..3226b08
--- /dev/null
+++ b/utils/aml_configs/aml_conf_parser.c
@@ -0,0 +1,486 @@
+/*
+ * Copyright (C) 2017 Amlogic Corporation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ ** parser.c
+ **
+ ** This program is designed for load the config of product in HAL.
+ **  - base on config loader/parser in aml tvserver!!
+ ** author: aml&shen pengru
+ **
+ */
+#define LOG_TAG "aml_parser"
+
+#define LOG_NDEBUG 0
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <assert.h>
+#include <string.h>
+#include <ctype.h>
+#include <cutils/log.h>
+#include <aml_conf_parser.h>
+#include <errno.h>
+
+/*************************************************
+    Utils
+*************************************************/
+#define READ_BUFF 1024
+int _copy_file(const char *src_file_name, const char *des_file_name)
+{
+    int ret = 0;
+    int nread;
+    char buf[READ_BUFF];
+    FILE *fp_src = NULL;
+    FILE *fp_des = NULL;
+
+    if ((NULL == src_file_name) || (NULL == des_file_name)) {
+        ALOGE("[%s:%d]sourece file doesn't exist!\n", __FUNCTION__, __LINE__);
+        return -1;
+    }
+
+    fp_src = fopen(src_file_name, "r+");
+    if (NULL == fp_src) {
+        ALOGE("[%s:%d] %s error %s\n", __FUNCTION__, __LINE__, src_file_name, strerror(errno));
+        return -1;
+    }
+
+    fp_des = fopen(des_file_name, "a");
+    if (NULL == fp_des) {
+        ALOGE("[%s:%d] %s error %s\n", __FUNCTION__, __LINE__, des_file_name, strerror(errno));
+        ret = -1;
+        goto FAIL;
+    }
+
+#if 0
+    while ( nread = fread(buf, sizeof(char), READ_BUFF, fp_src)) {
+        fwrite(buf, sizeof(char), nread, fp_des);
+    }
+#else
+    do {
+        nread = fread(buf, sizeof(char), READ_BUFF, fp_src);
+        fwrite(buf, sizeof(char), nread, fp_des);
+    } while(nread);
+#endif
+
+    fclose(fp_des);
+FAIL:
+    fclose(fp_src);
+
+    return ret;
+}
+
+static void _delete_all_trim(char *Str)
+{
+    char *pStr;
+    pStr = strchr (Str, '\n');
+    if (pStr != NULL) {
+        *pStr = 0;
+    }
+    int Len = strlen(Str);
+    if ( Len > 0 ) {
+        if ( Str[Len - 1] == '\r' ) {
+            Str[Len - 1] = '\0';
+        }
+    }
+    pStr = Str;
+    while (*pStr != '\0') {
+        if (*pStr == ' ') {
+            char *pTmp = pStr;
+            while (*pTmp != '\0') {
+                *pTmp = *(pTmp + 1);
+                pTmp++;
+            }
+        } else {
+            pStr++;
+        }
+    }
+    return;
+}
+
+static eLineType _get_line_type(char *Str)
+{
+    eLineType type = LINE_TYPE_COMMENT;
+    if (strchr(Str, '#') != NULL) {
+        type = LINE_TYPE_COMMENT;
+    } else if ( (strstr (Str, "[") != NULL) && (strstr (Str, "]") != NULL) ) { /* Is Section */
+        type = LINE_TYPE_SECTION;
+    } else {
+        if (strstr (Str, "=") != NULL) {
+            type = LINE_TYPE_KEY;
+        } else {
+            type = LINE_TYPE_COMMENT;
+        }
+    }
+    return type;
+}
+
+static SECTION *_get_section(struct parser *pParser, const char *section)
+{
+    SECTION *psec = NULL;
+
+    if (pParser->mpFirstSection == NULL)
+        return NULL;
+
+    //section
+    for (psec = pParser->mpFirstSection; psec != NULL; psec = psec->pNext) {
+        if (strncmp((psec->pLine->Text) + 1, section, strlen(section)) == 0)
+            return psec;
+    }
+    return NULL;
+}
+
+static LINE *_get_key_line_at_sec(SECTION *pSec, const char *key)
+{
+    LINE *pline = NULL;
+    //line
+    for (pline = pSec->pLine->pNext; (pline != NULL && pline->type != LINE_TYPE_SECTION); pline = pline->pNext) {
+        if (pline->type == LINE_TYPE_KEY) {
+            if (strncmp(pline->Text, key, strlen(key)) == 0)
+                return pline;
+        }
+    }
+    return NULL;
+}
+
+/*************************************************
+    APIs
+*************************************************/
+int parser_init(struct parser *pParser)
+{
+    if (pParser != NULL) {
+        pParser->mpFirstSection = NULL;
+        pParser->mpFileName[0]  = '\0';
+        pParser->m_pIniFile     = NULL;
+        pParser->mpFirstLine    = NULL;
+        return 0;
+    }
+    return -1;
+}
+
+int parser_delete(struct parser *pParser)
+{
+    LINE    *pCurLine  = NULL;
+    LINE    *pNextLine = NULL;
+    SECTION *pCurSec   = NULL;
+    SECTION *pNextSec  = NULL;
+
+    //free all lines
+    for (pCurLine = pParser->mpFirstLine; pCurLine != NULL;) {
+        pNextLine = pCurLine->pNext;
+        free(pCurLine);
+        pCurLine = pNextLine;
+    }
+    pParser->mpFirstLine = NULL;
+
+    //free all sections
+    for (pCurSec = pParser->mpFirstSection; pCurSec != NULL;) {
+        pNextSec = pCurSec->pNext;
+        free(pCurSec);
+        pCurSec = pNextSec;
+    }
+    pParser->mpFirstSection = NULL;
+
+    return 0;
+}
+
+int parser_load_from_file(struct parser *pParser, const char *filename)
+{
+    char    lineStr[MAX_INI_FILE_LINE_LEN];
+    //char    *pStr;
+    LINE    *pCurLINE    = NULL;
+    SECTION *pCurSection = NULL;
+    char             *pM = NULL;
+    SECTION        *pSec = NULL;
+
+    // open the config file
+    ALOGD("%s: name = %s", __func__, filename);
+    if (filename == NULL) {
+        ALOGE("[%s:%d]\n", __func__, __LINE__);
+        return -1;
+    }
+    strcpy(pParser->mpFileName, filename);
+    pParser->m_pIniFile = fopen(pParser->mpFileName, "r");
+    if (pParser->m_pIniFile == NULL) {
+        // open default config file
+        ALOGE("[%s:%d]open file %s failed error %s\n", __func__, __LINE__, pParser->mpFileName, strerror(errno));
+        if (_copy_file(AML_PARAM_AUDIO_HAL_SYSTEM, pParser->mpFileName)) {
+            ALOGE("[%s:%d]\n", __func__, __LINE__);
+            return -1;
+        }
+        else {
+            // reopen
+            ALOGD("%s: copy config from system partition!\n", __func__);
+            pParser->m_pIniFile = fopen(pParser->mpFileName, "r");
+            if (pParser->m_pIniFile == NULL) {
+                ALOGE("[%s:%d] error %s\n", __func__, __LINE__, strerror(errno));
+                return -1;
+            }
+        }
+    }
+
+    // parse line by line
+    while (fgets(lineStr, MAX_INI_FILE_LINE_LEN, pParser->m_pIniFile) != NULL) {
+        /* remove invaild info */
+        _delete_all_trim(lineStr);
+
+        /* initial one new line structrue */
+        LINE *pLINE = malloc(sizeof(LINE));
+        pLINE->pKeyStart   = pLINE->Text;
+        pLINE->pKeyEnd     = pLINE->Text;
+        pLINE->pValueStart = pLINE->Text;
+        pLINE->pValueEnd   = pLINE->Text;
+        pLINE->pNext       = NULL;
+        pLINE->type        = _get_line_type(lineStr);
+        strcpy(pLINE->Text, lineStr);
+        pLINE->LineLen = strlen(pLINE->Text);
+
+        /* insert the the link */
+        if (pParser->mpFirstLine == NULL) {
+            pParser->mpFirstLine = pLINE;
+        } else {
+            pCurLINE->pNext = pLINE;
+        }
+        pCurLINE = pLINE;
+
+        /* real parser */
+        switch (pCurLINE->type) {
+        case LINE_TYPE_SECTION:
+            pSec = malloc(sizeof(SECTION));
+            pSec->pLine = pLINE;
+            pSec->pNext = NULL;
+            if (pParser->mpFirstSection == NULL) { //first section
+                pParser->mpFirstSection = pSec;
+            } else {
+                pCurSection->pNext = pSec;
+            }
+            pCurSection = pSec;
+            break;
+        case LINE_TYPE_KEY:
+            pM = strchr(pCurLINE->Text, '=');
+            pCurLINE->pKeyStart   = pCurLINE->Text;                         // Key, start in ->Text
+            pCurLINE->pKeyEnd     = pM - 1;                                 // Key, end   in ->Text
+            pCurLINE->pValueStart = pM + 1;                                 // Val, start in ->Text
+            pCurLINE->pValueEnd   = pCurLINE->Text + pCurLINE->LineLen - 1; // Val, end   in ->Text
+            break;
+        case LINE_TYPE_COMMENT:
+        default:
+            break;
+        }
+    }
+
+    fclose (pParser->m_pIniFile);
+    pParser->m_pIniFile = NULL;
+    return 0;
+}
+
+int parser_dump(struct parser *pParser, const char *section)
+{
+    LINE *pline = NULL;
+    SECTION *pSec = NULL;
+
+    ALOGD("%s: === start to dump %s ===\n", __func__, pParser->mpFileName);
+
+    pSec = _get_section(pParser, section);
+    if (pSec == NULL)
+        return -1;
+
+    for (pline=pSec->pLine; pline!=NULL; pline=pline->pNext) {
+        if (pline != NULL) {
+            if (pSec->pNext != NULL && pline == pSec->pNext->pLine) {
+                break;
+            }
+        }
+        if (pline->type == LINE_TYPE_KEY) {
+            printf("%s\n", pline->Text);
+        }
+    }
+
+    ALOGD("%s: === dump over %s ===\n", __func__, pParser->mpFileName);
+
+	return 0;
+}
+
+const char *parser_get_string(struct parser *pParser, const char *section, const char *key, const char *def_value)
+{
+    SECTION *pSec = _get_section(pParser, section);
+    if (pSec == NULL)
+        return def_value;
+
+    LINE *pLine = _get_key_line_at_sec(pSec, key);
+    if (pLine == NULL)
+        return def_value;
+
+    return pLine->pValueStart;
+}
+
+int parser_get_int(struct parser *pParser, const char *section, const char *key, int def_value)
+{
+    const char *num = parser_get_string(pParser, section, key, NULL);
+    if (num != NULL) {
+        return atoi(num);
+    }
+    return def_value;
+}
+
+float parser_get_float(struct parser *pParser, const char *section, const char *key, float def_value)
+{
+    const char *num = parser_get_string(pParser, section, key, NULL);
+    if (num != NULL) {
+        return atof(num);
+    }
+    return def_value;
+}
+
+#ifndef AML_CONFIG_SUPPORT_READ_ONLY
+static int _save_to_file(struct parser *pParser, const char *filename)
+{
+	const char *filepath = NULL;
+	FILE *pFile = NULL;
+
+	if (filename == NULL) {
+		if (strlen(pParser->mpFileName) == 0) {
+			ALOGD("error save file is null");
+			return -1;
+		} else {
+			filepath = pParser->mpFileName;
+		}
+	} else {
+		filepath = filename;
+	}
+
+	if ((pFile = fopen (filepath, "wb")) == NULL) {
+		ALOGD("Save to file open error = %s", filepath);
+		return -1;
+	}
+
+	LINE *pCurLine = NULL;
+	for (pCurLine = pParser->mpFirstLine; pCurLine != NULL; pCurLine = pCurLine->pNext) {
+		fprintf (pFile, "%s\r\n", pCurLine->Text);
+	}
+
+	fflush(pFile);
+	fsync(fileno(pFile));
+	fclose(pFile);
+
+	return 0;
+}
+
+static int _insert_section(struct parser *pParser, SECTION *pSec)
+{
+	//insert it to sections list ,as first section
+	pSec->pNext             = pParser->mpFirstSection;
+	pParser->mpFirstSection = pSec;
+
+	//insert it to lines list, at first
+	pSec->pLine->pNext      = pParser->mpFirstLine;
+	pParser->mpFirstLine    = pSec->pLine;
+
+	return 0;
+}
+
+static int _insert_keyline(SECTION *pSec, LINE *line)
+{
+	LINE *line1 = pSec->pLine;
+	LINE *line2 = line1->pNext;
+
+	line1->pNext = line;
+	line->pNext  = line2;
+
+	return 0;
+}
+
+int parser_set_string(struct parser *pParser, const char *section, const char *key, const char *value)
+{
+	SECTION *pFindSec    = NULL;
+
+	SECTION *pNewSec     = NULL;
+	LINE    *pNewSecLine = NULL;
+	LINE    *pNewKeyLine = NULL;
+
+	pFindSec = _get_section(pParser, section);
+	if (pFindSec == NULL) {
+		/* CASE_1: can't find section. new section, new line */
+		pNewSec     = malloc(sizeof(SECTION));
+		pNewSecLine = malloc(sizeof(LINE));
+		pNewKeyLine = malloc(sizeof(LINE));
+		pNewKeyLine->type = LINE_TYPE_KEY;
+		pNewSecLine->type = LINE_TYPE_SECTION;
+		sprintf(pNewSecLine->Text, "[%s]", section);
+		pNewSec->pLine = pNewSecLine;
+		// section insert
+		_insert_section(pParser, pNewSec);
+
+		int keylen = strlen(key);
+		sprintf(pNewKeyLine->Text, "%s=%s", key, value);
+		pNewKeyLine->LineLen     = strlen(pNewKeyLine->Text);
+		pNewKeyLine->pKeyStart   = pNewKeyLine->Text;
+		pNewKeyLine->pKeyEnd     = pNewKeyLine->pKeyStart + keylen               - 1;
+		pNewKeyLine->pValueStart = pNewKeyLine->pKeyStart + keylen               + 1;
+		pNewKeyLine->pValueEnd   = pNewKeyLine->Text      + pNewKeyLine->LineLen - 1;
+		// line insert
+		_insert_keyline(pNewSec, pNewKeyLine);
+	} else {
+		/* CASE_2: find out the section */
+		LINE *pLine = _get_key_line_at_sec(pFindSec, key);
+		if (pLine == NULL) {
+			/* CASE_2.1: can't find line. new line */
+			pNewKeyLine       = malloc(sizeof(LINE));
+			pNewKeyLine->type = LINE_TYPE_KEY;
+			int keylen = strlen(key);
+			sprintf(pNewKeyLine->Text, "%s=%s", key, value);
+			pNewKeyLine->LineLen     = strlen(pNewKeyLine->Text);
+			pNewKeyLine->pKeyStart   = pNewKeyLine->Text;
+			pNewKeyLine->pKeyEnd     = pNewKeyLine->pKeyStart + keylen               - 1;
+			pNewKeyLine->pValueStart = pNewKeyLine->pKeyStart + keylen               + 1;
+			pNewKeyLine->pValueEnd   = pNewKeyLine->Text      + pNewKeyLine->LineLen - 1;
+
+			// line insert
+			_insert_keyline(pFindSec, pNewKeyLine);
+		} else {
+			/* CASE_2.2: find out the section&line */
+			sprintf(pLine->Text, "%s=%s", key, value);
+			pLine->LineLen   = strlen(pLine->Text);
+			pLine->pValueEnd = pLine->Text + pLine->LineLen - 1;
+		}
+	}
+
+	//save
+	_save_to_file(pParser, NULL);
+
+	return 0;
+}
+
+int parser_set_int(struct parser *pParser, const char *section, const char *key, int value)
+{
+	char tmp[64];
+
+	sprintf(tmp, "%d", value);
+	parser_set_string(pParser, section, key, tmp);
+
+	return 0;
+}
+
+int parser_set_float(struct parser *pParser, const char *section, const char *key, float value)
+{
+	char tmp[64];
+
+	sprintf(tmp, "%.2f", value);
+	parser_set_string(pParser, section, key, tmp);
+
+	return 0;
+}
+#endif
diff --git a/utils/aml_configs/backup/aml_audio_hal_product_cfg.c b/utils/aml_configs/backup/aml_audio_hal_product_cfg.c
new file mode 100755
index 0000000..163f9c8
--- /dev/null
+++ b/utils/aml_configs/backup/aml_audio_hal_product_cfg.c
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2017 Amlogic Corporation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ ** aml_audio_hal_product_cfg.c
+ **
+ ** This program is designed for load the tvconfig section [AUDIO_HAL].
+ ** author: shen pengru
+ **
+ */
+#define LOG_TAG "aml_halcfg_parser"
+
+#define LOG_NDEBUG 0
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <cutils/log.h>
+#include "loader.h"
+#include "parser.h"
+
+// APIs for load/unload tvconfig
+struct parser *aml_hal_config_load(const char *file_name)
+{
+	return aml_config_load(file_name);
+}
+
+int aml_hal_config_unload(struct parser *pParser)
+{
+	return aml_config_unload(pParser);
+}
+
+int aml_hal_config_dump(struct parser *pParser)
+{
+    return aml_config_dump(pParser, "AUDIO_HAL");
+}
+
+// APIs for get value
+const char *aml_hal_cfg_get_str(struct parser *pParser, const char *key, const char *def_value)
+{
+	return aml_config_get_str(pParser, "AUDIO_HAL", key, def_value);
+}
+
+int aml_hal_config_get_int(struct parser *pParser, const char *key, const int def_value)
+{
+    return aml_config_get_int(pParser, "AUDIO_HAL", key, def_value);
+}
+
+float aml_hal_config_get_float(struct parser *pParser, const char *key, const float def_value)
+{
+    return aml_config_get_float(pParser, "AUDIO_HAL", key, def_value);
+}
diff --git a/utils/aml_configs/test/Android.mk b/utils/aml_configs/test/Android.mk
new file mode 100755
index 0000000..bd538fa
--- /dev/null
+++ b/utils/aml_configs/test/Android.mk
@@ -0,0 +1,23 @@
+# Copyright 2005 The Android Open Source Project
+
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_C_INCLUDES := \
+    hardware/$(PLATFORM_NAME)/audio/utils/include
+
+LOCAL_SRC_FILES:= \
+    load.c
+
+LOCAL_MODULE:= loadconfig
+
+#LOCAL_FORCE_STATIC_EXECUTABLE := true
+#LOCAL_MODULE_PATH := $(TARGET_ROOT_OUT)
+#LOCAL_UNSTRIPPED_PATH := $(TARGET_ROOT_OUT_UNSTRIPPED)
+
+LOCAL_SHARED_LIBRARIES := \
+        libcutils \
+        libc \
+        libamaudioutils
+
+include $(BUILD_EXECUTABLE)
diff --git a/utils/aml_configs/test/load.c b/utils/aml_configs/test/load.c
new file mode 100755
index 0000000..051e21e
--- /dev/null
+++ b/utils/aml_configs/test/load.c
@@ -0,0 +1,81 @@
+/*
+ * Copyright (C) 2017 Amlogic Corporation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <getopt.h>
+#include <errno.h>
+#include <aml_conf_loader.h>
+#include <aml_conf_parser.h>
+
+int main( int argc, char** argv )
+{
+	unsigned char ver[2];
+	struct parser *gParser = NULL;
+    unsigned char *index = "audio.pre.gain.for.av";
+	gParser = aml_config_load(AML_PARAM_AUDIO_HAL_PARAM);
+    if (gParser != NULL) {
+        //section dump
+        //printf("\n[Dump TV Section]\n\n");
+		//aml_config_dump(gParser, "TV");
+        //printf("\n[Dump ATV Section]\n\n");
+		//aml_config_dump(gParser, "ATV");
+        //get string value
+        printf("index: %s, string  value: %s\n",
+            index,
+            aml_config_get_str(gParser, "TV", index, NULL));
+        //get int value
+        printf("index: %s, integer value: %d\n",
+            index,
+            aml_config_get_int(gParser, "TV", index, NULL));
+        //get int value
+        printf("index: %s, integer value: %d\n",
+            "audiohal.lfe.gain",
+            aml_config_get_int(gParser, "AUDIO_HAL", "audiohal.lfe.gain", NULL));
+
+        printf("\n[Dump AUDIO_HAL Section][0]\n\n");
+		aml_config_dump(gParser, "AUDIO_HAL");
+
+#if 0
+		aml_config_set_str(gParser, "AUDIO_HAL", "audiohal.lfe.gain",  "15");
+		aml_config_set_int(gParser, "AUDIO_HAL", "audiohal.lfe.cutoff", 120);
+		aml_config_set_float(gParser, "AUDIO_HAL", "audiohal.lfe.invert", 5.12);
+        printf("\n[Dump AUDIO_HAL Section][1]\n\n");
+		aml_config_dump(gParser, "AUDIO_HAL");
+
+		aml_config_set_str(gParser, "AUDIO_HAL", "audiohal.lfe.gain",  "10");
+		aml_config_set_int(gParser, "AUDIO_HAL", "audiohal.lfe.cutoff", 150);
+		aml_config_set_float(gParser, "AUDIO_HAL", "audiohal.lfe.invert", 3.1415926);
+        printf("\n[Dump AUDIO_HAL Section][2]\n\n");
+		aml_config_dump(gParser, "AUDIO_HAL");
+
+		aml_config_set_str(gParser, "AUDIO_HAL", "audiohal.lfe.gain",   "");
+		aml_config_set_str(gParser, "AUDIO_HAL", "audiohal.lfe.cutoff", "");
+		aml_config_set_str(gParser, "AUDIO_HAL", "audiohal.lfe.invert", "");
+        printf("\n[Dump AUDIO_HAL Section][3]\n\n");
+		aml_config_dump(gParser, "AUDIO_HAL");
+#endif
+        //unload
+        aml_config_unload(gParser);
+	}
+
+	return 0;
+}
diff --git a/utils/aml_configs/test/tvaudiohal.conf b/utils/aml_configs/test/tvaudiohal.conf
new file mode 100755
index 0000000..66b0866
--- /dev/null
+++ b/utils/aml_configs/test/tvaudiohal.conf
@@ -0,0 +1,66 @@
+[AUDIO_HAL]
+
+#
+#### channel map need move to *.dts in kernel
+#
+
+# hardware channel map@i2s port
+i2s.channel0=left
+i2s.channel1=right
+i2s.channel2=center
+i2s.channel3=lfe
+i2s.channel4=left_top
+i2s.channel5=right_top
+i2s.channel6=left_surround
+i2s.channel7=right_urround
+
+# if need invert the data before send to i2s port
+i2s.invert.channel0=0
+i2s.invert.channel0=0
+i2s.invert.channel0=0
+i2s.invert.channel0=0
+i2s.invert.channel0=0
+i2s.invert.channel0=0
+i2s.invert.channel0=0
+i2s.invert.channel0=0
+
+#
+#### dap
+#
+
+# enable aml software dap process
+aml.dap.enable=0
+
+#
+#### lfe
+#
+
+# enable aml iir
+aml.iir.enable=1
+
+
+#
+#### others
+#
+
+# if have real center channel
+speaker.center.enable=1
+
+
+#
+#### ditter, only need on ATMOS dsp now
+#
+
+# if need ditter on i2s data
+i2s.ditter.enable=1
+
+# enable ditter@i2s channel
+i2s.ditter.channel0=1
+i2s.ditter.channel1=1
+i2s.ditter.channel2=1
+i2s.ditter.channel3=1
+i2s.ditter.channel4=1
+i2s.ditter.channel5=1
+i2s.ditter.channel6=1
+i2s.ditter.channel7=1
+
diff --git a/utils/aml_data_utils.c b/utils/aml_data_utils.c
new file mode 100755
index 0000000..2a096da
--- /dev/null
+++ b/utils/aml_data_utils.c
@@ -0,0 +1,1166 @@
+/**
+ ** aml_data_utils.c
+ **
+ ** This program is the factory of PCM data. Such as,
+ **        re-mix
+ **        extend
+ **        extract
+ **        exchange
+ **        invert
+ **        concat
+ **        empty
+ **        ditter
+ **        replace
+ ** author: shen pengru
+ */
+#define LOG_TAG "audio_data_utils"
+//#define LOG_NDEBUG 0
+
+#include <stdlib.h>
+#include <stdint.h>
+#include <unistd.h>
+#include <string.h>
+#include <errno.h>
+#include <cutils/log.h>
+#include <fcntl.h>
+#include <math.h>
+#include <aml_data_utils.h>
+#include <aml_audio_hal_conf.h>
+#include <aml_conf_parser.h>
+#include <aml_conf_loader.h>
+
+#if defined (BUILDHOSTEXE)
+//#define DEBUG
+#ifdef DEBUG
+#define AMLOGE printf
+#define AMLOGD printf
+#else
+#define AMLOGE
+#define AMLOGD
+#endif
+#else
+#define AMLOGE ALOGE
+#define AMLOGD ALOGD
+#endif
+
+static struct aml_audio_channel_name gAudioChName[] = {
+	{AML_CH_IDX_L,   "left"},
+	{AML_CH_IDX_R,   "right"},
+	{AML_CH_IDX_C,   "center"},
+	{AML_CH_IDX_LFE, "lfe"},
+	{AML_CH_IDX_LS,  "left_surround"},
+	{AML_CH_IDX_RS,  "right_urround"},
+	{AML_CH_IDX_LT,  "left_top"},
+	{AML_CH_IDX_RT,  "right_top"},
+};
+
+static int _name_trans_to_i2s_chidx(const char *name)
+{
+	if (!strcmp(name, gAudioChName[0].ch_name)) {
+		return gAudioChName[0].ch_idx;
+	} else if (!strcmp(name, gAudioChName[1].ch_name)) {
+		return gAudioChName[1].ch_idx;
+	} else if (!strcmp(name, gAudioChName[2].ch_name)) {
+		return gAudioChName[2].ch_idx;
+	} else if (!strcmp(name, gAudioChName[3].ch_name)) {
+		return gAudioChName[3].ch_idx;
+	} else if (!strcmp(name, gAudioChName[4].ch_name)) {
+		return gAudioChName[4].ch_idx;
+	} else if (!strcmp(name, gAudioChName[5].ch_name)) {
+		return gAudioChName[5].ch_idx;
+	} else if (!strcmp(name, gAudioChName[6].ch_name)) {
+		return gAudioChName[6].ch_idx;
+	} else if (!strcmp(name, gAudioChName[7].ch_name)) {
+		return gAudioChName[7].ch_idx;
+	}
+	return AML_CH_IDX_NULL;
+}
+
+static inline int16_t _clamp16(int32_t sample)
+{
+    if ((sample>>15) ^ (sample>>31))
+        sample = 0x7FFF ^ (sample>>31);
+    return sample;
+}
+
+/*
+static inline int32_t _clamp32(int64_t sample)
+{
+    //TODO:
+    return sample;
+}
+*/
+
+static char *_get_ch_name(eChannelContentIdx idx)
+{
+	int i = 0;
+	int cnt = 0;
+
+	cnt = sizeof(gAudioChName)/sizeof(struct aml_audio_channel_name);
+
+	for (i=AML_CH_IDX_L; i<AML_I2S_CHANNEL_COUNT; i++) {
+		if (idx == gAudioChName[i].ch_idx) {
+			return gAudioChName[i].ch_name;
+		}
+	}
+
+	switch (idx) {
+	case AML_CH_IDX_5_1_ALL:
+		return "5.1Ch";
+	case AML_CH_IDX_7_1_ALL:
+		return "7.1Ch";
+	case AML_CH_IDX_5_1_2_ALL:
+		return "5.1.2Ch";
+	default:
+		break;
+	}
+
+	return "Invalid";
+}
+
+#define SHENPENGRU_TEST (0)
+
+#if SHENPENGRU_TEST
+struct aml_channel_map test_maps[] = {
+	{AML_CH_IDX_L,   AML_I2S_PORT_IDX_01,   AML_I2S_CHANNEL_0},
+	{AML_CH_IDX_R,   AML_I2S_PORT_IDX_01,   AML_I2S_CHANNEL_1},
+	{AML_CH_IDX_C,   AML_I2S_PORT_IDX_23,   AML_I2S_CHANNEL_2},
+	{AML_CH_IDX_LFE, AML_I2S_PORT_IDX_23,   AML_I2S_CHANNEL_3},
+	{AML_CH_IDX_LS,  AML_I2S_PORT_IDX_67,   AML_I2S_CHANNEL_6},
+	{AML_CH_IDX_RS,  AML_I2S_PORT_IDX_67,   AML_I2S_CHANNEL_7},
+	{AML_CH_IDX_LT,  AML_I2S_PORT_IDX_45,   AML_I2S_CHANNEL_4},
+	{AML_CH_IDX_RT,  AML_I2S_PORT_IDX_45,   AML_I2S_CHANNEL_5},
+};
+#endif
+
+static char *_get_ch_conf_name(int type, int content_idx)
+{
+	switch (type) {
+	case eAmlConfTypeChMap:
+		switch (content_idx) {
+		case AML_CH_IDX_L:
+			return AML_I2S_CHANNEL0;
+		case AML_CH_IDX_R:
+			return AML_I2S_CHANNEL1;
+		case AML_CH_IDX_C:
+			return AML_I2S_CHANNEL2;
+		case AML_CH_IDX_LFE:
+			return AML_I2S_CHANNEL3;
+		case AML_CH_IDX_LS:
+			return AML_I2S_CHANNEL4;
+		case AML_CH_IDX_RS:
+			return AML_I2S_CHANNEL5;
+		case AML_CH_IDX_LT:
+			return AML_I2S_CHANNEL6;
+		case AML_CH_IDX_RT:
+			return AML_I2S_CHANNEL7;
+		default:
+			break;
+		}
+		break;
+	case eAmlConfTypeChInv:
+		switch (content_idx) {
+		case AML_CH_IDX_L:
+			return AML_I2S_INVERT_CH0;
+		case AML_CH_IDX_R:
+			return AML_I2S_INVERT_CH1;
+		case AML_CH_IDX_C:
+			return AML_I2S_INVERT_CH2;
+		case AML_CH_IDX_LFE:
+			return AML_I2S_INVERT_CH3;
+		case AML_CH_IDX_LS:
+			return AML_I2S_INVERT_CH4;
+		case AML_CH_IDX_RS:
+			return AML_I2S_INVERT_CH5;
+		case AML_CH_IDX_LT:
+			return AML_I2S_INVERT_CH6;
+		case AML_CH_IDX_RT:
+			return AML_I2S_INVERT_CH7;
+		default:
+			break;
+		}
+		break;
+	case eAmlConfTypeChDit:
+		switch (content_idx) {
+		case AML_CH_IDX_L:
+			return AML_DITTER_I2S_CH0;
+		case AML_CH_IDX_R:
+			return AML_DITTER_I2S_CH1;
+		case AML_CH_IDX_C:
+			return AML_DITTER_I2S_CH2;
+		case AML_CH_IDX_LFE:
+			return AML_DITTER_I2S_CH3;
+		case AML_CH_IDX_LS:
+			return AML_DITTER_I2S_CH4;
+		case AML_CH_IDX_RS:
+			return AML_DITTER_I2S_CH5;
+		case AML_CH_IDX_LT:
+			return AML_DITTER_I2S_CH6;
+		case AML_CH_IDX_RT:
+			return AML_DITTER_I2S_CH7;
+		default:
+			break;
+		}
+		break;
+	default:
+		break;
+	}
+
+	return NULL;
+}
+
+static int _save_conf_to_maps(struct aml_channel_map *maps,
+			int content_idx, int ch_num, int invert, int ditter)
+{
+	int i = 0;
+
+	for (i=AML_CH_IDX_L; i<AML_CH_IDX_MAX; i++) {
+		if (content_idx == maps[i].channel_idx) {
+			maps[i].i2s_idx   = ch_num/2;
+			maps[i].bit_mask |= AML_I2S_CHANNEL_0<<ch_num;
+			maps[i].invert   |= invert<<ch_num;
+			maps[i].ditter   |= ditter<<ch_num;
+		}
+	}
+
+	return 0;
+}
+
+#if !defined (BUILDHOSTEXE)
+/* WARNNING: initial function, only need called once!! */
+struct aml_channel_map *data_load_product_config(void)
+{
+	struct parser *gParser = NULL;
+	char   chname[50];
+	struct aml_channel_map *maps = NULL;
+	int i = 0;
+	int find_idx, invert, ditter;
+
+	maps = malloc(sizeof(struct aml_channel_map)*AML_I2S_CHANNEL_COUNT);
+	if (!maps) {
+		return NULL;
+	} else {
+		maps[AML_CH_IDX_L].channel_idx   = AML_CH_IDX_L;
+		maps[AML_CH_IDX_R].channel_idx   = AML_CH_IDX_R;
+		maps[AML_CH_IDX_C].channel_idx   = AML_CH_IDX_C;
+		maps[AML_CH_IDX_LFE].channel_idx = AML_CH_IDX_LFE;
+		maps[AML_CH_IDX_LS].channel_idx  = AML_CH_IDX_LS;
+		maps[AML_CH_IDX_RS].channel_idx  = AML_CH_IDX_RS;
+		maps[AML_CH_IDX_LT].channel_idx  = AML_CH_IDX_LT;
+		maps[AML_CH_IDX_RT].channel_idx  = AML_CH_IDX_RT;
+	}
+
+	gParser = aml_config_load(AML_PARAM_AUDIO_HAL_PARAM);
+	if (gParser != NULL) {
+		// loop of i2s channel [0, 8]
+		for (i=0; i<AML_CH_IDX_MAX; i++) {
+			strcpy(chname, aml_config_get_str(gParser, AML_SECTION_AUDIO_HAL,
+						_get_ch_conf_name(eAmlConfTypeChMap, i), NULL));
+			invert   = aml_config_get_int(gParser, AML_SECTION_AUDIO_HAL,
+						_get_ch_conf_name(eAmlConfTypeChInv, i), 0);
+			ditter   = aml_config_get_int(gParser, AML_SECTION_AUDIO_HAL,
+						_get_ch_conf_name(eAmlConfTypeChDit, i), 0);
+			find_idx = _name_trans_to_i2s_chidx(chname);
+			_save_conf_to_maps(maps, find_idx, i, invert, ditter);
+		}
+		// unload
+		aml_config_unload(gParser);
+	}
+
+	return maps;
+}
+#endif
+
+int data_get_channel_i2s_port(
+	struct aml_channel_map *map, eChannelContentIdx channelName)
+{
+	int i = 0;
+
+	if (map == NULL) {
+		return AML_I2S_PORT_IDX_NULL;
+	}
+
+	for (i=AML_CH_IDX_L; i<AML_CH_IDX_MAX; i++) {
+		if (map[i].channel_idx == channelName) {
+			AMLOGD("%s: %s <-> i2s-port: %d\n", __func__,
+				_get_ch_name(channelName),
+				map[i].i2s_idx);
+			return map[i].i2s_idx;
+		}
+	}
+
+	return AML_I2S_PORT_IDX_NULL;
+}
+
+int data_get_channel_bit_mask(
+	struct aml_channel_map *map, eChannelContentIdx channelName)
+{
+	int i = 0;
+	int bit_mask = AML_I2S_CHANNEL_NULL;
+
+	if (map == NULL) {
+		return bit_mask;
+	}
+
+	for (i=AML_CH_IDX_L; i<AML_CH_IDX_MAX; i++) {
+		if (map[i].channel_idx == channelName) {
+			bit_mask = map[i].bit_mask;
+			AMLOGD("%s: %s <-> i2s-bit-mask: 0x%08x\n", __func__,
+				_get_ch_name(channelName),
+				bit_mask);
+			return bit_mask;
+		}
+	}
+
+	switch (channelName) {
+	case AML_CH_IDX_5_1_ALL:
+	case AML_CH_IDX_7_1_ALL:
+	case AML_CH_IDX_5_1_2_ALL:
+		for (i=0; i<AML_CH_IDX_MAX; i++) {
+			bit_mask |= map[i].bit_mask;
+		}
+		AMLOGD("%s: %s <-> i2s-bit-mask: 0x%08x\n", __func__,
+			_get_ch_name(channelName),
+			bit_mask);
+		return bit_mask;
+	default:
+		break;
+	}
+
+	return bit_mask;
+}
+
+eChannelContentIdx data_get_channel_content_idx(
+	struct aml_channel_map *map, int bitmask)
+{
+	int idx = AML_CH_IDX_NULL;
+	int i = 0;
+//	int bit_mask = AML_I2S_CHANNEL_NULL;
+
+	if (map == NULL) {
+		return idx;
+	}
+
+	for (i=AML_CH_IDX_L; i<AML_CH_IDX_MAX; i++) {
+		if (map[i].bit_mask & bitmask) {
+			idx = map[i].channel_idx;
+			AMLOGD("%s: i2s-bit-mask: 0x%08x <-> %s\n", __func__,
+				bitmask,
+				_get_ch_name(idx));
+			break;
+		}
+	}
+
+	return idx;
+}
+
+static int _data_remix_center_to_lr(void *buf, size_t frames, size_t framesz, int channels, int bitmask)
+{
+	int16_t center16;
+//	int32_t center32;
+	int16_t *buf16  = (int16_t *)buf;
+//	int32_t *buf32  = (int32_t *)buf;
+	int     i, tmp;
+
+	///< TODO: should use bitmask to find the center channel
+	if (bitmask == AML_I2S_CHANNEL_NULL)
+		return 0;
+
+	///< TODO: buf is 6ch pcm(L,R,C,lfe,Lr,Rs)
+	if (channels != 6) {
+		AMLOGD("%s: only support 6 ch now!\n", __func__);
+		return -1;
+	}
+
+	///< TODO:
+	if (framesz != e16BitPerSample) {
+		AMLOGD("%s: only support 16bit now!\n", __func__);
+		return -1;
+	}
+
+	switch (framesz) {
+	case e16BitPerSample:
+		///< 3/0 input L_out/R_out =  = 0.707*(L/R + 0.707*C);
+		for (i=0; i<(int)frames; i++) {
+			/* save data of center */
+			center16 = buf16[channels*i + 2];
+			/* calculate L */
+			tmp                   = buf16[channels*i + 0] << 12;
+			buf16[channels*i + 0] = _clamp16((MINUS_3_DB_IN_Q19_12 * ((tmp + MINUS_3_DB_IN_Q19_12*center16) >>12))>>12);
+			/* calculate R */
+			tmp                   = buf16[channels*i + 1] << 12;
+			buf16[channels*i + 1] = _clamp16((MINUS_3_DB_IN_Q19_12 * ((tmp + MINUS_3_DB_IN_Q19_12*center16) >>12))>>12);
+		}
+		break;
+	case e32BitPerSample:
+		//TODO:
+		break;
+	default:
+		break;
+	}
+
+	return 0;
+}
+
+static int _data_remix_all_to_lr(void *buf,	size_t frames, size_t framesz, int channels, int bitmask)
+{
+    /*
+     * --------------------------------------
+     * 3/2 input module:
+     * L_out = 0.707*(L + 0.707*C + 0.707*Ls)
+     * R_out = 0.707*(R + 0.707*C + 0.707*Rs)
+     * --------------------------------------
+     * our channel sequeces:
+     * 0->L
+     * 1->R
+     * 2->C
+     * 3->lfe
+     * 4->Ls
+     * 5->Rs
+     * --------------------------------------
+     */
+	int16_t l_16, r_16, c_16, ls_16, rs_16;
+//	int16_t l_32, r_32, c_32, ls_32, rs_32;
+	int16_t *buf16  = (int16_t *)buf;
+//	int32_t *buf32  = (int32_t *)buf;
+	int     i, tmp;
+
+	if (!bitmask)
+		return 0;
+
+	///< buf is 6ch pcm(L,R,C,lfe,Lr,Rs)
+	if (channels != 6) {
+		AMLOGD("%s: only support 6 ch now!\n", __func__);
+		return -1;
+	}
+
+	///< TODO:
+	if (framesz != e16BitPerSample) {
+		AMLOGD("%s: only support 16bit now!\n", __func__);
+		return -1;
+	}
+
+	switch (framesz) {
+	case e16BitPerSample:
+		for (i = 0; i < (int)frames; i++) {
+			/* save l/r/c/ls/rs */
+			l_16  = buf16[channels*i + 0];
+			r_16  = buf16[channels*i + 1];
+			c_16  = buf16[channels*i + 2];
+			ls_16 = buf16[channels*i + 4];
+			rs_16 = buf16[channels*i + 5];
+			/* handle L channel */
+			tmp = l_16 << 12;
+			buf16[channels*i] =
+				_clamp16((MINUS_3_DB_IN_Q19_12 * ((tmp + MINUS_3_DB_IN_Q19_12 * c_16 + MINUS_3_DB_IN_Q19_12 * ls_16) >> 12)) >> 12);
+			/* handle R channel */
+			tmp = r_16 << 12;
+			buf16[channels*i + 1] =
+				_clamp16((MINUS_3_DB_IN_Q19_12 * ((tmp + MINUS_3_DB_IN_Q19_12 * c_16 + MINUS_3_DB_IN_Q19_12 * rs_16) >> 12)) >> 12);
+		}
+		break;
+	case e32BitPerSample:
+		//TODO:
+		break;
+	default:
+		break;
+	}
+
+	return 0;
+}
+
+int data_remix_to_lr_channel(
+	struct  aml_channel_map *map,
+	void    *buf,
+	size_t  frames,
+	size_t  framesz,
+	int     channels,
+	eChannelContentIdx chIdx)
+{
+    int bit_mask = data_get_channel_bit_mask(map, chIdx);
+
+	switch (chIdx) {
+	case AML_CH_IDX_C:
+		return _data_remix_center_to_lr(buf, frames, framesz, channels, bit_mask);
+	case AML_CH_IDX_5_1_ALL:
+	case AML_CH_IDX_7_1_ALL:
+	case AML_CH_IDX_5_1_2_ALL:
+		return _data_remix_all_to_lr(buf, frames, framesz, channels, bit_mask);
+	default:
+		break;
+	}
+
+	return 0;
+}
+
+int data_empty_channels(
+	struct  aml_channel_map *map,
+	void    *buf,
+	size_t  frames,
+	size_t  framesz,
+	int     channels,
+	int     channel_empty_bit_mask)
+{
+	int i, j;
+	int16_t *buf16 = (int16_t *)buf;
+	int32_t *buf32 = (int32_t *)buf;
+
+	if (!map)
+		return 0;
+
+	switch (framesz) {
+	case e16BitPerSample:
+		for (i=0; i<(int)frames; i++) {
+			for (j=0; j<channels; j++) {
+				if (channel_empty_bit_mask & (AML_I2S_CHANNEL_0<<j)) {
+					buf16[channels*i + j] = 0x00;
+				}
+			}
+		}
+		break;
+	case e32BitPerSample:
+		for (i=0; i<(int)frames; i++) {
+			for (j=0; j<channels; j++) {
+				if (channel_empty_bit_mask & (AML_I2S_CHANNEL_0<<j)) {
+					buf32[channels*i + j] = 0x00;
+				}
+			}
+		}
+		break;
+	default:
+		break;
+	}
+
+	return 0;
+}
+
+int data_exchange_i2s_channels(
+	void    *buf,
+	size_t  frames,
+	size_t  framesz,
+	size_t  channels,
+	eI2SDataLineIdx     i2s_idx1,
+	eI2SDataLineIdx     i2s_idx2)
+{
+	int i, j;
+	int16_t *buf16 = (int16_t *)buf;
+	int32_t *buf32 = (int32_t *)buf;
+	int16_t tmp16[AML_CH_CNT_PER_PORT];
+	int32_t tmp32[AML_CH_CNT_PER_PORT];
+
+	if (channels < 2*AML_CH_CNT_PER_PORT) {
+		AMLOGE("%s: at least 2 i2s port is needed!\n", __func__);
+		return -1;
+	}
+
+	//printf("\t%d <-> %d\n", i2s_idx1, i2s_idx2);
+
+	switch (framesz) {
+	case e16BitPerSample:
+		for (i=0; i<(int)frames; i++) {
+			for (j=0; j<AML_CH_CNT_PER_PORT; j++) {
+				tmp16[j]                                             = buf16[i*channels + i2s_idx1*AML_CH_CNT_PER_PORT + j];
+				buf16[i*channels + i2s_idx1*AML_CH_CNT_PER_PORT + j] = buf16[i*channels + i2s_idx2*AML_CH_CNT_PER_PORT + j];
+				buf16[i*channels + i2s_idx2*AML_CH_CNT_PER_PORT + j] = tmp16[j];
+
+			}
+		#if 0
+			printf("0x%08x 0x%08x <-> 0x%08x 0x%08x\n\n",
+				buf16[i*channels + i2s_idx1*AML_CH_CNT_PER_PORT + 0],
+				buf16[i*channels + i2s_idx1*AML_CH_CNT_PER_PORT + 1],
+				buf16[i*channels + i2s_idx2*AML_CH_CNT_PER_PORT + 0],
+				buf16[i*channels + i2s_idx2*AML_CH_CNT_PER_PORT + 1]);
+		#endif
+		}
+		break;
+	case e32BitPerSample:
+		for (i=0; i<(int)frames; i++) {
+			for (j=0; j<AML_CH_CNT_PER_PORT; j++) {
+				tmp32[j]                                             = buf32[i*channels + i2s_idx1*AML_CH_CNT_PER_PORT + j];
+				buf32[i*channels + i2s_idx1*AML_CH_CNT_PER_PORT + j] = buf32[i*channels + i2s_idx2*AML_CH_CNT_PER_PORT + j];
+				buf32[i*channels + i2s_idx2*AML_CH_CNT_PER_PORT + j] = tmp32[j];
+			}
+		}
+		break;
+	default:
+		break;
+	}
+
+	return 0;
+}
+
+int data_replace_lfe_data(
+	void    *out_buf,
+	size_t  out_channels,
+	size_t  out_framesz,
+	void    *input_lfe_buffer,
+	size_t  in_channles,
+	size_t  in_framesz,
+	size_t  frames,
+	int     channel_insert_bit_mask)
+{
+	int i, j;
+	int16_t *buf_out16 = (int16_t *)out_buf;
+	int32_t *buf_out32 = (int32_t *)out_buf;
+	int16_t *buf_in16  = (int16_t *)input_lfe_buffer;
+	int32_t *buf_in32  = (int32_t *)input_lfe_buffer;
+	int     lfe_base;
+	int     lfe_cnt;
+
+	//TODO:
+	if (out_channels != 6) {
+		AMLOGE("%s: only support 5.1 channels\n", __func__);
+		return -1;
+	}
+
+	//TODO:
+	if (in_channles != 2) {
+		AMLOGE("%s: only support replace 2 channels\n", __func__);
+		return -1;
+	}
+
+	//TODO: should get from channel_insert_bit_mask
+	//case_1: ch2,ch3 are all lfe
+	if ((AML_I2S_CHANNEL_2|AML_I2S_CHANNEL_3) == channel_insert_bit_mask) {
+		lfe_base = 2;
+		lfe_cnt  = 2;
+	}
+	//case_1:     ch3  is lfe
+	if (AML_I2S_CHANNEL_3 == channel_insert_bit_mask) {
+		lfe_base = 3;
+		lfe_cnt  = 1;
+	}
+
+	switch (out_framesz) {
+	case e16BitPerSample:
+		switch (in_framesz) {
+		case e16BitPerSample:
+			for (i=0; i<(int)frames; i++) {
+				for (j=0; j<lfe_cnt; j++) {
+					buf_out16[out_channels*i + lfe_base + j] = buf_in16[in_channles*i + j];
+				}
+			}
+			break;
+		case e32BitPerSample:
+			for (i=0; i<(int)frames; i++) {
+				for (j=0; j<lfe_cnt; j++) {
+					buf_out16[out_channels*i + lfe_base + j] = (int16_t)(buf_in16[in_channles*i + j] >> 16);
+				}
+			}
+			break;
+		default:
+			break;
+		}
+		break;
+	case e32BitPerSample:
+		switch (in_framesz) {
+		case e16BitPerSample:
+			for (i=0; i<(int)frames; i++) {
+				for (j=0; j<lfe_cnt; j++) {
+					buf_out32[out_channels*i + lfe_base + j] = ((int32_t)buf_in16[in_channles*i + j]) << 16;
+				}
+			}
+			break;
+		case e32BitPerSample:
+			for (i=0; i<(int)frames; i++) {
+				for (j=0; j<lfe_cnt; j++) {
+					buf_out32[out_channels*i + lfe_base + j] = buf_in32[in_channles*i + j];
+				}
+			}
+			break;
+		default:
+			break;
+		}
+		break;
+	default:
+		break;
+	}
+
+	return 0;
+}
+
+int data_invert_channels(
+	void    *buf,
+	size_t  frames,
+	size_t  framesz,
+	int     channels,
+	int     channel_invert_bit_mask)
+{
+	int i, j;
+	int16_t *buf16 = (int16_t *)buf;
+	int32_t *buf32 = (int32_t *)buf;
+	int16_t tmp16;
+	int32_t tmp32;
+
+	//_find_index_need_effect(channel_invert_bit_mask);
+	switch (framesz) {
+	case e16BitPerSample:
+		for (i=0; i<(int)frames; i++) {
+			for (j=0; j<channels; j++) {
+				if (channel_invert_bit_mask & (AML_I2S_CHANNEL_0<<j)) {
+					tmp16                 = buf16[channels*i + j];
+					buf16[channels*i + j] = -tmp16;
+				}
+			}
+		}
+		break;
+	case e32BitPerSample:
+		for (i=0; i<(int)frames; i++) {
+			for (j=0; j<channels; j++) {
+				if (channel_invert_bit_mask & (AML_I2S_CHANNEL_0<<j)) {
+					tmp32                 = buf32[channels*i + j];
+					buf32[channels*i + j] = -tmp32;
+				}
+			}
+		}
+		break;
+	default:
+		break;
+	}
+
+	return 0;
+}
+
+int data_concat_channels(
+	void    *out_buf,
+	size_t  out_channels,
+	size_t  out_framesz,
+	void    *in_buf1, void *in_buf2, void *in_buf3, void *in_buf4,
+	size_t  in_channels,
+	size_t  in_framesz,
+	size_t  frames)
+{
+	int i;
+	int16_t *buf_out16  = (int16_t *)out_buf;
+	int32_t *buf_out32  = (int32_t *)out_buf;
+
+	int16_t *buf_in1_16 = (int16_t *)in_buf1;
+	int16_t *buf_in2_16 = (int16_t *)in_buf2;
+	int16_t *buf_in3_16 = (int16_t *)in_buf3;
+	int16_t *buf_in4_16 = (int16_t *)in_buf4;
+
+	int32_t *buf_in1_32 = (int32_t *)in_buf1;
+	int32_t *buf_in2_32 = (int32_t *)in_buf2;
+	int32_t *buf_in3_32 = (int32_t *)in_buf3;
+	int32_t *buf_in4_32 = (int32_t *)in_buf4;
+
+	if (in_channels != 2 && in_channels != 4 && in_channels != 6 && in_channels != 8) {
+		AMLOGE("%s: only support concat 2/4/6/8 channels together!\n", __func__);
+		return -EINVAL;
+	}
+
+	if (in_channels > out_channels) {
+		AMLOGE("%s: out_channels %zu < %zu inclannels\n", __func__, out_channels, in_channels);
+		return -EINVAL;
+	}
+
+	switch (out_framesz) {
+	case e16BitPerSample:
+		switch (in_framesz) {
+		case e16BitPerSample:
+			for (i=0; i<(int)frames; i++) {
+				if (in_channels >= 2) {
+					buf_out16[out_channels*i + 0] = buf_in1_16[2*i + 0];
+					buf_out16[out_channels*i + 1] = buf_in1_16[2*i + 1];
+				}
+				if (in_channels >= 4) {
+					buf_out16[out_channels*i + 2] = buf_in2_16[2*i + 0];
+					buf_out16[out_channels*i + 3] = buf_in2_16[2*i + 1];
+				}
+				if (in_channels >= 6) {
+					buf_out16[out_channels*i + 4] = buf_in3_16[2*i + 0];
+					buf_out16[out_channels*i + 5] = buf_in3_16[2*i + 1];
+				}
+				if (in_channels >= 8) {
+					buf_out16[out_channels*i + 6] = buf_in4_16[2*i + 0];
+					buf_out16[out_channels*i + 7] = buf_in4_16[2*i + 1];
+				}
+			}
+			break;
+		case e32BitPerSample:
+			for (i=0; i<(int)frames; i++) {
+				if (in_channels >= 2) {
+					buf_out16[out_channels*i + 0] = (int16_t)(buf_in1_32[2*i + 0]>>16);
+					buf_out16[out_channels*i + 1] = (int16_t)(buf_in1_32[2*i + 1]>>16);
+				}
+				if (in_channels >= 4) {
+					buf_out16[out_channels*i + 2] = (int16_t)(buf_in2_32[2*i + 0]>>16);
+					buf_out16[out_channels*i + 3] = (int16_t)(buf_in2_32[2*i + 1]>>16);
+				}
+				if (in_channels >= 6) {
+					buf_out16[out_channels*i + 4] = (int16_t)(buf_in3_32[2*i + 0]>>16);
+					buf_out16[out_channels*i + 5] = (int16_t)(buf_in3_32[2*i + 1]>>16);
+				}
+				if (in_channels >= 8) {
+					buf_out16[out_channels*i + 6] = (int16_t)(buf_in4_32[2*i + 0]>>16);
+					buf_out16[out_channels*i + 7] = (int16_t)(buf_in4_32[2*i + 1]>>16);
+				}
+			}
+			break;
+		default:
+			break;
+		}
+		break;
+	case e32BitPerSample:
+		switch (in_framesz) {
+		case e16BitPerSample:
+			for (i=0; i<(int)frames; i++) {
+				if (in_channels >= 2) {
+					buf_out32[out_channels*i + 0] = ((int32_t)(buf_in1_16[2*i + 0]))<<16;
+					buf_out32[out_channels*i + 1] = ((int32_t)(buf_in1_16[2*i + 1]))<<16;
+				}
+				if (in_channels >= 4) {
+					buf_out32[out_channels*i + 2] = ((int32_t)(buf_in2_16[2*i + 0]))<<16;
+					buf_out32[out_channels*i + 3] = ((int32_t)(buf_in2_16[2*i + 1]))<<16;
+				}
+				if (in_channels >= 6) {
+					buf_out32[out_channels*i + 4] = ((int32_t)(buf_in3_16[2*i + 0]))<<16;
+					buf_out32[out_channels*i + 5] = ((int32_t)(buf_in3_16[2*i + 1]))<<16;
+				}
+				if (in_channels >= 8) {
+					buf_out32[out_channels*i + 6] = ((int32_t)(buf_in4_16[2*i + 0]))<<16;
+					buf_out32[out_channels*i + 7] = ((int32_t)(buf_in4_16[2*i + 1]))<<16;
+				}
+			}
+			break;
+		case e32BitPerSample:
+			for (i=0; i<(int)frames; i++) {
+				if (in_channels >= 2) {
+					buf_out32[out_channels*i + 0] = buf_in1_32[2*i + 0];
+					buf_out32[out_channels*i + 1] = buf_in1_32[2*i + 1];
+				}
+				if (in_channels >= 4) {
+					buf_out32[out_channels*i + 2] = buf_in2_32[2*i + 0];
+					buf_out32[out_channels*i + 3] = buf_in2_32[2*i + 1];
+				}
+				if (in_channels >= 6) {
+					buf_out32[out_channels*i + 4] = buf_in3_32[2*i + 0];
+					buf_out32[out_channels*i + 5] = buf_in3_32[2*i + 1];
+				}
+				if (in_channels >= 8) {
+					buf_out32[out_channels*i + 6] = buf_in4_32[2*i + 0];
+					buf_out32[out_channels*i + 7] = buf_in4_32[2*i + 1];
+				}
+			}
+			break;
+		default:
+			break;
+		}
+		break;
+	default:
+		break;
+	}
+
+	return 0;
+}
+
+#define COUNT_DITTER_FRAMES   (4)
+#define COUNT_DITTER_CHANNELS (8)
+int16_t ditter_8ch_16[COUNT_DITTER_FRAMES*COUNT_DITTER_CHANNELS] = {
+	0xffff, 0x0001, 0xffff, 0x0000, 0xffff, 0x0000, 0x0001, 0xffff,
+	0x0001, 0xffff, 0x0001, 0xffff, 0x0001, 0xffff, 0xffff, 0x0001,
+	0xffff, 0x0001, 0xffff, 0x0000, 0xffff, 0x0001, 0x0000, 0x0000,
+	0x0001, 0xffff, 0x0001, 0x0001, 0x0000, 0x0001, 0xffff, 0xffff
+};
+int32_t ditter_8ch_32[COUNT_DITTER_FRAMES*COUNT_DITTER_CHANNELS] = {
+	0xffffffff, 0x00000001, 0xffffffff, 0x00000000, 0xffffffff, 0x00000000, 0x00000001, 0xffffffff,
+	0x00000001, 0xffffffff, 0x00000001, 0xffffffff, 0x00000001, 0xffffffff, 0xffffffff, 0x00000001,
+	0xffffffff, 0x00000001, 0xffffffff, 0x00000000, 0xffffffff, 0x00000001, 0x00000000, 0x00000000,
+	0x00000001, 0xffffffff, 0x00000001, 0x00000001, 0x00000000, 0x00000001, 0xffffffff, 0xffffffff
+};
+
+int data_add_ditter_to_channels(
+	void    *buffer,
+	size_t  frames,
+	size_t  framesz,
+	int     channels,
+	int     channel_ditter_bit_mask)
+{
+	int i, j;
+	int16_t *buf16  = (int16_t *)buffer;
+	int32_t *buf32  = (int32_t *)buffer;
+
+    int16_t *ditter16;
+    int32_t *ditter32;
+
+    int32_t tmpbuf32;
+    int64_t tmpbuf64;
+
+	if (channels > 8) {
+		AMLOGE("%s: only support 5.1.2 ch(8channels) now\n", __func__);
+		return -1;
+	}
+
+	//TODO: need remove this
+	switch (channel_ditter_bit_mask) {
+	case AML_CH_IDX_5_1_ALL:
+		channel_ditter_bit_mask = AML_I2S_CHANNEL_0|AML_I2S_CHANNEL_1
+			|AML_I2S_CHANNEL_2|AML_I2S_CHANNEL_3|AML_I2S_CHANNEL_4|AML_I2S_CHANNEL_5;
+		break;
+	case AML_CH_IDX_7_1_ALL:
+	case AML_CH_IDX_5_1_2_ALL:
+		channel_ditter_bit_mask = AML_I2S_CHANNEL_0|AML_I2S_CHANNEL_1
+			|AML_I2S_CHANNEL_2|AML_I2S_CHANNEL_3|AML_I2S_CHANNEL_4|AML_I2S_CHANNEL_5
+			|AML_I2S_CHANNEL_6|AML_I2S_CHANNEL_7;
+		break;
+	default:
+		break;
+	}
+
+	switch (framesz) {
+	case e16BitPerSample:
+		for (i=0; i<(int)frames; i++) {
+            ditter16 = &ditter_8ch_16[i%(COUNT_DITTER_FRAMES+1)];
+			for (j=0; j<channels; j++) {
+				if (channel_ditter_bit_mask & (AML_I2S_CHANNEL_0<<j)) {
+					tmpbuf32 = (int32_t)buf16[channels*i + j] + (int32_t)ditter16[j];
+					// [-2^15, 2^15-1]
+					if (tmpbuf32 > 32767 || tmpbuf32 < -32768) {
+						continue;
+					} else {
+						buf16[channels*i + j] = (int16_t)tmpbuf32;
+					}
+				}
+			}
+		}
+		break;
+	case e32BitPerSample:
+		for (i=0; i<(int)frames; i++) {
+            ditter32 = &ditter_8ch_32[i%(COUNT_DITTER_FRAMES+1)];
+			for (j=0; j<channels; j++) {
+				if (channel_ditter_bit_mask & (AML_I2S_CHANNEL_0<<j)) {
+					tmpbuf64 = (int64_t)buf32[channels*i + j] + (int64_t)ditter32[j];
+					// [-2^31, 2^31-1] // is it right here?
+					if (tmpbuf64 > 2147483647 || tmpbuf64 < -2147483647) {
+						continue;
+					} else {
+						buf32[channels*i + j] = (int32_t)tmpbuf64;
+					}
+				}
+			}
+		}
+		break;
+	default:
+		break;
+	}
+
+	return 0;
+}
+
+int data_extend_channels(
+	void    *out_buf,
+	size_t  out_channels,
+	size_t  out_framesz,
+	void    *in_buf,
+	size_t  in_channels,
+	size_t  in_framesz,
+	size_t  frames)
+{
+	int i, j;
+	int16_t *buf_in16   = (int16_t *)in_buf;
+	int32_t *buf_in32   = (int32_t *)in_buf;
+	int16_t *buf_out16  = (int16_t *)out_buf;
+	int32_t *buf_out32  = (int32_t *)out_buf;
+
+	//TODO: use one interfcae for data_extend_channels/data_extract_channels
+	if (out_channels < in_channels) {
+		AMLOGE("%s: only support extend channels\n", __func__);
+		return -1;
+	}
+
+	// initial out buffer first
+	memset((char *)out_buf, 0x00, frames*out_channels*out_framesz);
+
+	switch (out_framesz) {
+	case e16BitPerSample:
+		switch (in_framesz) {
+		case e16BitPerSample:
+			for (i=0; i<(int)frames; i++) {
+				for (j=0; j<(int)out_channels; j++) {
+					if (j < (int)in_channels) {
+						buf_out16[out_channels*i + j] = buf_in16[in_channels*i + j];
+					} else {
+						buf_out16[out_channels*i + j] = 0x00;
+					}
+				}
+			}
+			break;
+		case e32BitPerSample:
+			for (i=0; i<(int)frames; i++) {
+				for (j=0; j<(int)out_channels; j++) {
+					if (j < (int)in_channels) {
+						buf_out16[out_channels*i + j] = (int16_t)(buf_in32[in_channels*i + j]>>16);
+					} else {
+						buf_out16[out_channels*i + j] = 0x00;
+					}
+				}
+			}
+			break;
+		default:
+			break;
+		}
+		break;
+	case e32BitPerSample:
+		switch (in_framesz) {
+		case e16BitPerSample:
+			for (i=0; i<(int)frames; i++) {
+				for (j=0; j<(int)out_channels; j++) {
+					if (j < (int)in_channels) {
+						buf_out32[out_channels*i + j] = ((int32_t)buf_in16[in_channels*i + j])<<16;
+					} else {
+						buf_out32[out_channels*i + j] = 0x00;
+					}
+				}
+			}
+			break;
+		case e32BitPerSample:
+			for (i=0; i<(int)frames; i++) {
+				for (j=0; j<(int)out_channels; j++) {
+					if (j < (int)in_channels) {
+						buf_out32[out_channels*i + j] = buf_in32[in_channels*i + j];
+					} else {
+						buf_out32[out_channels*i + j] = 0x00;
+					}
+				}
+			}
+			break;
+		default:
+			break;
+		}
+		break;
+	default:
+		break;
+	}
+
+	return 0;
+}
+
+int data_extract_channels(
+	struct  aml_channel_map *map,
+	void    *out_buf,
+	size_t  out_channels,
+	size_t  out_framesz,
+	void    *in_buf,
+	size_t  in_channels,
+	size_t  in_framesz,
+	size_t  frames,
+	int     channel_extract_bit_mask)
+{
+	int i, k;
+	int16_t *buf_in16   = (int16_t *)in_buf;
+	int32_t *buf_in32   = (int32_t *)in_buf;
+	int16_t *buf_out16  = (int16_t *)out_buf;
+	int32_t *buf_out32  = (int32_t *)out_buf;
+	int cnt;
+
+	if (!map)
+		return 0;
+
+	//TODO: use one interfcae for data_extend_channels/data_extract_channels
+	if (out_channels > in_channels) {
+		AMLOGE("%s: only support extract channels\n", __func__);
+		return -1;
+	}
+
+	//check param
+	cnt = 0;
+	for (i=0; i<8; i++)
+		if (channel_extract_bit_mask & (AML_I2S_CHANNEL_0<<i))
+			cnt++;
+	if (cnt > (int)out_channels) {
+		AMLOGE("%s: need extract %d channels, but buf only have %zu chanels\n",
+			__func__, cnt, out_channels);
+		return -1;
+	}
+
+	switch (out_framesz) {
+	case e16BitPerSample:
+		switch (in_framesz) {
+		case e16BitPerSample:
+			for (i=0; i<(int)frames; i++) {
+				cnt = 0;
+				for (k=0; k<(int)in_channels; k++) {
+					if (channel_extract_bit_mask & (AML_I2S_CHANNEL_0<<k)) {
+						buf_out16[out_channels*i + cnt] = buf_in16[in_channels*i + k];
+						cnt++;
+					}
+				}
+			}
+			break;
+		case e32BitPerSample:
+			for (i=0; i<(int)frames; i++) {
+				cnt = 0;
+				for (k=0; k<(int)in_channels; k++) {
+					if (channel_extract_bit_mask & (AML_I2S_CHANNEL_0<<k)) {
+						buf_out16[out_channels*i + cnt] = (int16_t)(buf_in32[in_channels*i + k]>>16);
+						cnt++;
+					}
+				}
+			}
+			break;
+		default:
+			break;
+		}
+		break;
+	case e32BitPerSample:
+		switch (in_framesz) {
+		case e16BitPerSample:
+			for (i=0; i<(int)frames; i++) {
+				cnt = 0;
+				for (k=0; k<(int)in_channels; k++) {
+					if (channel_extract_bit_mask & (AML_I2S_CHANNEL_0<<k)) {
+						buf_out32[out_channels*i + cnt] = ((int32_t)buf_in16[in_channels*i + k])<<16;
+						cnt++;
+					}
+				}
+			}
+			break;
+		case e32BitPerSample:
+			for (i=0; i<(int)frames; i++) {
+				cnt = 0;
+				for (k=0; k<(int)in_channels; k++) {
+					if (channel_extract_bit_mask & (AML_I2S_CHANNEL_0<<k)) {
+						buf_out32[out_channels*i + cnt] = buf_in32[in_channels*i + k];
+						cnt++;
+					}
+				}
+			}
+			break;
+		default:
+			break;
+		}
+		break;
+	default:
+		break;
+	}
+
+	return 0;
+}
+
+static int delay[4096];
+static int delay_frame = 1440 * 4;
+static char *delay_start = (char *)delay;
+
+int audio_effect_real_lfe_gain(short* buffer, int frame_size, int LPF_Gain)
+{
+    int i;
+//    short data_left, data_right;
+    int output_size = frame_size << 2;
+    float gain;
+    int32_t tmp_sample;
+    memcpy((delay_start + delay_frame), buffer, output_size);
+    memcpy(buffer, delay_start, output_size);
+    memmove(delay_start, (delay_start + output_size), delay_frame);
+
+    gain = powf(10, (float)LPF_Gain/20);
+    //ALOGE("audio_effect_real_lfe_gain gain %f\n", gain);
+    for (i = 0; i < frame_size; i++) {
+        tmp_sample = (int32_t)buffer[i * 2 + 0] * gain;
+        buffer[i * 2 + 0] = _clamp16(tmp_sample);
+        tmp_sample = (int32_t)buffer[i * 2 + 1] * gain;
+        buffer[i * 2 + 1] = _clamp16(tmp_sample);
+    }
+
+	return 0;
+}
+
diff --git a/utils/aml_dump_debug.c b/utils/aml_dump_debug.c
new file mode 100755
index 0000000..5b7d401
--- /dev/null
+++ b/utils/aml_dump_debug.c
@@ -0,0 +1,96 @@
+/*
+ * hardware/amlogic/audio/utils/aml_dump_debug.c
+ *
+ * Copyright (C) 2017 Amlogic, Inc. All rights reserved.
+ *
+ * This source code is subject to the terms and conditions defined in the
+ * file 'LICENSE' which is part of this source code package.
+ *
+ */
+
+#include <stdbool.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <signal.h>
+#include <pthread.h>
+#include <unistd.h>
+#include <math.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <sys/mman.h>
+#include <sys/ioctl.h>
+#include <sys/stat.h>
+#include <sys/prctl.h>
+#include <cutils/log.h>
+#include <cutils/properties.h>
+
+#include <aml_dump_debug.h>
+
+#undef  LOG_TAG
+#define LOG_TAG "aml_dump_debug"
+
+static int gDumpDataFd = -1;
+
+void DoDumpData(const void *data_buf, int size, int aud_src_type) {
+    int tmp_type = -1;
+    char prop_value[PROPERTY_VALUE_MAX] = { 0 };
+    char file_path[PROPERTY_VALUE_MAX] = { 0 };
+
+    memset(prop_value, '\0', PROPERTY_VALUE_MAX);
+    property_get("audio.dumpdata.en", prop_value, "null");
+    if (strcasecmp(prop_value, "null") == 0
+            || strcasecmp(prop_value, "0") == 0) {
+        if (gDumpDataFd >= 0) {
+            close(gDumpDataFd);
+            gDumpDataFd = -1;
+        }
+        return;
+    }
+
+    property_get("audio.dumpdata.src", prop_value, "null");
+    if (strcasecmp(prop_value, "null") == 0
+            || strcasecmp(prop_value, "input") == 0
+            || strcasecmp(prop_value, "0") == 0) {
+        tmp_type = CC_DUMP_SRC_TYPE_INPUT;
+    } else if (strcasecmp(prop_value, "output") == 0
+            || strcasecmp(prop_value, "1") == 0) {
+        tmp_type = CC_DUMP_SRC_TYPE_OUTPUT;
+    } else if (strcasecmp(prop_value, "input_parse") == 0
+            || strcasecmp(prop_value, "2") == 0) {
+        tmp_type = CC_DUMP_SRC_TYPE_INPUT_PARSE;
+    }
+
+    if (tmp_type != aud_src_type) {
+        return;
+    }
+
+    memset(file_path, '\0', PROPERTY_VALUE_MAX);
+    property_get("audio.dumpdata.path", file_path, "null");
+    if (strcasecmp(file_path, "null") == 0) {
+        file_path[0] = '\0';
+    }
+
+    if (gDumpDataFd < 0 && file_path[0] != '\0') {
+        if (access(file_path, 0) == 0) {
+            gDumpDataFd = open(file_path, O_RDWR | O_SYNC);
+            if (gDumpDataFd < 0) {
+                ALOGE("%s, Open device file \"%s\" error: %s.\n",
+                        __FUNCTION__, file_path, strerror(errno));
+            }
+        } else {
+            gDumpDataFd = open(file_path, O_WRONLY | O_CREAT | O_EXCL,
+                    S_IRUSR | S_IWUSR);
+            if (gDumpDataFd < 0) {
+                ALOGE("%s, Create device file \"%s\" error: %s.\n",
+                        __FUNCTION__, file_path, strerror(errno));
+            }
+        }
+    }
+
+    if (gDumpDataFd >= 0) {
+        write(gDumpDataFd, data_buf, size);
+    }
+    return;
+}
diff --git a/utils/aml_hw_profile.c b/utils/aml_hw_profile.c
new file mode 100755
index 0000000..5b3a7e3
--- /dev/null
+++ b/utils/aml_hw_profile.c
@@ -0,0 +1,399 @@
+/**
+ ** aml_hw_profile.c
+ **
+ ** This program is APIs for get aml sound card/port.
+ ** author: shen pengru
+ **
+ */
+#include <errno.h>
+#include <pthread.h>
+#include <stdint.h>
+#include <sys/time.h>
+#include <stdlib.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <math.h>
+#include <cutils/log.h>
+#include <cutils/str_parms.h>
+#include <cutils/properties.h>
+#include <hardware/hardware.h>
+#include <system/audio.h>
+#include <hardware/audio.h>
+#include <aml_hw_profile.h>
+#include <aml_android_utils.h>
+
+#undef  LOG_TAG
+#define LOG_TAG "audio_hw_profile"
+
+extern int aml_sysfs_get_int16(const char *path, unsigned *val);
+
+int aml_get_sound_card_main()
+{
+	int card = -1, err = 0;
+	int fd = -1;
+	unsigned fileSize = 512;
+	char *read_buf = NULL, *pd = NULL;
+
+	fd = open(SOUND_CARDS_PATH, O_RDONLY);
+	if (fd < 0) {
+		ALOGE("%s: failed to open config file %s error: %s\n",
+			__func__,
+			SOUND_CARDS_PATH, strerror(errno));
+		close(fd);
+		return -EINVAL;
+	}
+
+	read_buf = (char *) malloc(fileSize);
+	if (!read_buf) {
+		ALOGE("%s: Failed to malloc read_buf, error: %s",
+			__func__, strerror(errno));
+		close(fd);
+		return -ENOMEM;
+	}
+	memset(read_buf, 0x0, fileSize);
+	err = read(fd, read_buf, (fileSize-1));
+	if (err < 0) {
+		ALOGE("%s: failed to read config file %s error: %s\n",
+			__func__,
+			SOUND_CARDS_PATH, strerror(errno));
+		close(fd);
+		free(read_buf);
+		return -EINVAL;
+	}
+	pd = strstr(read_buf, "AML");
+	if ((pd != NULL) && (pd >= (read_buf+3))) {///< check the pd pointer.
+		card = *(pd - 3) - '0';
+	}
+//OUT:
+	free(read_buf);
+	close(fd);
+	return card;
+}
+
+int aml_get_sound_card_ext(ePcmStreamType stream_type)
+{
+	int card_num = 1;       // start num, 0 is defualt sound card.
+	struct stat card_stat;
+	char fpath[256];
+	int ret;
+
+	while (card_num <= MAX_CARD_NUM) {
+		snprintf(fpath, sizeof(fpath), "/proc/asound/card%d", card_num);
+		ret = stat(fpath, &card_stat);
+		if (ret < 0) {
+			ret = -1;
+		} else {
+			snprintf(fpath, sizeof(fpath), "/dev/snd/pcmC%uD0%c", card_num,
+				stream_type ? 'c' : 'p');
+			ret = stat(fpath, &card_stat);
+			if (ret == 0) {
+				return card_num;
+			}
+		}
+		card_num++;
+	}
+
+	return ret;
+}
+
+static int _get_audio_port(char *name, int name_len)
+{
+	int port = -1, err = 0;
+	int fd = -1;
+	unsigned fileSize = 512;
+	char *read_buf = NULL, *pd = NULL;
+
+	fd = open(SOUND_PCM_PATH, O_RDONLY);
+	if (fd < 0) {
+		ALOGE("%s: failed to open config file %s error: %s\n",
+			__func__,
+			SOUND_PCM_PATH, strerror(errno));
+		close(fd);
+		return -EINVAL;
+	}
+	read_buf = (char *) malloc(fileSize);
+	if (!read_buf) {
+		ALOGE("%s: Failed to malloc read_buf error: %s", __func__, strerror(errno));
+		close(fd);
+		return -ENOMEM;
+	}
+	memset(read_buf, 0x0, fileSize);
+	err = read(fd, read_buf, (fileSize-1));
+	if (err < 0) {
+		ALOGE("%s: failed to read config file %s error: %s\n",
+			__func__,
+			SOUND_PCM_PATH, strerror(errno));
+		close(fd);
+		free(read_buf);
+		return -EINVAL;
+	}
+	pd = strstr(read_buf, name);
+	///< pd is the ptr when name first occur in read_buf
+	///< check the pd pointer.
+	if ((pd != NULL) && (pd >= (read_buf+name_len))) {
+		port = *(pd - name_len) - '0';
+	}
+
+//OUT:
+	free(read_buf);
+	close(fd);
+
+	return port;
+}
+
+int aml_get_i2s_port(void)
+{
+	return _get_audio_port(PCM_I2S_STRING, 3);
+}
+
+int aml_get_spdif_port(void)
+{
+	return _get_audio_port(PCM_SPDIF_STRING, 3);
+}
+
+int aml_get_pcm2bt_port(void)
+{
+	return _get_audio_port(PCM_PCM2BT_STRING, 11);
+}
+
+/******************************************************************************
+ * CodingType MaxChannels SamplingFreq SampleSize
+ * ------------------------------------------------------------------------
+ *     PCM,            2 ch, 32/44.1/48/88.2/96/176.4/192 kHz, 16/20/24 bit
+ *     PCM,            8 ch, 32/44.1/48/88.2/96/176.4/192 kHz, 16/20/24 bit
+ *     AC-3,           8 ch, 32/44.1/48 kHz,                            bit
+ *     DTS,            8 ch, 44.1/48 kHz,                               bit
+ *     OneBitAudio,    2 ch, 44.1 kHz,                                  bit
+ *     Dobly_Digital+, 8 ch, 44.1/48 kHz,                            16 bit
+ *     DTS-HD,         8 ch, 44.1/48/88.2/96/176.4/192 kHz,          16 bit
+ *     MAT,            8 ch, 32/44.1/48/88.2/96/176.4/192 kHz,       16 bit
+ *****************************************************************************/
+char* aml_get_hdmi_sink_cap(const char *keys)
+{
+//	int i = 0;
+	char * infobuf = NULL;
+//	int channel = 0;
+//	int dgraw = 0;
+	int fd = -1;
+	int size = 0;
+	char *aud_cap = NULL;
+
+	infobuf = (char *)malloc(1024 * sizeof(char));
+	if (infobuf == NULL) {
+		ALOGE("%s: malloc buffer failed, error: %s\n",
+			__func__, strerror(errno));
+		goto fail;
+	}
+
+	aud_cap = (char*)malloc(1024);
+	if (aud_cap == NULL) {
+		ALOGE("%s: malloc buffer failed, error: %s\n",
+			__func__, strerror(errno));
+		goto fail;
+	}
+
+	memset(aud_cap, 0, 1024);
+	memset(infobuf, 0, 1024);
+
+	fd = open("/sys/class/amhdmitx/amhdmitx0/aud_cap", O_RDONLY);
+	if (fd >= 0) {
+		int nread = read(fd, infobuf, 1024);
+              ALOGV("read cap size : %d",nread);
+		/* check the format cap */
+		if (strstr(keys, AUDIO_PARAMETER_STREAM_SUP_FORMATS)) {
+			size += sprintf(aud_cap, "=");
+			if (aml_strstr(infobuf, "Dobly_Digital+")) {
+				size += sprintf(aud_cap + size, "%s|", "AUDIO_FORMAT_E_AC3");
+			}
+			if (aml_strstr(infobuf, "AC-3")) {
+				size += sprintf(aud_cap + size, "%s|", "AUDIO_FORMAT_AC3");
+			}
+			if (aml_strstr(infobuf, "DTS-HD")) {
+				size += sprintf(aud_cap + size, "%s|", "AUDIO_FORMAT_DTS|AUDIO_FORMAT_DTSHD");
+			} else if (aml_strstr(infobuf, "DTS")) {
+				size += sprintf(aud_cap + size, "%s|", "AUDIO_FORMAT_DTS");
+			}
+			if (aml_strstr(infobuf, "MAT")) {
+				size += sprintf(aud_cap + size, "%s|", "AUDIO_FORMAT_DOLBY_TRUEHD");
+			}
+		}
+		/*check the channel cap */
+		else if (strstr(keys, AUDIO_PARAMETER_STREAM_SUP_CHANNELS)) {
+			/* take the 2ch suppported as default */
+			size += sprintf(aud_cap, "=%s|", "AUDIO_CHANNEL_OUT_STEREO");
+			if (aml_strstr(infobuf, "PCM, 8 ch")) {
+				size += sprintf(aud_cap + size, "%s|", "AUDIO_CHANNEL_OUT_5POINT1|AUDIO_CHANNEL_OUT_7POINT1");
+			} else if (aml_strstr(infobuf, "PCM, 6 ch")) {
+				size += sprintf(aud_cap + size, "%s|", "AUDIO_CHANNEL_OUT_5POINT1");
+			}
+		} else if (strstr(keys, AUDIO_PARAMETER_STREAM_SUP_SAMPLING_RATES)) {
+			/* take the 32/44.1/48 khz suppported as default */
+			size += sprintf(aud_cap, "=%s|", "32000|44100|48000");
+			if (aml_strstr(infobuf, "88.2")) {
+				size += sprintf(aud_cap + size, "%s|", "88200");
+			}
+			if (aml_strstr(infobuf, "96")) {
+				size += sprintf(aud_cap + size, "%s|", "96000");
+			}
+			if (aml_strstr(infobuf, "176.4")) {
+				size += sprintf(aud_cap + size, "%s|", "176400");
+			}
+			if (aml_strstr(infobuf, "192")) {
+				size += sprintf(aud_cap + size, "%s|", "192000");
+			}
+		}
+	}
+
+	if (infobuf) {
+		free(infobuf);
+	}
+	if (fd >= 0) {
+		close(fd);
+	}
+
+	return aud_cap;
+
+fail:
+	if (aud_cap) {
+		free(aud_cap);
+	}
+	if (infobuf) {
+		free(infobuf);
+	}
+
+	return NULL;
+}
+
+char*  aml_get_hdmi_arc_cap(unsigned *ad, int maxsize, const char *keys)
+{
+	int i = 0;
+//	int channel = 0;
+//	int dgraw = 0;
+//	int fd = -1;
+	int size = 0;
+	char *aud_cap = NULL;
+	unsigned char format, ch, sr;
+
+	aud_cap = (char*)malloc(1024);
+	if (aud_cap == NULL) {
+		ALOGE("%s: malloc buffer failed, err: %s\n",
+			__func__, strerror(errno));
+		goto fail;
+	}
+
+	memset(aud_cap, 0, 1024);
+	ALOGI("%s: get_hdmi_arc_cap\n", __func__);
+
+	/* check the format cap */
+	if (strstr(keys, AUDIO_PARAMETER_STREAM_SUP_FORMATS)) {
+		size += sprintf(aud_cap, "=%s|", "AUDIO_FORMAT_PCM_16_BIT");
+	}
+	/*check the channel cap */
+	else if (strstr(keys, AUDIO_PARAMETER_STREAM_SUP_CHANNELS)) {
+		//ALOGI("check channels\n");
+		/* take the 2ch suppported as default */
+		size += sprintf(aud_cap, "=%s|", "AUDIO_CHANNEL_OUT_STEREO");
+	} else if (strstr(keys, AUDIO_PARAMETER_STREAM_SUP_SAMPLING_RATES)) {
+		/* take the 32/44.1/48 khz suppported as default */
+		size += sprintf(aud_cap, "=%s|", "32000|44100|48000");
+		//ALOGI("check sample rate\n");
+	}
+
+	for (i = 0; i < maxsize; i++) {
+		if (ad[i] != 0) {
+			format = (ad[i] >> 19) & 0xf;
+			ch = (ad[i] >> 16) & 0x7;
+			sr = (ad[i] > 8) & 0xf;
+			ALOGI("%s: ad %x,format %d,ch %d,sr %d\n", __func__, ad[i], format, ch, sr);
+			/* check the format cap */
+			if (strstr(keys, AUDIO_PARAMETER_STREAM_SUP_FORMATS)) {
+				//ALOGI("check format\n");
+				if (format == 10) {
+					size += sprintf(aud_cap + size, "%s|", "AUDIO_FORMAT_E_AC3");
+				}
+				if (format == 2) {
+					size += sprintf(aud_cap + size, "%s|", "AUDIO_FORMAT_AC3");
+				}
+				if (format == 11) {
+					size += sprintf(aud_cap + size, "%s|", "AUDIO_FORMAT_DTS|AUDIO_FORMAT_DTSHD");
+				} else if (format == 7) {
+					size += sprintf(aud_cap + size, "%s|", "AUDIO_FORMAT_DTS");
+				}
+				if (format == 12) {
+					size += sprintf(aud_cap + size, "%s|", "AUDIO_FORMAT_DOLBY_TRUEHD");
+				}
+			}
+			/*check the channel cap */
+			else if (strstr(keys, AUDIO_PARAMETER_STREAM_SUP_CHANNELS)) {
+				//ALOGI("check channels\n");
+				if (/*format == 1 && */ch == 7) {
+					size += sprintf(aud_cap + size, "%s|", "AUDIO_CHANNEL_OUT_5POINT1|AUDIO_CHANNEL_OUT_7POINT1");
+				} else if (/*format == 1 && */ch == 5) {
+					size += sprintf(aud_cap + size, "%s|", "AUDIO_CHANNEL_OUT_5POINT1");
+				}
+			} else if (strstr(keys, AUDIO_PARAMETER_STREAM_SUP_SAMPLING_RATES)) {
+				ALOGI("%s: check sample rate\n", __func__);
+				if (format == 1 && sr == 4) {
+					size += sprintf(aud_cap + size, "%s|", "88200");
+				}
+				if (format == 1 && sr == 5) {
+					size += sprintf(aud_cap + size, "%s|", "96000");
+				}
+				if (format == 1 && sr == 6) {
+					size += sprintf(aud_cap + size, "%s|", "176400");
+				}
+				if (format == 1 && sr == 7) {
+					size += sprintf(aud_cap + size, "%s|", "192000");
+				}
+			}
+		} else {
+			format = 0;
+			ch = 0;
+			sr = 0;
+		}
+	}
+
+	return aud_cap;
+
+fail:
+	if (aud_cap) {
+		free(aud_cap);
+	}
+
+	return NULL;
+}
+
+void aml_set_codec_type(int type)
+{
+    char buf[16];
+    int fd = open ("/sys/class/audiodsp/digital_codec", O_WRONLY);
+
+    if (fd >= 0) {
+        memset(buf, 0, sizeof(buf));
+        snprintf(buf, sizeof(buf), "%d", type);
+
+        write(fd, buf, sizeof(buf));
+        close(fd);
+    }
+}
+
+
+int aml_get_codec_type(int format)
+{
+    switch (format) {
+        case AUDIO_FORMAT_AC3:
+            return TYPE_AC3;
+        case AUDIO_FORMAT_E_AC3:
+            return TYPE_EAC3;
+        case AUDIO_FORMAT_DTS:
+            return TYPE_DTS;
+        case AUDIO_FORMAT_DTS_HD:
+            return TYPE_DTS_HD;
+        case AUDIO_FORMAT_DOLBY_TRUEHD:
+            return TYPE_TRUE_HD;
+        case AUDIO_FORMAT_PCM:
+            return 0;
+        default:
+            return 0;
+    }
+}
diff --git a/utils/aml_ringbuffer.c b/utils/aml_ringbuffer.c
new file mode 100755
index 0000000..32b20ac
--- /dev/null
+++ b/utils/aml_ringbuffer.c
@@ -0,0 +1,410 @@
+/*
+ * hardware/amlogic/audio/utils/aml_ringbuffer.c
+ *
+ * Copyright (C) 2017 Amlogic, Inc. All rights reserved.
+ *
+ * This source code is subject to the terms and conditions defined in the
+ * file 'LICENSE' which is part of this source code package.
+ *
+ */
+
+#define LOG_TAG "ringbuffer"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <pthread.h>
+#include <errno.h>
+#include <string.h>
+#include <cutils/log.h>
+#include <aml_ringbuffer.h>
+
+/*************************************************
+Function: get_write_space
+Description: get the space can be written
+Input: write_point: write pointer
+       read_point:  read pointer
+       buffer_size: total buffer size
+Output:
+Return: the space can be written in byte
+*************************************************/
+static int get_write_space(unsigned char *write_point, unsigned char *read_point,
+        int buffer_size, int last_is_write)
+{
+    int bytes = 0;
+
+    if (write_point > read_point) {
+        bytes = buffer_size + read_point - write_point;
+    } else if (write_point < read_point) {
+        bytes = read_point - write_point;
+    } else if (!last_is_write) {
+        bytes = buffer_size;
+    }
+
+    return bytes;
+}
+
+/*************************************************
+Function: get_read_space
+Description: get the date space can be read
+Input: write_point: write pointer
+       read_point:  read pointer
+       buffer_size: total buffer size
+Output:
+Return: the data space can be read in byte
+*************************************************/
+static size_t get_read_space(unsigned char *write_point, unsigned char *read_point,
+        int buffer_size, int last_is_write) {
+    int bytes = 0;
+
+    if (write_point > read_point) {
+        bytes = write_point - read_point;
+    } else if (write_point < read_point) {
+        bytes = buffer_size + write_point - read_point;
+    } else if (last_is_write) {
+        bytes = buffer_size;
+    }
+
+    return bytes;
+}
+
+/*************************************************
+Function: write_to_buffer
+Description: write data to ring buffer
+Input: current_pointer: the current write pointer
+       data:  data to be written
+       bytes: the space of data to be written
+       start_addr: dest buffer
+       total_size: dest buffer size
+Output:
+Return: 0 for success
+*************************************************/
+static int write_to_buffer(unsigned char *current_pointer, unsigned char *data, int bytes,
+        unsigned char *start_addr, int total_size)
+{
+    int left_bytes = start_addr + total_size - current_pointer;
+
+    if (left_bytes >= bytes) {
+        memcpy(current_pointer, data, bytes);
+    } else {
+        memcpy(current_pointer, data, left_bytes);
+        memcpy(start_addr, data + left_bytes, bytes - left_bytes);
+    }
+
+    return 0;
+}
+
+/*************************************************
+Function: read_from_buffer
+Description: read data to ring buffer
+Input: current_pointer: the current read pointer
+       buffer:  buffer for the data to be read
+       bytes: the space of data to be read
+       start_addr: dest buffer
+       total_size: dest buffer size
+Output: read data
+Return: 0 for success
+*************************************************/
+static int read_from_buffer(unsigned char *current_pointer, unsigned char *buffer, int bytes,
+        unsigned char *start_addr, int total_size)
+{
+    int left_bytes = start_addr + total_size - current_pointer;
+
+    if (left_bytes >= bytes) {
+        memcpy(buffer, current_pointer, bytes);
+    } else {
+        memcpy(buffer, current_pointer, left_bytes);
+        memcpy(buffer + left_bytes, start_addr, bytes - left_bytes);
+    }
+
+    return 0;
+}
+
+/*************************************************
+Function: update_pointer
+Description: update read/write pointer of ring buffer
+Input: current_pointer: the current read/write pointer
+       bytes: data space has been written/read
+       start_addr: ring buffer
+       total_size: ring buffer size
+Output:
+Return: the updated pointer
+*************************************************/
+static inline void* update_pointer(unsigned char *current_pointer, int bytes,
+        unsigned char *start_addr, int total_size)
+{
+    current_pointer += bytes;
+
+    if (current_pointer >= start_addr + total_size) {
+        current_pointer -= total_size;
+    }
+
+    return current_pointer;
+}
+
+/*************************************************
+Function: ring_buffer_write
+Description: write data to ring buffer
+Input: rbuffer: the dest ring buffer
+       data: data to be written
+       bytes: data space in byte
+       cover: whether or not to cover the data if over run
+Output:
+Return: data space has been written
+*************************************************/
+size_t ring_buffer_write(struct ring_buffer *rbuffer, unsigned char* data, size_t bytes, int cover)
+{
+    struct ring_buffer *buf = rbuffer;
+    size_t write_space, written_bytes;
+
+    pthread_mutex_lock(&buf->lock);
+
+    if (buf->start_addr == NULL || buf->rd == NULL || buf->wr == NULL || buf->size == 0) {
+        ALOGE("%s, Buffer malloc fail!\n", __FUNCTION__);
+        pthread_mutex_unlock(&buf->lock);
+        return 0;
+    }
+
+    write_space = get_write_space(buf->wr, buf->rd, buf->size, buf->last_is_write);
+    if (write_space < bytes) {
+        if (UNCOVER_WRITE == cover) {
+            written_bytes = write_space;
+        } else {
+            written_bytes = bytes;
+        }
+    } else {
+        written_bytes = bytes;
+    }
+
+    write_to_buffer(buf->wr, data, written_bytes, buf->start_addr, buf->size);
+    buf->wr = update_pointer(buf->wr, written_bytes, buf->start_addr, buf->size);
+    if (written_bytes)
+        buf->last_is_write = 1;
+
+    pthread_mutex_unlock(&buf->lock);
+
+    return written_bytes;
+}
+
+/*************************************************
+Function: ring_buffer_read
+Description: read data from ring buffer
+Input: rbuffer: the source ring buffer
+       buffer: buffer for the read data
+       bytes: data space in byte
+Output: data has been read
+Return: data space has been read
+*************************************************/
+size_t ring_buffer_read(struct ring_buffer *rbuffer, unsigned char* buffer, size_t bytes)
+{
+    struct ring_buffer *buf = rbuffer;
+    size_t readable_space, read_bytes;
+
+    pthread_mutex_lock(&buf->lock);
+
+    if (buf->start_addr == NULL || buf->rd == NULL || buf->wr == NULL
+            || buf->size == 0) {
+        ALOGE("%s, Buffer malloc fail!\n", __FUNCTION__);
+        pthread_mutex_unlock(&buf->lock);
+        return 0;
+    }
+
+    readable_space = get_read_space(buf->wr, buf->rd, buf->size, buf->last_is_write);
+    if (readable_space < bytes) {
+        read_bytes = readable_space;
+    } else {
+        read_bytes = bytes;
+    }
+
+    read_from_buffer(buf->rd, buffer, read_bytes, buf->start_addr, buf->size);
+    buf->rd = update_pointer(buf->rd, read_bytes, buf->start_addr, buf->size);
+    if (read_bytes)
+        buf->last_is_write = 0;
+    pthread_mutex_unlock(&buf->lock);
+
+    return read_bytes;
+}
+
+/*************************************************
+Function: ring_buffer_init
+Description: initialize ring buffer
+Input: rbuffer: the ring buffer to be initialized
+       buffer_size: total size of ring buffer
+Output:
+Return: 0 for success, otherwise fail
+*************************************************/
+int ring_buffer_init(struct ring_buffer *rbuffer, int buffer_size)
+{
+    struct ring_buffer *buf = rbuffer;
+
+    pthread_mutex_lock(&buf->lock);
+
+    buf->size = buffer_size;
+    buf->start_addr = malloc(buffer_size * sizeof(unsigned char));
+    if (buf->start_addr == NULL) {
+        ALOGD("%s, Malloc android out buffer error!\n", __FUNCTION__);
+        pthread_mutex_unlock(&buf->lock);
+        return -1;
+    }
+
+    memset(buf->start_addr, 0, buffer_size);
+    buf->rd = buf->start_addr;
+    buf->wr = buf->start_addr;
+    buf->last_is_write = 0;
+    pthread_mutex_unlock(&buf->lock);
+
+    return 0;
+}
+
+/*************************************************
+Function: ring_buffer_release
+Description: release ring buffer
+Input: rbuffer: the ring buffer to be released
+Output:
+Return: 0 for success, otherwise fail
+*************************************************/
+int ring_buffer_release(struct ring_buffer *rbuffer)
+{
+    struct ring_buffer *buf = rbuffer;
+
+    pthread_mutex_lock(&buf->lock);
+
+    if (buf->start_addr != NULL) {
+        free(buf->start_addr);
+        buf->start_addr = NULL;
+    }
+
+    buf->rd = NULL;
+    buf->wr = NULL;
+    buf->size = 0;
+    buf->last_is_write = 0;
+
+    pthread_mutex_unlock(&buf->lock);
+
+    return 0;
+}
+
+/*************************************************
+Function: ring_buffer_reset
+Description: reset ring buffer
+Input: rbuffer: the ring buffer to be reset
+Output:
+Return: 0 for success, otherwise fail
+*************************************************/
+int ring_buffer_reset(struct ring_buffer *rbuffer)
+{
+    struct ring_buffer *buf = rbuffer;
+
+    pthread_mutex_lock(&buf->lock);
+    memset(buf->start_addr, 0, buf->size);
+    buf->rd = buf->wr = buf->start_addr;
+    buf->last_is_write = 0;
+    /*
+     * if (buf->rd >= (buf->start_addr + buf->size))
+     *    buf->rd -= buf->size;
+     */
+    pthread_mutex_unlock(&buf->lock);
+
+    return 0;
+}
+
+/*************************************************
+Function: ring_buffer_reset_size
+Description: reset ring buffer and change the size
+Input: rbuffer: the ring buffer to be reset
+       buffer_size: new size for ring buffer
+Output:
+Return: 0 for success, otherwise fail
+*************************************************/
+int ring_buffer_reset_size(struct ring_buffer *rbuffer, int buffer_size)
+{
+    if (buffer_size > rbuffer->size) {
+        ALOGW("resized buffer size exceed largest buffer size, max %d, cur %d\n", \
+              rbuffer->size, buffer_size);
+        ring_buffer_release(rbuffer);
+        rbuffer->size = buffer_size;
+        return ring_buffer_init(rbuffer, buffer_size);
+    }
+
+    ALOGI("reset buffer size from %d to %d\n", rbuffer->size, buffer_size);
+
+    pthread_mutex_lock(&rbuffer->lock);
+
+    rbuffer->size = buffer_size;
+    memset(rbuffer->start_addr, 0, buffer_size);
+    rbuffer->rd = rbuffer->start_addr;
+    rbuffer->wr = rbuffer->start_addr;
+
+    pthread_mutex_unlock(&rbuffer->lock);
+
+    return 0;
+}
+
+/*************************************************
+Function: get_buffer_read_space
+Description: get the data space for reading in the buffer
+Input: rbuffer: the ring buffer with data
+Output:
+Return: data space for success, otherwise < 0
+*************************************************/
+int get_buffer_read_space(struct ring_buffer *rbuffer)
+{
+    size_t read_space = 0;
+
+    pthread_mutex_lock(&rbuffer->lock);
+    if (rbuffer->start_addr == NULL || rbuffer->wr == NULL || rbuffer->rd == NULL
+            || rbuffer->size == 0) {
+        ALOGE("%s, Buffer malloc fail!\n", __FUNCTION__);
+        pthread_mutex_unlock(&rbuffer->lock);
+        return -1;
+    }
+
+    read_space = get_read_space(rbuffer->wr, rbuffer->rd, rbuffer->size, rbuffer->last_is_write);
+    pthread_mutex_unlock(&rbuffer->lock);
+
+    return read_space;
+}
+
+/*************************************************
+Function: get_buffer_write_space
+Description: get the space for writing in the buffer
+Input: rbuffer: the ring buffer to be written
+Output:
+Return: data space for success, otherwise < 0
+*************************************************/
+int get_buffer_write_space(struct ring_buffer *rbuffer)
+{
+    size_t write_space = 0;
+
+    pthread_mutex_lock(&rbuffer->lock);
+    if (rbuffer->start_addr == NULL || rbuffer->wr == NULL || rbuffer->wr == NULL
+        || rbuffer->size == 0) {
+        ALOGE("%s, Buffer malloc fail!\n", __FUNCTION__);
+        pthread_mutex_unlock(&rbuffer->lock);
+        return -1;
+    }
+
+    write_space = get_write_space(rbuffer->wr, rbuffer->rd, rbuffer->size, rbuffer->last_is_write);
+    pthread_mutex_unlock(&rbuffer->lock);
+
+    return write_space;
+}
+
+/*************************************************
+Function: ring_buffer_dump
+Description: dump the ringbuffer status
+Input: rbuffer: the ring buffer to be dumped
+Output:
+Return: NULL
+*************************************************/
+void ring_buffer_dump(struct ring_buffer *rbuffer)
+{
+    ALOGI("-buffer_size:%d", rbuffer->size);
+    ALOGI("-buffer_avail:%d, buffer_space:%d", get_buffer_read_space(rbuffer), get_buffer_write_space(rbuffer));
+}
+#ifdef __cplusplus
+}
+#endif
diff --git a/utils/aml_volume_utils.c b/utils/aml_volume_utils.c
new file mode 100755
index 0000000..63cfa4a
--- /dev/null
+++ b/utils/aml_volume_utils.c
@@ -0,0 +1,85 @@
+/*
+ * hardware/amlogic/audio/utils/aml_volume_utils.c
+ *
+ * Copyright (C) 2017 Amlogic, Inc. All rights reserved.
+ *
+ * This source code is subject to the terms and conditions defined in the
+ * file 'LICENSE' which is part of this source code package.
+ *
+ */
+
+#define LOG_TAG "aml_volume_utils"
+
+#include <stdlib.h>
+#include <stdint.h>
+#include <unistd.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <cutils/log.h>
+
+#include "aml_volume_utils.h"
+
+/* default volume cruve in dB. 101 index.
+   0 is mute, 100 is the max volume.
+   normally, 0dB is the max volume*/
+#define AUDIO_VOLUME_INDEX 101
+static float volume_cruve_in_dB[AUDIO_VOLUME_INDEX] = {
+    VOLUME_MIN_DB, /*mute*/
+    -60,   -53,   -47.5, -43.5, -39,   -36,   -34,   -32,   -30,   -28,    /*1-10*/
+    -27,   -26,   -25,   -24,   -23,   -22.2, -21.5, -21,   -20.6, -20.3,  /*11-20*/
+    -19.9, -19.5, -19,   -18.7, -18.4, -18.2, -18,   -17.8, -17.5, -17.3,  /*21-30*/
+    -17,   -16.8, -16.5, -16.2, -15.9, -15.6, -15.4, -15.2, -14.9, -14.7,  /*31-40*/
+    -14.4, -14.1, -13.9, -13.7, -13.5, -13.3, -13.1, -12.9, -12.7, -12.4,  /*41-50*/
+    -12.1, -11.8, -11.6, -11.4, -11.2, -11,   -10.8, -10.6, -10.3, -10,    /*51-60*/
+    -9.8,  -9.6,  -9.4,  -9.2,  -9,    -8.7,  -8.4,  -8.1,  -7.8,  -7.5,   /*61-70*/
+    -7.2,  -6.9,  -6.7,  -6.4,  -6.1,  -5.8,  -5.5,  -5.2,  -5,    -4.8,   /*71-80*/
+    -4.7,  -4.5,  -4.3,  -4.1,  -3.8,  -3.6,  -3.3,  -3,    -2.7,  -2.5,   /*81-90*/
+    -2.2,  -2,    -1.8,  -1.5,  -1.3,  -1,    -0.8,  -0.5,  -0.3,  0,      /*91-100*/
+};
+
+static inline int16_t clamp16(int32_t sample) {
+    if ((sample >> 15) ^ (sample >> 31))
+        sample = 0x7FFF ^ (sample >> 31);
+    return sample;
+}
+
+static inline int32_t clamp32(int64_t sample)
+{
+    if ((sample >> 31) ^ (sample >> 63))
+        sample = 0x7FFFFFFF ^ (sample >> 63);
+    return sample;
+}
+
+void apply_volume(float volume, void *buf, int sample_size, int bytes) {
+    int16_t *input16 = (int16_t *)buf;
+    int32_t *input32 = (int32_t *)buf;
+    unsigned int i = 0;
+
+    if (sample_size == 2) {
+        for (i = 0; i < bytes/sizeof(int16_t); i++) {
+            int32_t samp = (int32_t)(input16[i]);
+            input16[i] = clamp16((int32_t)(volume * samp));
+        }
+    } else if (sample_size == 4) {
+        for (i = 0; i < bytes/sizeof(int32_t); i++) {
+            int64_t samp = (int64_t)(input32[i]);
+            input32[i] = clamp32((int64_t)(volume * samp));
+        }
+    } else {
+        ALOGE("%s, unsupported audio format: %d!\n", __FUNCTION__, sample_size);
+    }
+    return;
+}
+
+float get_volume_by_index(int volume_index) {
+    float volume = 1.0;
+    if (volume_index >= AUDIO_VOLUME_INDEX) {
+        ALOGE("%s, invalid index!\n", __FUNCTION__);
+        return volume;
+    }
+    if (volume_index >= 0)
+        volume *= DbToAmpl(volume_cruve_in_dB[volume_index]);
+
+    return volume;
+}
+
diff --git a/utils/include/SPDIFEncoderAD.h b/utils/include/SPDIFEncoderAD.h
new file mode 100755
index 0000000..f6f3041
--- /dev/null
+++ b/utils/include/SPDIFEncoderAD.h
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2017 Amlogic Corporation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __SPDIFENCODER_AD_H__
+#define __SPDIFENCODER_AD_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ *@brief init the spdif encoder advanced
+ */
+int spdif_encoder_ad_init(audio_format_t format, const void *output, int max_output_size);
+
+/*
+ *@brief send the data to spdif encoder advaned
+ */
+int spdif_encoder_ad_write(const void *buffer, size_t numBytes);
+
+/*
+ *@brief get total iec61937 data size
+ */
+uint64_t spdif_encoder_ad_get_total();
+
+/*
+ *@brief get current iec61937 data size
+ */
+size_t spdif_encoder_ad_get_current_position(void);
+
+/*
+ *@brief flush output iec61937 data current position to zero!
+ */
+void spdif_encoder_ad_flush_output_current_position(void);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif  //__SPDIFENCODER_AD_H__
diff --git a/utils/include/ac3_parser_utils.h b/utils/include/ac3_parser_utils.h
new file mode 100755
index 0000000..26f5f1d
--- /dev/null
+++ b/utils/include/ac3_parser_utils.h
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2017 Amlogic Corporation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef _AC3_PARSER_UTILS_H_
+#define _AC3_PARSER_UTILS_H_
+
+#define BS_STD           8
+#define ISDD(bsid)       ((bsid) <= BS_STD)
+#define BS_AXE           16
+#define ISDDP(bsid)      ((bsid) <= BS_AXE && (bsid) > 10)
+
+
+/*
+ *parse ac3/eac3 frame header[ATSC Standard,Digital Audio Compression (AC-3, E-AC-3)]
+ * input params:
+ *          frameBuf: input data address
+ *          length: data length
+ *          frame_offset: frame begin offset
+ *          frame_size: frame size
+ *          chanenel_num: frame channel num
+ *          numblks: numblks of one frame
+ *          timeslice_61937: time slice of iec61937
+ *          framevalid_flag: frame valid flag
+ * return value:
+ *          0, success find one frame
+ *          1, fail to find one frame
+ */
+int parse_dolby_frame_header
+    (const unsigned char *frameBuf
+    , int length
+    , int *frame_offset
+    , int *frame_size
+    , int *channel_num
+    , int *numblks
+    , int *timeslice_61937
+    , int *framevalid_flag);
+
+
+#endif //end of _AC3_PARSER_UTILS_H_
+
diff --git a/utils/include/aml_alsa_mixer.h b/utils/include/aml_alsa_mixer.h
new file mode 100644
index 0000000..56154c6
--- /dev/null
+++ b/utils/include/aml_alsa_mixer.h
@@ -0,0 +1,169 @@
+/*
+ * Copyright (C) 2017 Amlogic Corporation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef _AML_ALSA_MIXER_H_
+#define _AML_ALSA_MIXER_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ *  Value of the Alsa Mixer Control Point
+ **/
+/* Audio i2s mute */
+typedef enum MIXER_AUDIO_I2S_MUTE {
+    I2S_MUTE_OFF = 0,
+    I2S_MUTE_ON  = 1,
+    I2S_MUTE_MAX,
+} eMixerAudioI2sMute;
+
+/* Audio spdif mute */
+typedef enum MIXER_SPDIF_MUTE {
+    SPDIF_MUTE_OFF = 0,
+    SPDIF_MUTE_ON  = 1,
+    SPDIF_MUTE_MAX,
+} eMixerSpdifMute;
+
+/* Audio In Source */
+typedef enum MIXER_AUDIO_IN_SOURCE {
+    AUDIOIN_SRC_LINEIN  = 0,
+    AUDIOIN_SRC_ATV     = 1,
+    AUDIOIN_SRC_HDMI    = 2,
+    AUDIOIN_SRC_SPDIFIN = 3,
+    AUDIOIN_SRC_MAX,
+} eMixerAudioInSrc;
+
+/* Audio I2SIN Audio Type */
+typedef enum MIXER_I2SIN_AUDIO_TYPE {
+    I2SIN_AUDIO_TYPE_LPCM      = 0,
+    I2SIN_AUDIO_TYPE_NONE_LPCM = 1,
+    I2SIN_AUDIO_TYPE_UN_KNOWN  = 2,
+    I2SIN_AUDIO_TYPE_MAX,
+} eMixerI2sInAudioType;
+
+/* Audio SPDIFIN Audio Type */
+typedef enum MIXER_SPDIFIN_AUDIO_TYPE {
+    SPDIFIN_AUDIO_TYPE_LPCM   = 0,
+    SPDIFIN_AUDIO_TYPE_AC3    = 1,
+    SPDIFIN_AUDIO_TYPE_EAC3   = 2,
+    SPDIFIN_AUDIO_TYPE_DTS    = 3,
+    SPDIFIN_AUDIO_TYPE_DTSHD  = 4,
+    SPDIFIN_AUDIO_TYPE_TRUEHD = 5,
+    SPDIFIN_AUDIO_TYPE_PAUSE  = 6,
+    SPDIFIN_AUDIO_TYPE_MAX,
+} eMixerApdifinAudioType;
+
+/* Hardware resample enable */
+typedef enum MIXER_HW_RESAMPLE_ENABLE {
+    HW_RESAMPLE_DISABLE = 0,
+    HW_RESAMPLE_ENABLE  = 1,
+    HW_RESAMPLE_MAX,
+} eMixerHwResample;
+
+/* Output Swap */
+typedef enum MIXER_OUTPUT_SWAP {
+    OUTPUT_SWAP_LR = 0,
+    OUTPUT_SWAP_LL = 1,
+    OUTPUT_SWAP_RR = 2,
+    OUTPUT_SWAP_RL = 3,
+    OUTPUT_SWAP_MAX,
+} eMixerOutputSwap;
+
+/* spdifin/arcin */
+typedef enum AUDIOIN_SWITCH {
+    SPDIF_IN = 0,
+    ARC_IN = 1,
+} eMixerAudioinSwitch;
+
+struct aml_mixer_ctrl {
+    int  ctrl_idx;
+    char ctrl_name[50];
+};
+
+/*
+ *  Alsa Mixer Control Command List
+ **/
+typedef enum AML_MIXER_CTRL_ID {
+    AML_MIXER_ID_I2S_MUTE = 0,
+    AML_MIXER_ID_SPDIF_MUTE,
+    AML_MIXER_ID_HDMI_OUT_AUDIO_MUTE,
+    AML_MIXER_ID_HDMI_ARC_AUDIO_ENABLE,
+    AML_MIXER_ID_AUDIO_IN_SRC,
+    AML_MIXER_ID_I2SIN_AUDIO_TYPE,
+    AML_MIXER_ID_SPDIFIN_AUDIO_TYPE,
+    AML_MIXER_ID_HW_RESAMPLE_ENABLE,
+    AML_MIXER_ID_OUTPUT_SWAP,
+    AML_MIXER_ID_HDMI_IN_AUDIO_STABLE,
+    AML_MIXER_ID_HDMI_IN_SAMPLERATE,
+    AML_MIXER_ID_HDMI_IN_CHANNELS,
+    AML_MIXER_ID_HDMI_IN_FORMATS,
+    AML_MIXER_ID_HDMI_ATMOS_EDID,
+    AML_MIXER_ID_ATV_IN_AUDIO_STABLE,
+    AML_MIXER_ID_SPDIF_FORMAT,
+    AML_MIXER_ID_AV_IN_AUDIO_STABLE,
+    AML_MIXER_ID_EQ_MASTER_VOLUME,
+    AML_MIXER_ID_SPDIFIN_ARCIN_SWITCH,
+    AML_MIXER_ID_MAX,
+} eMixerCtrlID;
+
+/*
+ *tinymix "Audio spdif format" list
+ */
+enum AML_SPDIF_FORMAT
+{
+    AML_STEREO_PCM = 0,
+    AML_DTS_RAW_MODE = 1,
+    AML_DOLBY_DIGITAL = 2,
+    AML_DTS = 3,
+    AML_DOLBY_DIGITAL_PLUS = 4,
+    AML_DTS_HD = 5,
+    AML_MULTI_CH_LPCM = 6,
+    AML_TRUE_HD = 7,
+    AML_DTS_HD_MA = 8,
+    AML_HIGH_SR_STEREO_LPCM = 9,
+};
+
+struct aml_mixer_list {
+    int  id;
+    char mixer_name[50];
+};
+
+/*
+ * get interface
+ **/
+int aml_mixer_ctrl_get_int(int mixer_id);
+int aml_mixer_ctrl_get_enum_str_to_int(int mixer_id, int *ret);
+
+//int aml_mixer_ctrl_get_str(int mixer_id, char *value);
+// or
+#if 0
+int aml_mixer_get_audioin_src(int mixer_id);
+int aml_mixer_get_i2sin_type(int mixer_id);
+int aml_mixer_get_spdifin_type(int mixer_id);
+#endif
+
+/*
+ * set interface
+ **/
+int aml_mixer_ctrl_set_int(int mixer_id, int value);
+int aml_mixer_ctrl_set_str(int mixer_id, char *value);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/utils/include/aml_android_utils.h b/utils/include/aml_android_utils.h
new file mode 100755
index 0000000..be3be9c
--- /dev/null
+++ b/utils/include/aml_android_utils.h
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2017 Amlogic Corporation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef _AML_ANDROID_UTILS_H_
+#define _AML_ANDROID_UTILS_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef enum AML_BOOLEAN_DEFINE {
+	eAML_BOOL_FALSE = 0,
+	eAML_BOOL_TRUE  = 1,
+} eAmlBoolean;
+
+/*
+ * Android Property Interface
+ */
+int aml_getprop_bool(const char *path);
+int aml_getprop_int(const char *path);
+
+/*
+ * Sys Fs Interface
+ */
+int aml_sysfs_get_int(const char *path);
+int aml_sysfs_get_int16(const char *path, unsigned *value);
+int aml_sysfs_get_str(const char *path, char *buf, int count);
+int aml_sysfs_set_int(const char *path, int value);
+int aml_sysfs_set_str(const char *path, const char *value);
+
+/*
+ * Others
+ */
+int aml_strstr(char *mystr,char *substr);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/utils/include/aml_audio_hal_conf.h b/utils/include/aml_audio_hal_conf.h
new file mode 100755
index 0000000..c26c312
--- /dev/null
+++ b/utils/include/aml_audio_hal_conf.h
@@ -0,0 +1,72 @@
+/*
+ * Copyright (C) 2017 Amlogic Corporation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef _AML_AUDIO_HAL_CONF_H_
+#define _AML_AUDIO_HAL_CONF_H_
+
+enum eAudioHalConfType {
+	eAmlConfTypeChMap = 0,
+	eAmlConfTypeChInv = 1,
+	eAmlConfTypeChDit = 2,
+};
+
+/* channel map need move to *.dts in kernel */
+// hardware channel map@i2s port
+#define AML_I2S_CHANNEL0 "i2s.channel0"
+#define AML_I2S_CHANNEL1 "i2s.channel1"
+#define AML_I2S_CHANNEL2 "i2s.channel2"
+#define AML_I2S_CHANNEL3 "i2s.channel3"
+#define AML_I2S_CHANNEL4 "i2s.channel4"
+#define AML_I2S_CHANNEL5 "i2s.channel5"
+#define AML_I2S_CHANNEL6 "i2s.channel6"
+#define AML_I2S_CHANNEL7 "i2s.channel7"
+
+// if need invert the data before send to i2s port
+#define AML_I2S_INVERT_CH0 "i2s.invert.channel0"
+#define AML_I2S_INVERT_CH1 "i2s.invert.channel1"
+#define AML_I2S_INVERT_CH2 "i2s.invert.channel2"
+#define AML_I2S_INVERT_CH3 "i2s.invert.channel3"
+#define AML_I2S_INVERT_CH4 "i2s.invert.channel4"
+#define AML_I2S_INVERT_CH5 "i2s.invert.channel5"
+#define AML_I2S_INVERT_CH6 "i2s.invert.channel6"
+#define AML_I2S_INVERT_CH7 "i2s.invert.channel7"
+
+/* dap */
+// enable aml software dap process
+#define AML_SW_DAP_ENABLE  "aml.dap.enable"
+
+/* lfe */
+// enable aml iir
+#define AML_SW_IIR_ENABLE  "aml.iir.enable"
+
+/* others */
+// if have real center channel
+#define AML_SPK_HAVE_CENTER "speaker.center.enable"
+
+/* ditter, only need on ATMOS dsp now */
+// if need ditter on i2s data
+#define AML_DITTER_ENABLE   "i2s.ditter.enable"
+// enable ditter@i2s channel
+#define AML_DITTER_I2S_CH0  "i2s.ditter.channel0"
+#define AML_DITTER_I2S_CH1  "i2s.ditter.channel1"
+#define AML_DITTER_I2S_CH2  "i2s.ditter.channel2"
+#define AML_DITTER_I2S_CH3  "i2s.ditter.channel3"
+#define AML_DITTER_I2S_CH4  "i2s.ditter.channel4"
+#define AML_DITTER_I2S_CH5  "i2s.ditter.channel5"
+#define AML_DITTER_I2S_CH6  "i2s.ditter.channel6"
+#define AML_DITTER_I2S_CH7  "i2s.ditter.channel7"
+
+#endif
diff --git a/utils/include/aml_audio_hal_product_cfg.h b/utils/include/aml_audio_hal_product_cfg.h
new file mode 100755
index 0000000..6d307ee
--- /dev/null
+++ b/utils/include/aml_audio_hal_product_cfg.h
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2017 Amlogic Corporation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef _AML_AUDIO_HAL_PRODUCT_CFG_H_
+#define _AML_AUDIO_HAL_PRODUCT_CFG_H_
+
+#include "parser.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct parser *aml_hal_config_load(const char *file_name);
+int aml_hal_config_unload(struct parser *pParser);
+int aml_hal_config_dump(struct parser *pParser);
+const char *aml_hal_cfg_get_str(struct parser *pParser, const char *key, const char *def_value);
+int aml_hal_config_get_int(struct parser *pParser, const char *key, const int def_value);
+float aml_hal_config_get_float(struct parser *pParser, const char *key, const float def_value);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/utils/include/aml_audio_mixer.h b/utils/include/aml_audio_mixer.h
new file mode 100755
index 0000000..b6aef16
--- /dev/null
+++ b/utils/include/aml_audio_mixer.h
@@ -0,0 +1,117 @@
+/*
+ * Copyright (C) 2017 Amlogic Corporation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef _AML_AUDIO_MIXER_H_
+#define _AML_AUDIO_MIXER_H_
+
+#include <tinyalsa/asoundlib.h>
+#include <aml_ringbuffer.h>
+
+__BEGIN_DECLS
+
+/**
+ * Audio mixer:
+ * only support mixing two steams, one main stream and one aux stream.
+ * And the output streams configs must be same as input streams.
+ * TODO: add formats adaptions.
+ */
+struct aml_audio_mixer;
+
+/**
+ * callback function that user should register to the mixer,
+ * mixer will pop mixed data out to buffer when ready.
+ */
+typedef int (*mixer_write_callback)(void *buffer, void *priv, size_t size);
+
+/**
+ * constructor with mixer output pcm configs
+ * return NULL if no enough memory.
+ */
+struct aml_audio_mixer *new_aml_audio_mixer(struct pcm_config out_config);
+
+/**
+ * distructor to free the mixer
+ */
+void aml_delete_audio_mixer(struct aml_audio_mixer *audio_mixer);
+
+/**
+ * register the main input pcm config and ringbuffer to mixer.
+ * if ringbuffer == NULL, then alloc the input ringbuffer according to cfg internally.
+ * return < 0 if failed.
+ */
+int aml_register_mixer_main_in_buffer(struct aml_audio_mixer *audio_mixer,
+            struct ring_buffer *ringbuffer, struct pcm_config cfg);
+
+
+/**
+ * register the aux input pcm config and ringbuffer to mixer.
+ * if ringbuffer == NULL, then alloc the input ringbuffer according to cfg internally.
+ * return < 0 if failed.
+ */
+int aml_register_mixer_aux_in_buffer(struct aml_audio_mixer *audio_mixer,
+            struct ring_buffer *ringbuffer, struct pcm_config cfg);
+
+/**
+ * release the main in ringbuffer
+ */
+int aml_release_main_in_buffer(struct aml_audio_mixer *audio_mixer);
+
+/**
+ * release the aux in ringbuffer
+ */
+int aml_release_aux_in_buffer(struct aml_audio_mixer *audio_mixer);
+
+/**
+ * write size of data to mixer main in ringbuffer from buffer
+ */
+int aml_write_mixer_main_in_buf(struct aml_audio_mixer *audio_mixer, void *buffer, size_t size);
+
+/**
+ * write size of data to mixer aux in ringbuffer from buffer
+ */
+int aml_write_mixer_aux_in_buf(struct aml_audio_mixer *audio_mixer, void *buffer, size_t size);
+
+/**
+ * register user callback to audio mixer which will be called when data ready
+ * priv_data is used in callback function
+ */
+int aml_register_audio_mixer_callback(struct aml_audio_mixer *audio_mixer, mixer_write_callback cbk, void *priv_data);
+
+/**
+ * release user callback to audio mixer
+ */
+int aml_release_audio_mixer_callback(struct aml_audio_mixer *audio_mixer);
+
+/**
+ * start the mixing thread
+ * return < 0 if failed.
+ */
+int aml_start_audio_mixer(struct aml_audio_mixer *audio_mixer);
+
+/**
+ * stop the mixing thread
+ * return < 0 if failed.
+ */
+int aml_stop_audio_mixer(struct aml_audio_mixer *audio_mixer);
+
+/**
+ * dump the audiomixer status
+ */
+void aml_dump_audio_mixer(struct aml_audio_mixer *audio_mixer);
+
+__END_DECLS
+
+#endif
diff --git a/utils/include/aml_audio_resampler.h b/utils/include/aml_audio_resampler.h
new file mode 100644
index 0000000..6ad10f9
--- /dev/null
+++ b/utils/include/aml_audio_resampler.h
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2017 Amlogic Corporation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __AUDIO_RESAMPLER_H__
+#define __AUDIO_RESAMPLER_H__
+
+#define MAX_RESAMPLE_CHANNEL 8
+
+struct resample_para {
+    unsigned int FractionStep;
+    unsigned int SampleFraction;
+    unsigned int input_sr;
+    unsigned int output_sr;
+    unsigned int channels;
+    int16_t lastsample[MAX_RESAMPLE_CHANNEL];
+};
+
+int resampler_init(struct resample_para *resample);
+int resample_process(struct resample_para *resample, unsigned int in_frame,
+    int16_t* input, int16_t* output);
+
+#endif
diff --git a/utils/include/aml_buffer_provider.h b/utils/include/aml_buffer_provider.h
new file mode 100755
index 0000000..75071aa
--- /dev/null
+++ b/utils/include/aml_buffer_provider.h
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2017 Amlogic Corporation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef _BUFFER_PROVIDER_H
+#define _BUFFER_PROVIDER_H
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+int init_buffer_provider();
+int release_buffer_provider();
+struct ring_buffer *get_general_buffer();
+struct ring_buffer *get_DDP_buffer();
+struct ring_buffer *get_DD_61937_buffer();
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/utils/include/aml_conf_loader.h b/utils/include/aml_conf_loader.h
new file mode 100755
index 0000000..1bae2f2
--- /dev/null
+++ b/utils/include/aml_conf_loader.h
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2017 Amlogic Corporation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef _LOADER_H_
+#define _LOADER_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct parser *aml_config_load(const char *file_name);
+int aml_config_unload(struct parser *pParser);
+int aml_config_dump(struct parser *pParser, const char *section);
+/* get */
+const char *aml_config_get_str(struct parser *pParser, const char *section,  const char *key, const char *def_value);
+int aml_config_get_int(struct parser *pParser, const char *section, const char *key, const int def_value);
+float aml_config_get_float(struct parser *pParser, const char *section, const char *key, const float def_value);
+#ifndef AML_CONFIG_SUPPORT_READ_ONLY
+/* set */
+int aml_config_set_str(struct parser *pParser, const char *section,  const char *key, const char *value);
+int aml_config_set_int(struct parser *pParser, const char *section,  const char *key, int value);
+int aml_config_set_float(struct parser *pParser, const char *section,  const char *key, float value);
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/utils/include/aml_conf_parser.h b/utils/include/aml_conf_parser.h
new file mode 100755
index 0000000..ec00d39
--- /dev/null
+++ b/utils/include/aml_conf_parser.h
@@ -0,0 +1,107 @@
+/*
+ * Copyright (C) 2017 Amlogic Corporation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef _PARSER_H_
+#define _PARSER_H_
+
+#define MAX_INI_FILE_LINE_LEN (512)
+
+/*
+ * example.conf
+ * ----------------------------------------------------------------------------
+ * [SECTION_0]
+ *
+ * # this is a comment
+ * configname_1 = true
+ * configname_2 = 1234
+ * configname_3 = 11.2
+ *
+ * [SECTION_1]
+ *
+ * configname_1 = true
+ * configname_2 = 1234
+ * # this is a comment
+ * configname_3 = 11.2
+ * ----------------------------------------------------------------------------
+ */
+/**
+ ** Line Type
+ **/
+typedef enum _LINE_TYPE {
+    LINE_TYPE_SECTION = 0, // Section line
+    LINE_TYPE_KEY,         // Config item line
+    LINE_TYPE_COMMENT,     // Comment line
+} eLineType;
+
+/**
+ ** Link of One Line
+ **/
+typedef struct _LINE {
+    eLineType    type;                        // line type
+    char         Text[MAX_INI_FILE_LINE_LEN]; // whole content of this line
+    int          LineLen;                     // length
+    char         *pKeyStart;                  // pointer to start of key
+    char         *pKeyEnd;
+    char         *pValueStart;                // pointer to start of value
+    char         *pValueEnd;
+    struct _LINE *pNext;                      // next line
+} LINE;
+
+/**
+ ** Link of Section
+ **/
+typedef struct _SECTION {
+    LINE            *pLine;                   // first line in this section
+    struct _SECTION *pNext;                   // next section in this config file
+} SECTION;
+
+/**
+ ** Parser
+ **/
+struct parser {
+    char    mpFileName[256];                  // path of config file
+    FILE    *m_pIniFile;                      // handle
+    LINE    *mpFirstLine;                     // first line in this config file
+    SECTION *mpFirstSection;                  // first section in this config file
+};
+
+/* load from */
+#define AML_PARAM_AUDIO_HAL_SYSTEM "/system/etc/tvaudiohal.conf"
+/* save to */
+#define AML_PARAM_AUDIO_HAL_PARAM  "/mnt/vendor/param/tvaudiohal.conf"
+
+#define AML_SECTION_AUDIO_HAL      "AUDIO_HAL"
+
+/**
+ **  APIS
+ **/
+int parser_init(struct parser *pParser);
+int parser_delete(struct parser *pParser);
+int parser_load_from_file(struct parser *pParser, const char *filename);
+/* dump api */
+int parser_dump(struct parser *pParser, const char *section);
+/* get apis */
+const char *parser_get_string(struct parser *pParser, const char *section, const char *key, const char *def_value);
+int parser_get_int(struct parser *pParser, const char *section, const char *key, int def_value);
+float parser_get_float(struct parser *pParser, const char *section, const char *key, float def_value);
+#ifndef AML_CONFIG_SUPPORT_READ_ONLY
+/* set apis */
+int parser_set_string(struct parser *pParser, const char *section, const char *key, const char *value);
+int parser_set_int(struct parser *pParser, const char *section, const char *key, int value);
+int parser_set_float(struct parser *pParser, const char *section, const char *key, float value);
+#endif
+
+#endif
diff --git a/utils/include/aml_data_utils.h b/utils/include/aml_data_utils.h
new file mode 100755
index 0000000..377575a
--- /dev/null
+++ b/utils/include/aml_data_utils.h
@@ -0,0 +1,349 @@
+/*
+ * Copyright (C) 2017 Amlogic Corporation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef _AML_DATA_UTILS_H_
+#define _AML_DATA_UTILS_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+enum eSAMPLE_SIZE {
+	e16BitPerSample = 2,
+	e32BitPerSample = 4,
+};
+
+#define MINUS_3_DB_IN_Q19_12 2896 // -3dB = 0.707 * 2^12 = 2896
+
+typedef enum CHANNEL_CONTENT_INDEX {
+	AML_CH_IDX_NULL      = -1,
+	AML_CH_IDX_L         = 0,
+	AML_CH_IDX_R         = 1,
+	AML_CH_IDX_C         = 2,
+	AML_CH_IDX_LFE       = 3,
+	AML_CH_IDX_LS        = 4,
+	AML_CH_IDX_RS        = 5,
+	AML_CH_IDX_LT        = 6,
+	AML_CH_IDX_RT        = 7,
+	AML_CH_IDX_MAX       = 8,
+	AML_CH_IDX_5_1_ALL   = 0x003F,
+	AML_CH_IDX_7_1_ALL   = 0x00FF,
+	AML_CH_IDX_5_1_2_ALL = 0x033F,
+} eChannelContentIdx;
+
+struct aml_audio_channel_name {
+	int  ch_idx;
+	char ch_name[50];
+};
+
+typedef enum I2S_DATALINE_INDEX {
+	AML_I2S_PORT_IDX_01   = 0,
+	AML_I2S_PORT_IDX_23   = 1,
+	AML_I2S_PORT_IDX_45   = 2,
+	AML_I2S_PORT_IDX_67   = 3,
+	AML_I2S_PORT_IDX_NULL = 0x8000,
+	AML_I2S_PORT_IDX_MAX  = 0xFFFF,
+} eI2SDataLineIdx;
+
+typedef enum CHANNEL_ON_I2S_BIT_MASK{
+	AML_I2S_CHANNEL_NULL = 0x0,
+	AML_I2S_CHANNEL_0    = 0x1<<0,
+	AML_I2S_CHANNEL_1    = 0x1<<1,
+	AML_I2S_CHANNEL_2    = 0x1<<2,
+	AML_I2S_CHANNEL_3    = 0x1<<3,
+	AML_I2S_CHANNEL_4    = 0x1<<4,
+	AML_I2S_CHANNEL_5    = 0x1<<5,
+	AML_I2S_CHANNEL_6    = 0x1<<6,
+	AML_I2S_CHANNEL_7    = 0x1<<7,
+} eChOnI2SBitMask;
+
+#define AML_I2S_CHANNEL_COUNT  (8)
+#define AML_CH_CNT_PER_PORT    (2)
+
+struct aml_channel_map {
+	eChannelContentIdx channel_idx;
+	// WARNNING: support map to only one i2s data line
+	eI2SDataLineIdx    i2s_idx;
+	// WARNNING: may be one channel will map to 2 i2s data channel
+	// eg, i2s_23 -> lfe/lfe
+	eChOnI2SBitMask    bit_mask;
+	// invert
+	eChOnI2SBitMask    invert;
+	// ditter
+	eChOnI2SBitMask    ditter;
+};
+
+/******************************************************************************
+ * Function: data_load_product_config()
+ * Description:
+ *      initial/load channel maps for current product
+ * Input:  NULL
+ * Output: NULL
+ * Return: Hw I2S Ch Maps
+ *****************************************************************************/
+#if !defined (BUILDHOSTEXE)
+struct aml_channel_map *data_load_product_config(void);
+#endif
+
+/******************************************************************************
+ * Function: data_get_channel_i2s_port()
+ * Description:
+ *       get hw i2s port for channel "channelName"
+ * Input:  eChannelContentIdx
+ * Output:
+ * Return: eI2SDataLineIdx
+ *****************************************************************************/
+int data_get_channel_i2s_port(
+	struct aml_channel_map *map,
+	eChannelContentIdx channelName);
+
+eChannelContentIdx data_get_channel_content_idx(
+	struct aml_channel_map *map,
+	int bitmask);
+
+/******************************************************************************
+ * Function: data_get_channel_bit_mask()
+ * Description:
+ *       get hw i2s bit mask for channel "channelName"
+ * Input:  eChannelContentIdx
+ * Output:
+ * Return: eChOnI2SBitMask
+ *****************************************************************************/
+int data_get_channel_bit_mask(
+	struct aml_channel_map *map,
+	eChannelContentIdx channelName);
+
+/******************************************************************************
+ * Function: data_empty_channels()
+ * Description:
+ *     clean channel data
+ * Input:
+ *     buf                    - input data
+ *     frames                 - frame count
+ *     framesz                - frame size
+ *     channels               - channel count
+ *     channel_empty_bit_mask - eChOnI2SBitMask, bit mask of channels which will
+ *                              be empty
+ * Output:
+ *     buf                    - output data
+ * Return: Zero if success
+ *****************************************************************************/
+int data_empty_channels(
+	struct  aml_channel_map *map,
+	void    *buf,
+	size_t  frames,
+	size_t  framesz,
+	int     channels,
+	int     channel_empty_bit_mask);
+
+/******************************************************************************
+ * Function: data_remix_to_lr_channel()
+ * Description: re-mix data to LR channel
+ * Input:
+ *      buf                        - Input Buffer
+ *      frames                     - Count of frames
+ *      framesz                    - Frame size(eg, 16bits->2, 32bits->4)
+ *      channels                   - Count of channels
+ *      channel_remix_src_bit_mask - Which channel will be remix
+ * Output:
+ *      buf                        - Output Buffer
+ * Return: Zero if success
+ *****************************************************************************/
+int data_remix_to_lr_channel(
+	struct  aml_channel_map *map,
+	void    *buf,
+	size_t  frames,
+    size_t  framesz,
+	int     channels,
+	eChannelContentIdx chIdx);
+
+/******************************************************************************
+ * Function: data_exchange_i2s_channels()
+ * Description:
+ *     exchange data between i2s_idx1 and i2s_idx2
+ *     only support exchange between different i2s port
+ * Input:
+ *     buf      - input data
+ *     channels - channel count
+ *     frames   - frame count
+ *     framesz  - frame size
+ *     i2s_idx1 - index of i2s data line 1 for exchange
+ *     i2s_idx2 - index of i2s data line 2 for exchange
+ * Output:
+ *     buf      - output data
+ * Return: Zero if success
+ *****************************************************************************/
+int data_exchange_i2s_channels(
+	void    *buf,
+	size_t  frames,
+	size_t  framesz,
+	size_t  channels,
+	eI2SDataLineIdx i2s_idx1,
+	eI2SDataLineIdx i2s_idx2);
+
+/******************************************************************************
+ * Function: data_replace_lfe_data()
+ * Description:
+ *     replace lfe data
+ * Input:
+ *     out_channles            - channel count of putput data
+ *     out_framesz             - frame size of output
+ *     input_lfe_buffer        - input lfe data
+ *     in_channles             - channel count of input data
+ *     in_framesz              - frame size of input
+ *     frames                  - frame count
+ *     channel_insert_bit_mask - eChOnI2SBitMask, bit mask of lfe channel
+ * Output:
+ *     out_buf                 - output data
+ * Return: Zero if success
+ *****************************************************************************/
+int data_replace_lfe_data(
+	void    *out_buf,
+	size_t  out_channles,
+	size_t  out_framesz,
+	void    *input_lfe_buffer,
+	size_t  in_channles,
+	size_t  in_framesz,
+	size_t  frames,
+	int     channel_insert_bit_mask);
+
+/******************************************************************************
+ * Function: data_invert_channels()
+ * Description:
+ *     Invert the data of masked channels
+ * Input:
+ *     buf                     - input data
+ *     channels                - channel count
+ *     frames                  - frame count
+ *     framesz                 - frame size
+ *     channel_invert_bit_mask - eChOnI2SBitMask, bit mask of channels which will
+ *                               be invert
+ * Output:
+ *     buf                     - output data
+ * Return: Zero if success
+ *****************************************************************************/
+int data_invert_channels(
+	void    *buf,
+	size_t  frames,
+	size_t  framesz,
+	int     channels,
+	int     channel_invert_bit_mask);
+
+/******************************************************************************
+ * Function: data_concat_channels()
+ * Description:
+ *     connect 4*2ch data to one 8ch data.
+ * Input:
+ *     out_channels - channel count of output
+ *     out_framesz  - frame size of output data
+ *     in_buf1      - input 2ch buffer 1
+ *     in_buf2      - input 2ch buffer 2
+ *     in_buf3      - input 2ch buffer 3
+ *     in_buf4      - input 2ch buffer 4
+ *     in_channels  - channel count of all input data
+ *     in_framesz   - frame size of input data
+ *     frames       - frame count
+ * Output:
+ *     out_buf      - output data
+ * Return: Zero if success
+ *****************************************************************************/
+int data_concat_channels(
+	void    *out_buf,
+	size_t  out_channels,
+	size_t  out_framesz,
+	void    *in_buf1, void *in_buf2, void *in_buf3, void *in_buf4,
+	size_t  in_channels,
+	size_t  in_framesz,
+	size_t  frames);
+
+/******************************************************************************
+ * Function: data_add_ditter_to_channels()
+ * Description:
+ *     add ditter
+ * Input:
+ *     buffer                  - input data
+ *     channels                - channel count
+ *     frames                  - frame count
+ *     framesz                 - frame size
+ *     channel_ditter_bit_mask - eChOnI2SBitMask, bit mask of channels which will
+ *                               be add ditter
+ * Output:
+ *     buffer                  - output data
+ * Return: Zero if success
+ *****************************************************************************/
+int data_add_ditter_to_channels(
+	void    *buffer,
+	size_t  frames,
+	size_t  framesz,
+	int     channels,
+	int     channel_ditter_bit_mask);
+
+/******************************************************************************
+ * Function: data_extend_to_channels()
+ * Description: extend the data
+ * Input:
+ *     out_channels - channel count of output
+ *     out_framesz  - Frame size(eg, 16bits->2, 32bits->4)
+ *     in_buf       - Input Buffer
+ *     in_channels  - channel count of input
+ *     in_framesz   - Frame size(eg, 16bits->2, 32bits->4)
+ *     frames       - frame count
+ * Output:
+ *     out_buf      - output buffer
+ * Return: Zero if success
+ *****************************************************************************/
+int data_extend_channels(
+	void    *out_buf,
+	size_t  out_channels,
+	size_t  out_framesz,
+	void    *in_buf,
+	size_t  in_channels,
+	size_t  in_framesz,
+	size_t  frames);
+
+/******************************************************************************
+ * Function: data_extract_channels()
+ * Description: extract channel data
+ * Input:
+ *     out_channels             - channel count of output
+ *     out_framesz              - frame size of output data
+ *     in_buf                   - input buffer
+ *     in_channels              - channel count of input
+ *     in_framesz               - frame szie of input data
+ *     frames                   - frame count
+ *     channel_extract_bit_mask - eChOnI2SBitMask, ch mask will be extract
+ * Output:
+ *     out_buf                  - output buffer
+ * Return: Zero if success
+ *****************************************************************************/
+int data_extract_channels(
+	struct  aml_channel_map *map,
+	void    *out_buf,
+	size_t  out_channels,
+	size_t  out_framesz,
+	void    *in_buf,
+	size_t  in_channels,
+	size_t  in_framesz,
+	size_t  frames,
+	int     channel_extract_bit_mask);
+
+int audio_effect_real_lfe_gain(short* buffer, int frame_size, int LPF_Gain);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/utils/include/aml_dump_debug.h b/utils/include/aml_dump_debug.h
new file mode 100755
index 0000000..69fc6dc
--- /dev/null
+++ b/utils/include/aml_dump_debug.h
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2017 Amlogic Corporation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __AML_DUMP_DEBUG_H__
+#define __AML_DUMP_DEBUG_H__
+
+#define CC_DUMP_SRC_TYPE_INPUT         (0)
+#define CC_DUMP_SRC_TYPE_OUTPUT        (1)
+#define CC_DUMP_SRC_TYPE_INPUT_PARSE   (2)
+
+void DoDumpData(const void *data_buf, int size, int aud_src_type);
+
+#endif
+
diff --git a/utils/include/aml_hw_profile.h b/utils/include/aml_hw_profile.h
new file mode 100755
index 0000000..4d97a9d
--- /dev/null
+++ b/utils/include/aml_hw_profile.h
@@ -0,0 +1,70 @@
+/*
+ * Copyright (C) 2017 Amlogic Corporation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef _AML_HW_PROFILE_H_
+#define _AML_HW_PROFILE_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define MAX_CARD_NUM    2
+
+#define SOUND_CARDS_PATH  "/proc/asound/cards"
+#define SOUND_PCM_PATH    "/proc/asound/pcm"
+
+#define PCM_I2S_STRING    "I2S"
+#define PCM_SPDIF_STRING  "SPDIF"
+#define PCM_PCM2BT_STRING "pcm2bt-pcm"
+
+typedef enum PCM_STREAM_TYPE {
+	AML_STREAM_TYPE_PLAYBACK = 0,
+	AML_STREAM_TYPE_CAPTURE  = 1,
+	AML_STREAM_TYPE_MAX,
+} ePcmStreamType;
+
+
+enum {
+    TYPE_PCM = 0,
+    TYPE_AC3 = 2,
+    TYPE_DTS = 3,
+    TYPE_EAC3 = 4,
+    TYPE_DTS_HD = 5 ,
+    TYPE_MULTI_PCM = 6,
+    TYPE_TRUE_HD = 7,
+    TYPE_DTS_HD_MA = 8,//should not used after we unify DTS-HD&DTS-HD MA
+    TYPE_PCM_HIGH_SR = 9,
+};
+
+int aml_get_sound_card_main(void);
+int aml_get_sound_card_ext(ePcmStreamType type);
+
+int aml_get_i2s_port(void);
+int aml_get_spdif_port(void);
+int aml_get_pcm2bt_port(void);
+
+char* aml_get_hdmi_sink_cap(const char *keys);
+char* aml_get_hdmi_arc_cap(unsigned *ad, int maxsize, const char *keys);
+
+void aml_set_codec_type(int type);
+int  aml_get_codec_type(int format);
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/utils/include/aml_ringbuffer.h b/utils/include/aml_ringbuffer.h
new file mode 100755
index 0000000..af61c41
--- /dev/null
+++ b/utils/include/aml_ringbuffer.h
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2017 Amlogic Corporation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef _RINGBUFFER_H
+#define _RINGBUFFER_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <pthread.h>
+
+typedef struct ring_buffer {
+    pthread_mutex_t lock;
+    unsigned char *start_addr;
+    unsigned char *rd;
+    unsigned char *wr;
+    int size;
+    int last_is_write;
+}ring_buffer_t;
+
+#define UNCOVER_WRITE    0
+#define COVER_WRITE      1
+
+size_t ring_buffer_write(struct ring_buffer *rbuffer, unsigned char* data, size_t bytes, int cover);
+size_t ring_buffer_read(struct ring_buffer *rbuffer, unsigned char* buffer, size_t bytes);
+int ring_buffer_init(struct ring_buffer *rbuffer, int buffer_size);
+int ring_buffer_release(struct ring_buffer *rbuffer);
+int ring_buffer_reset(struct ring_buffer *rbuffer);
+int ring_buffer_reset_size(struct ring_buffer *rbuffer, int buffer_size);
+int get_buffer_read_space(struct ring_buffer *rbuffer);
+int get_buffer_write_space(struct ring_buffer *rbuffer);
+void ring_buffer_dump(struct ring_buffer *rbuffer);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/utils/include/aml_volume_utils.h b/utils/include/aml_volume_utils.h
new file mode 100755
index 0000000..ec13aba
--- /dev/null
+++ b/utils/include/aml_volume_utils.h
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2017 Amlogic Corporation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __AML_VOLUME_UTILS_H__
+#define __AML_VOLUME_UTILS_H__
+
+#include <math.h>
+
+// Absolute min volume in dB (can be represented in single precision normal float value)
+#define VOLUME_MIN_DB (-758)
+
+static inline float DbToAmpl(float decibels)
+{
+    if (decibels <= VOLUME_MIN_DB) {
+        return 0.0f;
+    }
+    return exp( decibels * 0.115129f); // exp( dB * ln(10) / 20 )
+}
+
+static inline float AmplToDb(float amplification)
+{
+    if (amplification == 0) {
+        return VOLUME_MIN_DB;
+    }
+    return 20 * log10(amplification);
+}
+
+float get_volume_by_index(int volume_index);
+void apply_volume(float volume, void *buf, int sample_size, int bytes);
+
+#endif
+
diff --git a/utils/include/spdifenc_wrap.h b/utils/include/spdifenc_wrap.h
new file mode 100755
index 0000000..9756b00
--- /dev/null
+++ b/utils/include/spdifenc_wrap.h
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2017 Amlogic Corporation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __SPDIFENC_WRAP_H__
+#define __SPDIFENC_WRAP_H__
+
+//#ifdef __cplusplus
+//extern "C" {
+//#endif
+
+int spdifenc_init(struct pcm *mypcm, audio_format_t format);
+int spdifenc_write(const void *buffer, size_t numBytes);
+uint64_t  spdifenc_get_total(void);
+
+//#ifdef __cplusplus
+//}
+//#endif
+
+#endif  //__SPDIFENC_WRAP_H__
diff --git a/utils/ini/IniParser.cpp b/utils/ini/IniParser.cpp
new file mode 100755
index 0000000..efcdf46
--- /dev/null
+++ b/utils/ini/IniParser.cpp
@@ -0,0 +1,414 @@
+/*
+ * Copyright (C) 2017 Amlogic Corporation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/*
+ * Author:  Shoufu Zhao <shoufu.zhao@amlogic.com>
+ */
+
+#define LOG_TAG "IniParser"
+#define LOG_NDEBUG 0
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <assert.h>
+#include <string.h>
+#include <ctype.h>
+#include <unistd.h>
+#include <errno.h>
+
+#include <utils/Log.h>
+
+#include "ini.h"
+#include "IniParser.h"
+
+IniParser::IniParser() {
+    ALOGD("%s, entering...\n", __FUNCTION__);
+    mpFirstSection = NULL;
+    mpCurSection = NULL;
+
+    mpFileName[0] = '\0';
+}
+
+IniParser::~IniParser() {
+    ALOGD("%s, entering...\n", __FUNCTION__);
+    free();
+}
+
+int IniParser::parse(const char* filename) {
+    ALOGD("%s, entering...\n", __FUNCTION__);
+
+    strncpy(mpFileName, filename, CC_MAX_INI_FILE_NAME_LEN - 1);
+    return ini_parse(filename, handler, this);
+}
+
+int IniParser::parse_mem(char* file_buf) {
+    ALOGD("%s, entering...\n", __FUNCTION__);
+    return ini_parse_mem(file_buf, handler, this);
+}
+
+int IniParser::SetSaveFileName(const char* filename) {
+    ALOGD("%s, entering...\n", __FUNCTION__);
+
+    strncpy(mpFileName, filename, CC_MAX_INI_FILE_NAME_LEN - 1);
+    return 0;
+}
+
+void IniParser::free() {
+    ALOGD("%s, entering...\n", __FUNCTION__);
+
+    INI_SECTION* pNextSec = NULL;
+    for (INI_SECTION* pSec = mpFirstSection; pSec != NULL;) {
+        pNextSec = pSec->pNext;
+
+        INI_LINE* pNextLine = NULL;
+        for (INI_LINE* pLine = pSec->pLine; pLine != NULL;) {
+            pNextLine = pLine->pNext;
+
+            if (pLine != NULL) {
+#if CC_MEMORY_NEW_DEL_TRACE == 1
+                del_mem(__FUNCTION__, "pLine", pLine);
+#endif
+
+                delete pLine;
+                pLine = NULL;
+            }
+
+            pLine = pNextLine;
+        }
+
+        if (pSec != NULL) {
+#if CC_MEMORY_NEW_DEL_TRACE == 1
+            del_mem(__FUNCTION__, "pSec", pSec);
+#endif
+
+            delete pSec;
+            pSec = NULL;
+        }
+
+        pSec = pNextSec;
+    }
+
+    mpFirstSection = NULL;
+    mpCurSection = NULL;
+
+#if CC_MEMORY_NEW_DEL_TRACE == 1
+    printNewMemND(__FUNCTION__);
+    printDelMemND(__FUNCTION__);
+    clearMemND();
+#endif
+}
+
+void IniParser::trim(char *str, char ch) {
+    char* pStr;
+
+    pStr = str;
+    while (*pStr != '\0') {
+        if (*pStr == ch) {
+            char* pTmp = pStr;
+            while (*pTmp != '\0') {
+                *pTmp = *(pTmp + 1);
+                pTmp++;
+            }
+        } else {
+            pStr++;
+        }
+    }
+}
+
+void IniParser::trim(char *str) {
+    char* pStr = NULL;
+
+    pStr = strchr(str, '\n');
+    if (pStr != NULL) {
+        *pStr = 0;
+    }
+
+    int Len = strlen(str);
+    if (Len > 0) {
+        if (str[Len - 1] == '\r') {
+            str[Len - 1] = '\0';
+        }
+    }
+
+    pStr = strchr(str, '#');
+    if (pStr != NULL) {
+        *pStr = 0;
+    }
+
+    pStr = strchr(str, ';');
+    if (pStr != NULL) {
+        *pStr = 0;
+    }
+
+    trim(str, ' ');
+    trim(str, '{');
+    trim(str, '\\');
+    trim(str, '}');
+    trim(str, '\"');
+    return;
+}
+
+void IniParser::print() {
+    for (INI_SECTION* pSec = mpFirstSection; pSec != NULL; pSec = pSec->pNext) {
+        ALOGD("[%s]\n", pSec->Name);
+        for (INI_LINE* pLine = pSec->pLine; pLine != NULL; pLine = pLine->pNext) {
+            ALOGD("%s = %s\n", pLine->Name, pLine->Value);
+        }
+        ALOGD("\n\n\n");
+    }
+}
+
+INI_SECTION* IniParser::getSection(void* user, const char* section) {
+    IniParser* parser = (IniParser*) user;
+    if (parser == NULL) {
+        return NULL;
+    }
+
+    for (INI_SECTION* pSec = parser->mpFirstSection; pSec != NULL; pSec = pSec->pNext) {
+        if (strncmp(pSec->Name, section, strlen(section)) == 0) {
+            return pSec;
+        }
+    }
+
+    return NULL;
+}
+
+INI_LINE* IniParser::getKeyLineAtSec(INI_SECTION* pSec, const char* key) {
+    for (INI_LINE* pLine = pSec->pLine; pLine != NULL; pLine = pLine->pNext) {
+        if (strncmp(pLine->Name, key, strlen(key)) == 0) {
+            return pLine;
+        }
+    }
+    return NULL;
+}
+
+const char* IniParser::GetString(const char* section, const char* key,
+        const char* def_value) {
+    INI_SECTION* pSec = getSection(this, section);
+    if (pSec == NULL) {
+        //ALOGD("%s, section %s is NULL\n", __FUNCTION__, section);
+        return def_value;
+    }
+
+    INI_LINE* pLine = getKeyLineAtSec(pSec, key);
+    if (pLine == NULL) {
+        //ALOGD("%s, key \"%s\" is NULL\n", __FUNCTION__, key);
+        return def_value;
+    }
+
+    return pLine->Value;
+}
+
+int IniParser::SaveToFile(const char *filename) {
+    const char *fname = NULL;
+    FILE *fp = NULL;
+
+    if (filename == NULL) {
+        if (strlen(mpFileName) == 0) {
+            ALOGE("%s, save file name is NULL!!!\n", __FUNCTION__);
+            return -1;
+        } else {
+            fname = mpFileName;
+        }
+    } else {
+        fname = filename;
+    }
+
+    if ((fp = fopen (fname, "wb")) == NULL) {
+        ALOGE("%s, Open file \"%s\" ERROR (%s)!!!\n", __FUNCTION__, fname, strerror(errno));
+        return -1;
+    }
+
+    for (INI_SECTION* pSec = mpFirstSection; pSec != NULL; pSec = pSec->pNext) {
+        fprintf(fp, "[%s]\r\n", pSec->Name);
+        for (INI_LINE* pLine = pSec->pLine; pLine != NULL; pLine = pLine->pNext) {
+            fprintf(fp, "%s = %s\r\n", pLine->Name, pLine->Value);
+        }
+    }
+
+    fflush(fp);
+    fsync(fileno(fp));
+
+    fclose(fp);
+    fp = NULL;
+
+    return 0;
+}
+
+int IniParser::SetString(const char *section, const char *key, const char *value) {
+    setKeyValue(this, section, key, value, 1);
+    SaveToFile(NULL);
+    return 0;
+}
+
+INI_LINE* IniParser::newLine(const char* name, const char* value) {
+    INI_LINE* pLine = NULL;
+
+    pLine = new INI_LINE();
+    if (pLine != NULL) {
+        pLine->pNext = NULL;
+        strcpy(pLine->Name, name);
+        strcpy(pLine->Value, value);
+
+#if CC_MEMORY_NEW_DEL_TRACE == 1
+        new_mem(__FUNCTION__, "pLine", pLine);
+#endif
+    }
+
+    return pLine;
+}
+
+INI_SECTION* IniParser::newSection(const char* section, INI_LINE* pLine) {
+    INI_SECTION* pSec = NULL;
+
+    pSec = new INI_SECTION();
+    if (pSec != NULL) {
+        pSec->pLine = pLine;
+        pSec->pNext = NULL;
+        strcpy(pSec->Name, section);
+
+#if CC_MEMORY_NEW_DEL_TRACE == 1
+        new_mem(__FUNCTION__, "pSec", pSec);
+#endif
+    }
+
+    return pSec;
+}
+
+int IniParser::setKeyValue(void* user, const char* section, const char* key, const char* value, int set_mode) {
+    IniParser* parser = NULL;
+    INI_LINE* pLine = NULL;
+    INI_SECTION *pSec = NULL;
+
+    if (user == NULL || section == NULL || key == NULL || value == NULL) {
+        return 1;
+    }
+
+    parser = (IniParser*) user;
+
+    parser->trim((char *) value);
+    if (value[0] == '\0') {
+        return 1;
+    }
+
+    if (parser->mpFirstSection == NULL) {
+        pLine = newLine(key, value);
+        pSec = newSection(section, pLine);
+
+        parser->mpFirstSection = pSec;
+        parser->mpCurSection = pSec;
+        pSec->pCurLine = pLine;
+    } else {
+        pSec = getSection(user, section);
+        if (pSec == NULL) {
+            pLine = newLine(key, value);
+            pSec = newSection(section, pLine);
+
+            parser->mpCurSection->pNext = pSec;
+            parser->mpCurSection = pSec;
+            pSec->pCurLine = pLine;
+
+            pSec->pCurLine = pLine;
+        } else {
+            pLine = getKeyLineAtSec(pSec, key);
+            if (pLine == NULL) {
+                pLine = newLine(key, value);
+
+                pSec->pCurLine->pNext = pLine;
+                pSec->pCurLine = pLine;
+            } else {
+                if (set_mode == 1) {
+                    strcpy(pLine->Value, value);
+                } else {
+                    strcat(pLine->Value, value);
+                }
+            }
+        }
+    }
+
+    return 0;
+}
+
+int IniParser::handler(void* user, const char* section, const char* name,
+        const char* value) {
+    //ALOGD("%s, section = %s, name = %s, value = %s\n", __FUNCTION__, section, name, value);
+    setKeyValue(user, section, name, value, 0);
+    return 1;
+}
+
+#if CC_MEMORY_NEW_DEL_TRACE == 1
+
+#define CC_MEM_RECORD_CNT    (1024)
+
+typedef struct tag_memnd {
+    char fun_name[50];
+    char var_name[50];
+    void *ptr;
+} memnd;
+
+static memnd gMemNewItems[CC_MEM_RECORD_CNT];
+static int gMemNewInd = 0;
+
+static memnd gMemDelItems[CC_MEM_RECORD_CNT];
+static int gMemDelInd = 0;
+
+static void new_mem(const char *fun_name, const char *var_name, void *ptr) {
+    strcpy(gMemNewItems[gMemNewInd].fun_name, fun_name);
+    strcpy(gMemNewItems[gMemNewInd].var_name, var_name);
+    gMemNewItems[gMemNewInd].ptr = ptr;
+
+    gMemNewInd += 1;
+}
+
+static void del_mem(const char *fun_name, const char *var_name, void *ptr) {
+    strcpy(gMemDelItems[gMemDelInd].fun_name, fun_name);
+    strcpy(gMemDelItems[gMemDelInd].var_name, var_name);
+    gMemDelItems[gMemDelInd].ptr = ptr;
+
+    gMemDelInd += 1;
+}
+
+static void printMemND(const char *fun_name, memnd *tmp_nd, int tmp_cnt) {
+    //int i = 0;
+
+    ALOGD("fun_name = %s, fun_name = %s, total_cnt = %d\n", fun_name, (char *)tmp_nd, tmp_cnt);
+
+#if CC_MEMORY_NEW_DEL_TRACE_PRINT_ALL == 1
+    for (i = 0; i < tmp_cnt; i++) {
+        ALOGD("fun_name = %s, var_name = %s, ptr = %p\n", tmp_nd[i].fun_name, tmp_nd[i].var_name, tmp_nd[i].ptr);
+    }
+#endif
+}
+
+static void printDelMemND(const char *fun_name) {
+    ALOGD("fun_name = %s\n", fun_name);
+    printMemND(__FUNCTION__, gMemDelItems, gMemDelInd);
+}
+
+static void printNewMemND(const char *fun_name) {
+    ALOGD("fun_name = %s\n", fun_name);
+    printMemND(__FUNCTION__, gMemNewItems, gMemNewInd);
+}
+
+static void clearMemND() {
+    //int i = 0;
+
+    gMemNewInd = 0;
+    gMemDelInd = 0;
+    memset((void *)gMemNewItems, 0, sizeof(memnd) * CC_MEM_RECORD_CNT);
+    memset((void *)gMemDelItems, 0, sizeof(memnd) * CC_MEM_RECORD_CNT);
+}
+#endif
diff --git a/utils/ini/include/IniParser.h b/utils/ini/include/IniParser.h
new file mode 100755
index 0000000..f54bdce
--- /dev/null
+++ b/utils/ini/include/IniParser.h
@@ -0,0 +1,87 @@
+/*
+ * Copyright (C) 2017 Amlogic Corporation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/*
+ * Author:  Shoufu Zhao <shoufu.zhao@amlogic.com>
+ */
+
+#ifndef __INI_PARSER_H__
+#define __INI_PARSER_H__
+
+#define CC_MAX_INI_FILE_NAME_LEN    (512)
+#define CC_MAX_INI_FILE_LINE_LEN    (2048)
+
+#define CC_MAX_INI_LINE_NAME_LEN    (128)
+
+typedef struct S_INI_LINE {
+    struct S_INI_LINE *pNext;
+    char Name[CC_MAX_INI_LINE_NAME_LEN];
+    char Value[CC_MAX_INI_FILE_LINE_LEN];
+} INI_LINE;
+
+typedef struct S_INI_SECTION {
+    INI_LINE* pLine;
+    INI_LINE* pCurLine;
+    struct S_INI_SECTION *pNext;
+    char Name[CC_MAX_INI_LINE_NAME_LEN];
+} INI_SECTION;
+
+class IniParser
+{
+public:
+    IniParser();
+    ~IniParser();
+
+    void free();
+    int parse(const char* fname);
+    int SetSaveFileName(const char* fname);
+    int parse_mem(char* file_buf);
+    static INI_SECTION* getSection(void* user, const char* section);
+    const char* GetString(const char* section, const char* key, const char* def_value);
+    int SetString(const char *section, const char *key, const char *value);
+    void print();
+
+private:
+    int SaveToFile(const char *filename);
+
+    static void trim(char *str, char ch);
+    static void trim(char *str);
+    static INI_LINE* getKeyLineAtSec(INI_SECTION* pSec, const char* key);
+    static int setKeyValue(void* user, const char* section, const char* name, const char* value, int set_mode);
+    static int handler(void* user, const char* section, const char* name, const char* value);
+    static INI_LINE* newLine(const char* name, const char* value);
+    static INI_SECTION* newSection(const char* section, INI_LINE* pLINE);
+
+private:
+    INI_SECTION* mpFirstSection;
+    INI_SECTION* mpCurSection;
+
+    char mpFileName[CC_MAX_INI_FILE_NAME_LEN];
+};
+
+//for memory new and delete debug
+#define CC_MEMORY_NEW_DEL_TRACE              (1)
+#define CC_MEMORY_NEW_DEL_TRACE_PRINT_ALL    (0)
+
+#if CC_MEMORY_NEW_DEL_TRACE == 1
+static void new_mem(const char *fun_name, const char *var_name, void *ptr);
+static void del_mem(const char *fun_name, const char *var_name, void *ptr);
+static void printDelMemND(const char *fun_name);
+static void printNewMemND(const char *fun_name);
+static void clearMemND();
+#endif
+
+#endif //__INI_PARSER_H__
diff --git a/utils/ini/include/ini.h b/utils/ini/include/ini.h
new file mode 100755
index 0000000..b82dc02
--- /dev/null
+++ b/utils/ini/include/ini.h
@@ -0,0 +1,90 @@
+/*
+ * Copyright (C) 2017 Amlogic Corporation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/* inih -- simple .INI file parser
+
+ inih is released under the New BSD license (see LICENSE.txt). Go to the project
+ home page for more info:
+
+ http://code.google.com/p/inih/
+
+ */
+
+#ifndef __INI_H__
+#define __INI_H__
+
+/* Make this header file easier to include in C++ code */
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <stdio.h>
+
+/* Parse given INI-style file. May have [section]s, name=value pairs
+ (whitespace stripped), and comments starting with ';' (semicolon). Section
+ is "" if name=value pair parsed before any section heading. name:value
+ pairs are also supported as a concession to Python's ConfigParser.
+
+ For each name=value pair parsed, call handler function with given user
+ pointer as well as section, name, and value (data only valid for duration
+ of handler call). Handler should return nonzero on success, zero on error.
+
+ Returns 0 on success, line number of first error on parse error (doesn't
+ stop on first error), -1 on file open error, or -2 on memory allocation
+ error (only when INI_USE_STACK is zero).
+ */
+int ini_parse(const char* filename,
+        int (*handler)(void* user, const char* section, const char* name,
+                const char* value), void* user);
+
+/* Same as ini_parse(), but takes a FILE* instead of filename. This doesn't
+ close the file when it's finished -- the caller must do that. */
+int ini_parse_file(FILE* file,
+        int (*handler)(void* user, const char* section, const char* name,
+                const char* value), void* user);
+
+int ini_parse_mem(const char* buf,
+        int (*handler)(void* user, const char* section, const char* name,
+                const char* value), void* user);
+
+/* Nonzero to allow multi-line value parsing, in the style of Python's
+ ConfigParser. If allowed, ini_parse() will call the handler with the same
+ name for each subsequent line parsed. */
+#ifndef INI_ALLOW_MULTILINE
+#define INI_ALLOW_MULTILINE 1
+#endif
+
+/* Nonzero to allow a UTF-8 BOM sequence (0xEF 0xBB 0xBF) at the start of
+ the file. See http://code.google.com/p/inih/issues/detail?id=21 */
+#ifndef INI_ALLOW_BOM
+#define INI_ALLOW_BOM 1
+#endif
+
+/* Nonzero to use stack, zero to use heap (malloc/free). */
+#ifndef INI_USE_STACK
+#define INI_USE_STACK 1
+#endif
+
+/* Maximum line length for any line in INI file. */
+#ifndef INI_MAX_LINE
+#define INI_MAX_LINE 20000
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __INI_H__ */
diff --git a/utils/ini/include/ini_config.h b/utils/ini/include/ini_config.h
new file mode 100755
index 0000000..aa31f0e
--- /dev/null
+++ b/utils/ini/include/ini_config.h
@@ -0,0 +1,38 @@
+
+/*
+ * Copyright (C) 2017 Amlogic Corporation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __INI_CONFIG_H__
+#define __INI_CONFIG_H__
+
+#if MODE_COMPILE_IN_PC
+    #define CS_DEFAULT_PANEL_INI_FILE_NAME             "input/panel/ID_0_Pnl_FACTORY.ini"
+    #define CS_DEFAULT_PANEL_PQ_DB_FILE_NAME           "input/pq/pq_default.bin"
+    #define CS_DEFAULT_AUDIO_PARAM_INI_FILE_NAME       "input/audio/eq_drc/aml_internal_hw_eq.ini"
+#else
+    #define CS_DEFAULT_PANEL_INI_FILE_NAME             "/system/etc/ID_0_Pnl_FACTORY.ini"
+    #define CS_DEFAULT_PANEL_PQ_DB_FILE_NAME           "/system/etc/pq_default.bin"
+    #define CS_DEFAULT_AUDIO_PARAM_INI_FILE_NAME       "/system/etc/ID_0_Aud_eq_drc_FACTORY.ini"
+#endif
+
+#define CC_RW_KEY_USE_OTHER_MODULE    (0)
+
+#if MODE_COMPILE_IN_PC
+    #define CC_RW_KEY_USE_OTHER_MODULE    (0)
+    #define CC_UBOOT_RW_SIMULATE
+#endif
+
+#endif //__INI_CONFIG_H__
diff --git a/utils/ini/ini.cpp b/utils/ini/ini.cpp
new file mode 100755
index 0000000..20c3229
--- /dev/null
+++ b/utils/ini/ini.cpp
@@ -0,0 +1,290 @@
+/*
+ * Copyright (C) 2017 Amlogic Corporation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define _CRT_SECURE_NO_WARNINGS
+//#pragma warning (disable: 4127)
+
+#include <stdio.h>
+#include <ctype.h>
+#include <string.h>
+
+#include "ini.h"
+
+#if !INI_USE_STACK
+#include <stdlib.h>
+#endif
+
+#define MAX_SECTION 50
+#define MAX_NAME 50
+
+/* Strip whitespace chars off end of given string, in place. Return s. */
+static char* rstrip(char* s) {
+    char* p = s + strlen(s);
+    while (p > s && isspace((unsigned char) (*--p)))
+        *p = '\0';
+    return s;
+}
+
+/* Return pointer to first non-whitespace char in given string. */
+static char* lskip(const char* s) {
+    while (*s && isspace((unsigned char) (*s)))
+        s++;
+    return (char*) s;
+}
+
+/* Return pointer to first char c or ';' comment in given string, or pointer to
+ null at end of string if neither found. ';' must be prefixed by a whitespace
+ character to register as a comment. */
+static char* find_char_or_comment(const char* s, char c) {
+    int was_whitespace = 0;
+    while (*s && *s != c && !(was_whitespace && *s == ';')) {
+        was_whitespace = isspace((unsigned char) (*s));
+        s++;
+    }
+    return (char*) s;
+}
+
+/* Version of strncpy that ensures dest (size bytes) is null-terminated. */
+static char* strncpy0(char* dest, const char* src, size_t size) {
+    strncpy(dest, src, size);
+    dest[size - 1] = '\0';
+    return dest;
+}
+
+/* See documentation in header file. */
+int ini_parse_file(FILE* file,
+        int (*handler)(void*, const char*, const char*, const char*),
+        void* user) {
+    /* Uses a fair bit of stack (use heap instead if you need to) */
+#if INI_USE_STACK
+    char line[INI_MAX_LINE];
+#else
+    char* line;
+#endif
+    char section[MAX_SECTION] = "";
+    char prev_name[MAX_NAME] = "";
+
+    char* start;
+    char* end;
+    char* name;
+    char* value;
+    int lineno = 0;
+    int error = 0;
+
+#if !INI_USE_STACK
+    line = (char*) malloc(INI_MAX_LINE);
+    if (!line) {
+        return -2;
+    }
+#endif
+
+    /* Scan through file line by line */
+    while (fgets(line, INI_MAX_LINE, file) != NULL) {
+        lineno++;
+
+        start = line;
+#if INI_ALLOW_BOM
+        if (lineno == 1 && (unsigned char)start[0] == 0xEF &&
+                (unsigned char)start[1] == 0xBB &&
+                (unsigned char)start[2] == 0xBF) {
+            start += 3;
+        }
+#endif
+        start = lskip(rstrip(start));
+
+        if (*start == ';' || *start == '#') {
+            /* Per Python ConfigParser, allow '#' comments at start of line */
+        }
+        else if (*start == '[') {
+            /* A "[section]" line */
+            end = find_char_or_comment(start + 1, ']');
+            if (*end == ']') {
+                *end = '\0';
+                strncpy0(section, start + 1, sizeof(section));
+                *prev_name = '\0';
+            } else if (!error) {
+                /* No ']' found on section line */
+                error = lineno;
+            }
+        }
+#if INI_ALLOW_MULTILINE
+        else if (*prev_name && *start && (start > line || strstr(start, "=") == NULL)) {
+            /* Non-black line with leading whitespace, treat as continuation
+             of previous name's value (as per Python ConfigParser). */
+            if (!handler(user, section, prev_name, start) && !error)
+            error = lineno;
+        }
+#endif
+        else if (*start && *start != ';') {
+            /* Not a comment, must be a name[=:]value pair */
+            end = find_char_or_comment(start, '=');
+            if (*end != '=') {
+                end = find_char_or_comment(start, ':');
+            }
+            if (*end == '=' || *end == ':') {
+                *end = '\0';
+                name = rstrip(start);
+                value = lskip(end + 1);
+                end = find_char_or_comment(value, '\0');
+                if (*end == ';')
+                    *end = '\0';
+                rstrip(value);
+
+                /* Valid name[=:]value pair found, call handler */
+                strncpy0(prev_name, name, sizeof(prev_name));
+                if (!handler(user, section, name, value) && !error)
+                    error = lineno;
+            } else if (!error) {
+                /* No '=' or ':' found on name[=:]value line */
+                error = lineno;
+            }
+        }
+    }
+
+#if !INI_USE_STACK
+    free(line);
+#endif
+
+    return error;
+}
+
+int ini_parse_mem(const char* buf,
+        int (*handler)(void* user, const char* section, const char* name,
+                const char* value), void* user) {
+    char* bufptr = (char*) buf;
+
+    /* Uses a fair bit of stack (use heap instead if you need to) */
+#if INI_USE_STACK
+    char line[INI_MAX_LINE];
+#else
+    char* line;
+#endif
+    char section[MAX_SECTION] = "";
+    char prev_name[MAX_NAME] = "";
+
+    char* start;
+    char* end;
+    char* name;
+    char* value;
+    int lineno = 0;
+    int error = 0;
+
+#if !INI_USE_STACK
+    line = (char*) malloc(INI_MAX_LINE);
+    if (!line) {
+        return -2;
+    }
+#endif
+
+    while (1) {
+        int ncount = 0;
+        while (*bufptr != '\0') {
+            if (*bufptr == '\r' || *bufptr == '\n')
+                break;
+
+            line[ncount] = *bufptr++;
+            ncount++;
+        }
+        while (*bufptr == '\r' || *bufptr == '\n')
+            bufptr++;
+        line[ncount] = 0;
+
+        if (ncount == 0)
+            break;
+
+        /* Scan through file line by line */
+        //while (fgets(line, INI_MAX_LINE, file) != NULL) {
+        lineno++;
+
+        start = line;
+#if INI_ALLOW_BOM
+        if (lineno == 1 && (unsigned char)start[0] == 0xEF &&
+                (unsigned char)start[1] == 0xBB &&
+                (unsigned char)start[2] == 0xBF) {
+            start += 3;
+        }
+#endif
+        start = lskip(rstrip(start));
+
+        if (*start == ';' || *start == '#') {
+            /* Per Python ConfigParser, allow '#' comments at start of line */
+        }
+#if INI_ALLOW_MULTILINE
+        else if (*prev_name && *start && start > line) {
+            /* Non-black line with leading whitespace, treat as continuation
+             of previous name's value (as per Python ConfigParser). */
+            if (!handler(user, section, prev_name, start) && !error)
+            error = lineno;
+        }
+#endif
+        else if (*start == '[') {
+            /* A "[section]" line */
+            end = find_char_or_comment(start + 1, ']');
+            if (*end == ']') {
+                *end = '\0';
+                strncpy0(section, start + 1, sizeof(section));
+                *prev_name = '\0';
+            } else if (!error) {
+                /* No ']' found on section line */
+                error = lineno;
+            }
+        } else if (*start && *start != ';') {
+            /* Not a comment, must be a name[=:]value pair */
+            end = find_char_or_comment(start, '=');
+            if (*end != '=') {
+                end = find_char_or_comment(start, ':');
+            }
+            if (*end == '=' || *end == ':') {
+                *end = '\0';
+                name = rstrip(start);
+                value = lskip(end + 1);
+                end = find_char_or_comment(value, '\0');
+                if (*end == ';')
+                    *end = '\0';
+                rstrip(value);
+
+                /* Valid name[=:]value pair found, call handler */
+                strncpy0(prev_name, name, sizeof(prev_name));
+                if (!handler(user, section, name, value) && !error)
+                    error = lineno;
+            } else if (!error) {
+                /* No '=' or ':' found on name[=:]value line */
+                error = lineno;
+            }
+        }
+    }
+
+#if !INI_USE_STACK
+    free(line);
+#endif
+
+    return error;
+}
+
+/* See documentation in header file. */
+int ini_parse(const char* filename,
+        int (*handler)(void*, const char*, const char*, const char*),
+        void* user) {
+    FILE* file;
+    int error;
+
+    file = fopen(filename, "r");
+    if (!file)
+        return -1;
+    error = ini_parse_file(file, handler, user);
+    fclose(file);
+    return error;
+}
diff --git a/utils/spdifenc_wrap.cpp b/utils/spdifenc_wrap.cpp
new file mode 100755
index 0000000..0af8ce6
--- /dev/null
+++ b/utils/spdifenc_wrap.cpp
@@ -0,0 +1,112 @@
+/*
+ * Copyright (C) 2010 Amlogic Corporation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "AudioSPDIF-wrap"
+#include <stdint.h>
+#include <utils/Log.h>
+#include <system/audio.h>
+#include <audio_utils/spdif/SPDIFEncoder.h>
+#include <tinyalsa/asoundlib.h>
+#include <cutils/properties.h>
+
+extern "C"
+{
+//#include "audio_hw_utils.h"
+}
+
+static int getprop_bool(const char * path)
+{
+    char buf[PROPERTY_VALUE_MAX];
+    int ret = -1;
+    ret = property_get(path, buf, NULL);
+    if (ret > 0) {
+        if (strcasecmp(buf,"true") == 0 || strcmp(buf,"1") == 0) {
+            return 1;
+        }
+    }
+    return 0;
+}
+
+namespace android
+{
+class MySPDIFEncoder : public SPDIFEncoder
+{
+public:
+    MySPDIFEncoder(struct pcm *mypcm, audio_format_t format)
+        : SPDIFEncoder(format),
+          pcm_handle(mypcm), mTotalBytes(0)//, eac3_frame(0), mformat(format)
+    {};
+    virtual ssize_t writeOutput(const void* buffer, size_t bytes)
+    {
+        int ret = -1;
+        ALOGV("write size %zu \n", bytes);
+#if 1
+        if (getprop_bool("media.audiohal.outdump")) {
+            FILE *fp1 = fopen("/data/audio_out/hdmi_audio_out.spdif", "a+");
+            if (fp1) {
+                fwrite((char *)buffer, 1, bytes, fp1);
+                //ALOGD("flen = %d---outlen=%d ", flen, out_frames * frame_size);
+                fclose(fp1);
+            } else {
+                //ALOGD("could not open file:/data/hdmi_audio_out.pcm");
+            }
+        }
+#endif
+        mTotalBytes += bytes;
+        ret = pcm_write(pcm_handle, buffer, bytes);
+        if (ret)
+            return ret;
+
+        return bytes;
+    }
+    virtual uint64_t total_bytes()
+    {
+        return mTotalBytes;
+    }
+protected:
+    struct pcm *pcm_handle;
+private:
+    uint64_t mTotalBytes;
+//    uint64_t eac3_frame;
+//    audio_format_t mformat;
+};
+static MySPDIFEncoder *myencoder = NULL;
+extern "C" int spdifenc_init(struct pcm *mypcm, audio_format_t format)
+{
+    if (myencoder) {
+        delete myencoder;
+        myencoder = NULL;
+    }
+    myencoder = new MySPDIFEncoder(mypcm, format);
+    if (myencoder == NULL) {
+        ALOGE("init SPDIFEncoder failed \n");
+        return  -1;
+    }
+    ALOGI("init SPDIFEncoder done\n");
+    return 0;
+}
+extern "C" int  spdifenc_write(const void *buffer, size_t numBytes)
+{
+    return myencoder->write(buffer, numBytes);
+}
+extern "C" uint64_t  spdifenc_get_total()
+{
+    return myencoder->total_bytes();
+}
+}
diff --git a/utils/test/Android.mk b/utils/test/Android.mk
new file mode 100755
index 0000000..f17d141
--- /dev/null
+++ b/utils/test/Android.mk
@@ -0,0 +1,40 @@
+# Copyright 2005 The Android Open Source Project
+
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_C_INCLUDES := \
+    hardware/$(PLATFORM_NAME)/audio/utils/include
+
+LOCAL_SRC_FILES:= \
+    test.c
+
+LOCAL_MODULE:= testamlconf
+
+#LOCAL_FORCE_STATIC_EXECUTABLE := true
+#LOCAL_MODULE_PATH := $(TARGET_ROOT_OUT)
+#LOCAL_UNSTRIPPED_PATH := $(TARGET_ROOT_OUT_UNSTRIPPED)
+
+LOCAL_SHARED_LIBRARIES := \
+        libcutils \
+        libc \
+        libamaudioutils
+
+include $(BUILD_EXECUTABLE)
+
+include $(CLEAR_VARS)
+
+LOCAL_C_INCLUDES := \
+    hardware/$(PLATFORM_NAME)/audio/utils/include
+
+LOCAL_CFLAGS := -DBUILDHOSTEXE
+
+LOCAL_SRC_FILES:= \
+    test_data_utils.c \
+    ../aml_data_utils.c
+
+LOCAL_MODULE:= testdatautils
+
+LOCAL_SHARED_LIBRARIES :=
+
+include $(BUILD_HOST_EXECUTABLE)
diff --git a/utils/test/test.c b/utils/test/test.c
new file mode 100755
index 0000000..370169e
--- /dev/null
+++ b/utils/test/test.c
@@ -0,0 +1,95 @@
+/*
+ * Copyright (C) 2017 Amlogic Corporation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <getopt.h>
+#include <errno.h>
+#include <aml_conf_loader.h>
+#include <aml_conf_parser.h>
+#include <aml_data_utils.h>
+
+static struct aml_audio_channel_name gChName[] = {
+	{AML_CH_IDX_L,   "left"},
+	{AML_CH_IDX_R,   "right"},
+	{AML_CH_IDX_C,   "center"},
+	{AML_CH_IDX_LFE, "lfe"},
+	{AML_CH_IDX_LS,  "left_surround"},
+	{AML_CH_IDX_RS,  "right_urround"},
+	{AML_CH_IDX_LT,  "left_top"},
+	{AML_CH_IDX_RT,  "right_top"},
+};
+
+static char *_get_ch_name(eChannelContentIdx idx)
+{
+	int i = 0;
+	int cnt = 0;
+
+	cnt = sizeof(gChName)/sizeof(struct aml_audio_channel_name);
+
+	for (i=AML_CH_IDX_L; i<AML_I2S_CHANNEL_COUNT; i++) {
+		if (idx == gChName[i].ch_idx) {
+			return gChName[i].ch_name;
+		}
+	}
+
+	switch (idx) {
+	case AML_CH_IDX_5_1_ALL:
+		return "5.1Ch";
+	case AML_CH_IDX_7_1_ALL:
+		return "7.1Ch";
+	case AML_CH_IDX_5_1_2_ALL:
+		return "5.1.2Ch";
+	default:
+		break;
+	}
+
+	return "Invalid";
+}
+
+int main(void)
+{
+	struct aml_channel_map *maps = NULL;
+	int i;
+
+	// test read product channel config
+	maps = data_load_product_config();
+	if (maps) {
+		printf("idx mask i2s-idx invert ditter\n");
+		printf("------------------------------\n");
+		for (i=0; i<AML_CH_IDX_MAX; i++) {
+			printf("%d   0x%02x       %d      %d      %d (%s)\n",
+				maps[i].channel_idx,
+				maps[i].bit_mask,
+				maps[i].i2s_idx,
+				maps[i].invert,
+				maps[i].ditter,
+				_get_ch_name(i));
+		}
+		printf("------------------------------\n");
+	}
+
+	// test android utils
+	// test alsa mixer utils
+	// test hw profile utils
+
+	return 0;
+}
diff --git a/utils/test/test_data_utils.c b/utils/test/test_data_utils.c
new file mode 100755
index 0000000..3969ad6
--- /dev/null
+++ b/utils/test/test_data_utils.c
@@ -0,0 +1,662 @@
+/*
+ * Copyright (C) 2017 Amlogic Corporation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <getopt.h>
+#include <errno.h>
+#include <aml_data_utils.h>
+
+/******************************************************************************
+ * All parttens of channel maps@xiaomi
+ *****************************************************************************/
+struct aml_channel_map atmos_maps[8] = {
+	{AML_CH_IDX_L,   AML_I2S_PORT_IDX_01, AML_I2S_CHANNEL_0,                                    0,    AML_I2S_CHANNEL_0},
+	{AML_CH_IDX_R,   AML_I2S_PORT_IDX_01, AML_I2S_CHANNEL_1,                                    0,    AML_I2S_CHANNEL_1},
+	{AML_CH_IDX_C,   AML_I2S_PORT_IDX_23, AML_I2S_CHANNEL_2,                                    0,    AML_I2S_CHANNEL_2},
+	{AML_CH_IDX_LFE, AML_I2S_PORT_IDX_23, AML_I2S_CHANNEL_3,                                    0,    AML_I2S_CHANNEL_3},
+	{AML_CH_IDX_LS,  AML_I2S_PORT_IDX_67, AML_I2S_CHANNEL_6,                                    0,    AML_I2S_CHANNEL_6},
+	{AML_CH_IDX_RS,  AML_I2S_PORT_IDX_67, AML_I2S_CHANNEL_7,                                    0,    AML_I2S_CHANNEL_7},
+	{AML_CH_IDX_LT,  AML_I2S_PORT_IDX_45, AML_I2S_CHANNEL_4,                                    0,    AML_I2S_CHANNEL_4},
+	{AML_CH_IDX_RT,  AML_I2S_PORT_IDX_45, AML_I2S_CHANNEL_5,                                    0,    AML_I2S_CHANNEL_5},
+};
+
+struct aml_channel_map mi_maps[8] = {
+	{AML_CH_IDX_L,   AML_I2S_PORT_IDX_01,   AML_I2S_CHANNEL_0,                                   0,                   0},
+	{AML_CH_IDX_R,   AML_I2S_PORT_IDX_01,   AML_I2S_CHANNEL_1,                                   0,                   0},
+	{AML_CH_IDX_C,   AML_I2S_PORT_IDX_NULL, AML_I2S_CHANNEL_NULL,                                0,                   0},
+	{AML_CH_IDX_LFE, AML_I2S_PORT_IDX_23,   AML_I2S_CHANNEL_2|AML_I2S_CHANNEL_3,                 0,                   0},
+	{AML_CH_IDX_LS,  AML_I2S_PORT_IDX_45,   AML_I2S_CHANNEL_4,                                   0,                   0},
+	{AML_CH_IDX_RS,  AML_I2S_PORT_IDX_45,   AML_I2S_CHANNEL_5,                                   0,                   0},
+	{AML_CH_IDX_LT,  AML_I2S_PORT_IDX_NULL, AML_I2S_CHANNEL_NULL,                                0,                   0},
+	{AML_CH_IDX_RT,  AML_I2S_PORT_IDX_NULL, AML_I2S_CHANNEL_NULL,                                0,                   0},
+};
+
+struct aml_channel_map rainman_maps[8] = {
+	{AML_CH_IDX_L,   AML_I2S_PORT_IDX_01,   AML_I2S_CHANNEL_0,                                   0,                   0},
+	{AML_CH_IDX_R,   AML_I2S_PORT_IDX_01,   AML_I2S_CHANNEL_1,                                   0,                   0},
+	{AML_CH_IDX_C,   AML_I2S_PORT_IDX_NULL, AML_I2S_CHANNEL_NULL,                                0,                   0},
+	{AML_CH_IDX_LFE, AML_I2S_PORT_IDX_23,   AML_I2S_CHANNEL_2|AML_I2S_CHANNEL_3, AML_I2S_CHANNEL_2,                   0},
+	{AML_CH_IDX_LS,  AML_I2S_PORT_IDX_NULL, AML_I2S_CHANNEL_NULL,                                0,                   0},
+	{AML_CH_IDX_RS,  AML_I2S_PORT_IDX_NULL, AML_I2S_CHANNEL_NULL,                                0,                   0},
+	{AML_CH_IDX_LT,  AML_I2S_PORT_IDX_NULL, AML_I2S_CHANNEL_NULL,                                0,                   0},
+	{AML_CH_IDX_RT,  AML_I2S_PORT_IDX_NULL, AML_I2S_CHANNEL_NULL,                                0,                   0},
+};
+
+struct aml_channel_map pulpfiction_maps[8] = {
+	{AML_CH_IDX_L,   AML_I2S_PORT_IDX_01,   AML_I2S_CHANNEL_0,                                   0,                   0},
+	{AML_CH_IDX_R,   AML_I2S_PORT_IDX_01,   AML_I2S_CHANNEL_1,                                   0,                   0},
+	{AML_CH_IDX_C,   AML_I2S_PORT_IDX_NULL, AML_I2S_CHANNEL_NULL,                                0,                   0},
+	{AML_CH_IDX_LFE, AML_I2S_PORT_IDX_23,   AML_I2S_CHANNEL_2|AML_I2S_CHANNEL_3,                 0,                   0},
+	{AML_CH_IDX_LS,  AML_I2S_PORT_IDX_NULL, AML_I2S_CHANNEL_NULL,                                0,                   0},
+	{AML_CH_IDX_RS,  AML_I2S_PORT_IDX_NULL, AML_I2S_CHANNEL_NULL,                                0,                   0},
+	{AML_CH_IDX_LT,  AML_I2S_PORT_IDX_NULL, AML_I2S_CHANNEL_NULL,                                0,                   0},
+	{AML_CH_IDX_RT,  AML_I2S_PORT_IDX_NULL, AML_I2S_CHANNEL_NULL,                                0,                   0},
+};
+struct aml_channel_map matrix_maps[8] = {
+	{AML_CH_IDX_L,   AML_I2S_PORT_IDX_23,   AML_I2S_CHANNEL_2,                                   0,                   0},
+	{AML_CH_IDX_R,   AML_I2S_PORT_IDX_23,   AML_I2S_CHANNEL_3,                                   0,                   0},
+	{AML_CH_IDX_C,   AML_I2S_PORT_IDX_NULL, AML_I2S_CHANNEL_NULL,                                0,                   0},
+	{AML_CH_IDX_LFE, AML_I2S_PORT_IDX_NULL, AML_I2S_CHANNEL_NULL,                                0,                   0},
+	{AML_CH_IDX_LS,  AML_I2S_PORT_IDX_NULL, AML_I2S_CHANNEL_NULL,                                0,                   0},
+	{AML_CH_IDX_RS,  AML_I2S_PORT_IDX_NULL, AML_I2S_CHANNEL_NULL,                                0,                   0},
+	{AML_CH_IDX_LT,  AML_I2S_PORT_IDX_NULL, AML_I2S_CHANNEL_NULL,                                0,                   0},
+	{AML_CH_IDX_RT,  AML_I2S_PORT_IDX_NULL, AML_I2S_CHANNEL_NULL,                                0,                   0},
+};
+
+static struct aml_audio_channel_name gChName[] = {
+	{AML_CH_IDX_L,   "left"},
+	{AML_CH_IDX_R,   "right"},
+	{AML_CH_IDX_C,   "center"},
+	{AML_CH_IDX_LFE, "lfe"},
+	{AML_CH_IDX_LS,  "left_surround"},
+	{AML_CH_IDX_RS,  "right_urround"},
+	{AML_CH_IDX_LT,  "left_top"},
+	{AML_CH_IDX_RT,  "right_top"},
+};
+
+static char *_get_ch_name(eChannelContentIdx idx)
+{
+	int i = 0;
+	int cnt = 0;
+
+	cnt = sizeof(gChName)/sizeof(struct aml_audio_channel_name);
+
+	for (i=AML_CH_IDX_L; i<AML_I2S_CHANNEL_COUNT; i++) {
+		if (idx == gChName[i].ch_idx) {
+			return gChName[i].ch_name;
+		}
+	}
+
+	switch (idx) {
+	case AML_CH_IDX_5_1_ALL:
+		return "5.1Ch";
+	case AML_CH_IDX_7_1_ALL:
+		return "7.1Ch";
+	case AML_CH_IDX_5_1_2_ALL:
+		return "5.1.2Ch";
+	default:
+		break;
+	}
+
+	return "Invalid";
+}
+
+static int dump_channel_map(const char *prj, struct aml_channel_map *maps)
+{
+	int i;
+
+	if (maps) {
+		printf("\n\n=============================================================\n");
+		printf("idx i2s-idx mask invert ditter [PRJ: %s]\n", prj);
+		printf("------------------------------\n");
+		for (i=0; i<AML_CH_IDX_MAX; i++) {
+			if (AML_I2S_PORT_IDX_NULL == maps[i].i2s_idx
+				|| AML_I2S_CHANNEL_NULL == maps[i].bit_mask) {
+				printf("%d      -    ----   ----   ---- (%s)\n",
+					maps[i].channel_idx,
+					_get_ch_name(i));
+			} else {
+				printf("%d      %d    0x%02x   0x%02x   0x%02x (%s)\n",
+					maps[i].channel_idx,
+					maps[i].i2s_idx,
+					maps[i].bit_mask,
+					maps[i].invert,
+					maps[i].ditter,
+					_get_ch_name(i));
+			}
+		}
+		printf("------------------------------\n\n");
+	}
+
+	return 0;
+}
+
+static int testpartten_chmap(const char *prj, struct aml_channel_map *maps)
+{
+	int num, i;
+	int port;
+	int bit_ch;
+	int bit;
+	int idx;
+
+	dump_channel_map(prj, maps);
+	for (num=AML_CH_IDX_L; num<AML_CH_IDX_MAX; num++) {
+		port = data_get_channel_i2s_port(maps, num);
+		if (port != AML_I2S_PORT_IDX_NULL) {
+			printf("----------------------------------------------\n");
+			bit_ch = data_get_channel_bit_mask(maps, num);
+			printf("[chan_idx][%d] %s <-> i2s:%02d <-> mask:0x%02x\n", num,
+				_get_ch_name(num),
+				port,
+				bit_ch);
+			for (i=0; i<8; i++) {
+				bit = bit_ch&(0x1<<i);
+				if (bit) {
+					idx = data_get_channel_content_idx(maps, bit);
+					printf("\n\t[bit_mask] 0x%02x <-> %s\n", bit, _get_ch_name(idx));
+				}
+			}
+		}
+	}
+
+	return 0;
+}
+
+/******************************************************************************
+ *  DATA TEST PARTTENS
+ *****************************************************************************/
+int16_t data16[8*8] = {
+	0x1101, 0x1102, 0x1103, 0x1104, 0x1105, 0x1106, 0x1107, 0x1108,
+	0x1111, 0x1112, 0x1113, 0x1114, 0x1115, 0x1116, 0x1117, 0x1118,
+	0x1121, 0x1122, 0x1123, 0x1124, 0x1125, 0x1126, 0x1127, 0x1128,
+	0x1131, 0x1132, 0x1133, 0x1134, 0x1135, 0x1136, 0x1137, 0x1138,
+	0x1141, 0x1142, 0x1143, 0x1144, 0x1145, 0x1146, 0x1147, 0x1148,
+	0x1151, 0x1152, 0x1153, 0x1154, 0x1155, 0x1156, 0x1157, 0x1158,
+	0x1161, 0x1162, 0x1163, 0x1164, 0x1165, 0x1166, 0x1167, 0x1168,
+	0x1171, 0x1172, 0x1173, 0x1174, 0x1175, 0x1176, 0x1177, 0x1178,
+};
+
+int32_t data32[8*8] = {
+	0x11111101, 0x11111102, 0x11111103, 0x11111104, 0x11111105, 0x11111106, 0x11111107, 0x11111108,
+	0x11111111, 0x11111112, 0x11111113, 0x11111114, 0x11111115, 0x11111116, 0x11111117, 0x11111118,
+	0x11111121, 0x11111122, 0x11111123, 0x11111124, 0x11111125, 0x11111126, 0x11111127, 0x11111128,
+	0x11111131, 0x11111132, 0x11111133, 0x11111134, 0x11111135, 0x11111136, 0x11111137, 0x11111138,
+	0x11111141, 0x11111142, 0x11111143, 0x11111144, 0x11111145, 0x11111146, 0x11111147, 0x11111148,
+	0x11111151, 0x11111152, 0x11111153, 0x11111154, 0x11111155, 0x11111156, 0x11111157, 0x11111158,
+	0x11111161, 0x11111162, 0x11111163, 0x11111164, 0x11111165, 0x11111166, 0x11111167, 0x11111168,
+	0x11111171, 0x11111172, 0x11111173, 0x11111174, 0x11111175, 0x11111176, 0x11111177, 0x11111178,
+};
+
+int _dump_data(void *buf, int channels, int framesz, int frames)
+{
+	int16_t *buf16 = (int16_t *)buf;
+	int32_t *buf32 = (int32_t *)buf;
+	int i, j;
+
+	for (i=0; i<frames; i++) {
+		if (framesz == e16BitPerSample) {
+			for (j=0; j<channels; j++) {
+				printf(" 0x%08x", buf16[i*channels + j]);
+			}
+			printf("\n");
+		} else if (framesz == e32BitPerSample) {
+			for (j=0; j<channels; j++) {
+				printf(" 0x%08x", buf32[i*channels + j]);
+			}
+			printf("\n");
+		}
+	}
+
+	return 0;
+}
+/******************************************
+ *  SINGLE BUFFER
+ *****************************************/
+/**
+ **        empty
+ */
+static int testpartten_empty(struct  aml_channel_map *map)
+{
+	int bit_empty = 0;
+
+	printf("\n==16==\n");
+	_dump_data((void *)data16, 8, e16BitPerSample, 8);
+	bit_empty  = 0;
+	bit_empty  = data_get_channel_bit_mask(map, AML_CH_IDX_L);
+	bit_empty |= data_get_channel_bit_mask(map, AML_CH_IDX_LFE);
+	data_empty_channels(map, (void *)data16, 8, e16BitPerSample, 8, bit_empty);
+	printf("->after empty:\n");
+	_dump_data((void *)data16, 8, e16BitPerSample, 8);
+
+
+	printf("\n==32==\n");
+	_dump_data((void *)data32, 8, e32BitPerSample, 8);
+	bit_empty  = 0;
+	bit_empty  = data_get_channel_bit_mask(map, AML_CH_IDX_C);
+	bit_empty |= data_get_channel_bit_mask(map, AML_CH_IDX_LFE);
+	data_empty_channels(map, (void *)data32, 8, e32BitPerSample, 8, bit_empty);
+	printf("->after empty:\n");
+	_dump_data((void *)data32, 8, e32BitPerSample, 8);
+
+	return 0;
+}
+/**
+ **        invert
+ */
+static int testpartten_invert(struct  aml_channel_map *map)
+{
+	int bit_mask = 0;
+
+	printf("\n==16==\n\n");
+	_dump_data((void *)data16, 8, e16BitPerSample, 8);
+	bit_mask  = 0;
+	bit_mask  = data_get_channel_bit_mask(map, AML_CH_IDX_L);
+	bit_mask |= data_get_channel_bit_mask(map, AML_CH_IDX_LFE);
+	data_invert_channels((void *)data16, 8, e16BitPerSample, 8, bit_mask);
+	printf("->after invert:\n");
+	_dump_data((void *)data16, 8, e16BitPerSample, 8);
+
+	printf("\n==32==\n\n");
+	_dump_data((void *)data32, 8, e32BitPerSample, 8);
+	bit_mask  = 0;
+	bit_mask  = data_get_channel_bit_mask(map, AML_CH_IDX_L);
+	bit_mask |= data_get_channel_bit_mask(map, AML_CH_IDX_LFE);
+	data_invert_channels((void *)data32, 8, e32BitPerSample, 8, bit_mask);
+	printf("->after invert:\n");
+	_dump_data((void *)data32, 8, e32BitPerSample, 8);
+
+	return 0;
+}
+/**
+ **        exchange
+ */
+static int testpartten_exchange(struct  aml_channel_map *map)
+{
+	if (map == NULL)
+		return -1;
+
+	printf("\n==16==\n\n");
+	_dump_data((void *)data16, 8, e16BitPerSample, 8);
+	data_exchange_i2s_channels((void *)data16, 8, e16BitPerSample, 8, AML_I2S_PORT_IDX_01, AML_I2S_PORT_IDX_23);
+	printf("\n->after exchange:\n");
+	_dump_data((void *)data16, 8, e16BitPerSample, 8);
+
+	printf("\n==32==\n\n");
+	_dump_data((void *)data32, 8, e32BitPerSample, 8);
+	data_exchange_i2s_channels((void *)data32, 8, e32BitPerSample, 8, AML_I2S_PORT_IDX_01, AML_I2S_PORT_IDX_67);
+	printf("->after exchange:\n");
+	_dump_data((void *)data32, 8, e32BitPerSample, 8);
+
+	return 0;
+}
+/**
+ **        re-mix
+ */
+int16_t remix16[6*8] = {
+	0x1101, 0x1102, 0x1103, 0x1104, 0x1105, 0x1106,
+	0x1111, 0x1112, 0x1113, 0x1114, 0x1115, 0x1116,
+	0x1121, 0x1122, 0x1123, 0x1124, 0x1125, 0x1126,
+	0x1131, 0x1132, 0x1133, 0x1134, 0x1135, 0x1136,
+	0x1141, 0x1142, 0x1143, 0x1144, 0x1145, 0x1146,
+	0x1151, 0x1152, 0x1153, 0x1154, 0x1155, 0x1156,
+	0x1161, 0x1162, 0x1163, 0x1164, 0x1165, 0x1166,
+	0x1171, 0x1172, 0x1173, 0x1174, 0x1175, 0x1176,
+};
+
+static int testpartten_remix(struct  aml_channel_map *map)
+{
+	int16_t rdata_16[6*8] = {0};
+	int i;
+
+	if (map == NULL)
+		return -1;
+
+	printf("\n==16==\n\n");
+	for (i=0; i<6*8; i++) {
+		rdata_16[i] = remix16[i];
+	}
+	_dump_data((void *)rdata_16, 6, e16BitPerSample, 8);
+	data_remix_to_lr_channel(map, (void *)rdata_16, 8, e16BitPerSample, 6, AML_CH_IDX_C);
+	printf("\n->after remix c to lr:\n");
+	_dump_data((void *)rdata_16, 6, e16BitPerSample, 8);
+
+	printf("\n==16==\n\n");
+	for (i=0; i<6*8; i++) {
+		rdata_16[i] = remix16[i];
+	}
+	_dump_data((void *)rdata_16, 6, e16BitPerSample, 8);
+	data_remix_to_lr_channel(map, (void *)rdata_16, 8, e16BitPerSample, 6, AML_CH_IDX_5_1_ALL);
+	printf("\n->after remix all to lr:\n");
+	_dump_data((void *)rdata_16, 6, e16BitPerSample, 8);
+
+	return 0;
+}
+/**
+ **        ditter
+ */
+static int testpartten_ditter(struct aml_channel_map *map)
+{
+	if (map == NULL)
+		return -1;
+
+	printf("\n==16==\n\n");
+	_dump_data((void *)data16, 8, e16BitPerSample, 8);
+	data_add_ditter_to_channels((void *)data16, 8, e16BitPerSample, 8, AML_CH_IDX_5_1_2_ALL);
+	printf("\n->after ditter:\n");
+	_dump_data((void *)data16, 8, e16BitPerSample, 8);
+
+	return 0;
+}
+
+/******************************************
+ *  MULTI  BUFFER
+ *****************************************/
+/**
+ **        concat
+ */
+#define T_FRAMES     (8)
+#define T_CHNUM_ALL  (8)
+#define T_CHNUM_SUB1 (2)
+#define T_CHNUM_SUB2 (2)
+#define T_CHNUM_SUB3 (2)
+#define T_CHNUM_SUB4 (2)
+int32_t d_all_32[T_FRAMES*T_CHNUM_ALL] = {
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+};
+
+int32_t sub1_32[T_FRAMES*T_CHNUM_SUB1] = {
+	0x11111101, 0x11111102,
+	0x11111121, 0x11111122,
+	0x11111131, 0x11111132,
+	0x11111141, 0x11111142,
+	0x11111151, 0x11111152,
+	0x11111161, 0x11111162,
+	0x11111171, 0x11111172,
+	0x11111111, 0x11111112,
+};
+int32_t sub2_32[T_FRAMES*T_CHNUM_SUB2] = {
+	0x11111103, 0x11111104,
+	0x11111123, 0x11111124,
+	0x11111133, 0x11111134,
+	0x11111143, 0x11111144,
+	0x11111153, 0x11111154,
+	0x11111163, 0x11111164,
+	0x11111173, 0x11111174,
+	0x11111113, 0x11111114,
+};
+int32_t sub3_32[T_FRAMES*T_CHNUM_SUB3] = {
+	0x11111105, 0x11111106,
+	0x11111125, 0x11111126,
+	0x11111135, 0x11111136,
+	0x11111145, 0x11111146,
+	0x11111155, 0x11111156,
+	0x11111165, 0x11111166,
+	0x11111175, 0x11111176,
+	0x11111115, 0x11111116,
+};
+int32_t sub4_32[T_FRAMES*T_CHNUM_SUB4] = {
+	0x11111107, 0x11111108,
+	0x11111127, 0x11111128,
+	0x11111137, 0x11111138,
+	0x11111147, 0x11111148,
+	0x11111157, 0x11111158,
+	0x11111167, 0x11111168,
+	0x11111177, 0x11111178,
+	0x11111117, 0x11111118,
+};
+
+static int testpartten_concat(struct aml_channel_map *map)
+{
+	if (map == NULL)
+		return -1;
+
+	printf("\n==16==\n\n");
+	_dump_data((void *)d_all_32, 8, e32BitPerSample, 8);
+	_dump_data((void *)sub1_32,  2, e32BitPerSample, 8);
+	_dump_data((void *)sub2_32,  2, e32BitPerSample, 8);
+	_dump_data((void *)sub3_32,  2, e32BitPerSample, 8);
+	_dump_data((void *)sub4_32,  2, e32BitPerSample, 8);
+	//data_add_ditter_to_channels((void *)data16, 8, e16BitPerSample, 8, AML_CH_IDX_5_1_2_ALL);
+	data_concat_channels(
+		d_all_32, T_CHNUM_ALL, e32BitPerSample,
+		sub1_32, sub2_32, sub3_32, sub4_32,
+		(T_CHNUM_SUB1+T_CHNUM_SUB2+T_CHNUM_SUB3+T_CHNUM_SUB4),
+		e32BitPerSample,
+		T_FRAMES
+		);
+	printf("\n->after cancat:\n");
+	_dump_data((void *)d_all_32, 8, e32BitPerSample, 8);
+
+	return 0;
+}
+
+/******************************************
+ *  TWO    BUFFER
+ *****************************************/
+/**
+ **        replace
+ */
+#define T_RP_FRAMES     (8)
+#define T_RP_CHNUM_ALL  (6)
+#define T_RP_LFE        (2)
+int16_t rep_d_16[T_RP_CHNUM_ALL*T_RP_FRAMES] = {
+	0x1101, 0x1102, 0x1103, 0x1104, 0x1105, 0x1106,
+	0x1111, 0x1112, 0x1113, 0x1114, 0x1115, 0x1116,
+	0x1121, 0x1122, 0x1123, 0x1124, 0x1125, 0x1126,
+	0x1131, 0x1132, 0x1133, 0x1134, 0x1135, 0x1136,
+	0x1141, 0x1142, 0x1143, 0x1144, 0x1145, 0x1146,
+	0x1151, 0x1152, 0x1153, 0x1154, 0x1155, 0x1156,
+	0x1161, 0x1162, 0x1163, 0x1164, 0x1165, 0x1166,
+	0x1171, 0x1172, 0x1173, 0x1174, 0x1175, 0x1176,
+};
+
+int16_t lfe_d_16[T_RP_LFE*T_RP_FRAMES] = {
+	0x0000, 0x0000,
+	0x0222, 0x0222,
+	0x0444, 0x0444,
+	0x0666, 0x0666,
+	0x0888, 0x0888,
+	0x0aaa, 0x0aaa,
+	0x0ccc, 0x0bbb,
+	0x0eee, 0x0ccc,
+};
+
+static int testpartten_replace(struct  aml_channel_map *map)
+{
+	if (map == NULL)
+		return -1;
+
+	printf("\n==16==\n\n");
+	_dump_data((void *)rep_d_16, T_RP_CHNUM_ALL, e16BitPerSample, T_RP_FRAMES);
+	printf("\n");
+	_dump_data((void *)lfe_d_16, T_RP_LFE,       e16BitPerSample, T_RP_FRAMES);
+
+	data_replace_lfe_data(
+		(void *)rep_d_16, T_RP_CHNUM_ALL, e16BitPerSample,
+		(void *)lfe_d_16, T_RP_LFE,       e16BitPerSample,
+		(T_RP_FRAMES),
+		data_get_channel_bit_mask(map, AML_CH_IDX_LFE)
+		);
+
+	printf("\n->after cancat:\n");
+	_dump_data((void *)rep_d_16, T_RP_CHNUM_ALL, e16BitPerSample, T_RP_FRAMES);
+
+	return 0;
+}
+
+/**
+ **        extend
+ */
+int16_t ex_d_16[8*8] = {
+	0x0001, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+	0x0000, 0x0001, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+	0x0000, 0x0000, 0x0001, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+	0x0000, 0x0000, 0x0000, 0x0001, 0x0000, 0x0000, 0x0000, 0x0000,
+	0x0000, 0x0000, 0x0000, 0x0000, 0x0001, 0x0000, 0x0000, 0x0000,
+	0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0001, 0x0000, 0x0000,
+	0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0001, 0x0000,
+	0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0001,
+};
+
+int16_t ex_in_d_16[8*2] = {
+	0x1101, 0x1102,
+	0x1111, 0x1112,
+	0x1121, 0x1122,
+	0x1131, 0x1132,
+	0x1141, 0x1142,
+	0x1151, 0x1152,
+	0x1161, 0x1162,
+	0x1171, 0x1172,
+};
+
+static int testpartten_extend(struct  aml_channel_map *map)
+{
+	if (map == NULL)
+		return -1;
+
+	printf("\n==16==\n\n");
+	_dump_data((void *)ex_d_16, 8/* channels */, e16BitPerSample, 8/*frames*/);
+	printf("\n");
+	_dump_data((void *)ex_in_d_16, 2/* channels */, e16BitPerSample, 8/*frames*/);
+	printf("\n");
+
+	data_extend_channels(
+		(void *)ex_d_16,    8, e16BitPerSample,
+		(void *)ex_in_d_16, 2, e16BitPerSample,
+		8/*frames*/
+		);
+
+	printf("\n->after extend:\n");
+	_dump_data((void *)ex_d_16, 8/* channels */, e16BitPerSample, 8/*frames*/);
+
+	return 0;
+}
+
+/**
+ **        extract
+ */
+int16_t ext_d_16[8*6] = {
+	0x1101, 0x1102, 0x1103, 0x1104, 0x1105, 0x1106,
+	0x1111, 0x1112, 0x1113, 0x1114, 0x1115, 0x1116,
+	0x1121, 0x1122, 0x1123, 0x1124, 0x1125, 0x1126,
+	0x1131, 0x1132, 0x1133, 0x1134, 0x1135, 0x1136,
+	0x1141, 0x1142, 0x1143, 0x1144, 0x1145, 0x1146,
+	0x1151, 0x1152, 0x1153, 0x1154, 0x1155, 0x1156,
+	0x1161, 0x1162, 0x1163, 0x1164, 0x1165, 0x1166,
+	0x1171, 0x1172, 0x1173, 0x1174, 0x1175, 0x1176,
+};
+
+int16_t ext_16[8*2] = {
+	0x0000, 0x0000,
+	0x0000, 0x0000,
+	0x0000, 0x0000,
+	0x0000, 0x0000,
+	0x0000, 0x0000,
+	0x0000, 0x0000,
+	0x0000, 0x0000,
+	0x0000, 0x0000,
+};
+
+static int testpartten_extract(struct  aml_channel_map *map)
+{
+	if (map == NULL)
+		return -1;
+
+	printf("\n==16==\n\n");
+	_dump_data((void *)ext_d_16, 6/* channels */, e16BitPerSample, 8/*frames*/);
+	printf("\n");
+	_dump_data((void *)ext_16,   2/* channels */, e16BitPerSample, 8/*frames*/);
+	printf("\n");
+
+	data_extract_channels(
+		map,
+		(void *)ext_16,   2/*channels*/, e16BitPerSample,
+		(void *)ext_d_16, 6/*channels*/, e16BitPerSample,
+		8/* frames */,
+		data_get_channel_bit_mask(map, AML_CH_IDX_LFE)
+		);
+
+	printf("\n->after extract:\n");
+
+	_dump_data((void *)ext_16,   2/* channels */, e16BitPerSample, 8/*frames*/);
+	printf("\n");
+
+	return 0;
+}
+
+
+int main(void)
+{
+	struct  aml_channel_map *map = NULL;
+
+	map = atmos_maps;
+	//map = mi_maps;
+
+#if 0
+	// case1: channel map, PASS
+#if 0
+	testpartten_chmap("Missionimpossible", mi_maps);
+	testpartten_chmap("Pulpfiction", pulpfiction_maps);
+	testpartten_chmap("Matrix", matrix_maps);
+	testpartten_chmap("Rainman", rainman_maps);
+#else
+	testpartten_chmap("Atmos", atmos_maps);
+#endif
+#endif
+
+#if 0
+	// case2: empty, PASS
+	testpartten_empty(map);
+	// case3: invert, PASS
+	testpartten_invert(map);
+	// case4: exchange, PASS
+	testpartten_exchange(map);
+	// case5: remix,                 !!!Support 16bit only
+	testpartten_remix(map);
+#endif
+	// case6: ditter,                !!!Support 16bit/8ch only
+	testpartten_ditter(map);
+
+#if 0
+	// case7: concat,                !!!only support same frame sz
+	testpartten_concat(map);
+#endif
+
+#if 0
+	// case8: replace lfe,           !!!only support all_6ch&lfe_2ch.
+	testpartten_replace(map);
+	// case9: extend,                !!!16bit only now
+	testpartten_extend(map);
+	// case10: extract,
+	map = mi_maps;
+	testpartten_extract(map);
+#endif
+
+	return 0;
+}