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;
+}