Add toolchain and mbtk source

Change-Id: Ie12546301367ea59240bf23d5e184ad7e36e40b3
diff --git a/mbtk/mbtk_lib/src/mbtk_audio.c b/mbtk/mbtk_lib/src/mbtk_audio.c
new file mode 100755
index 0000000..5d4af20
--- /dev/null
+++ b/mbtk/mbtk_lib/src/mbtk_audio.c
@@ -0,0 +1,861 @@
+/**
+ *   \file mbtk_audio.c
+ *   \brief A Documented file.
+ *
+ *  Detailed description
+ *   \Author:  js.wang <js.wang@mobiletek.cn>
+ *   \Version: 1.0.0
+ *   \Date: 2022-03-31
+ */
+#include <fcntl.h>
+#include <stdint.h>
+#include <limits.h>
+#include <termios.h>
+#include <stdarg.h>
+#include <dirent.h>
+#include <sys/stat.h>
+#include <sys/statfs.h>
+#include <sys/types.h>
+#include "mbtk_log.h"
+#include "mbtk_type.h"
+#include <libubox/blobmsg_json.h>
+#include "libubus.h"
+#include "mbtk_audio.h"
+
+/******************************************************************************\
+ *  Macros / Defines
+\******************************************************************************/
+
+#ifndef UNUSEDPARAM
+#define UNUSEDPARAM(a)		(void)(a)
+#endif
+
+#define AUDIO_UBUS_REQUEST_NAME         "audio_if"
+#define mbtk_dtmf_UBUS_NAME	            "proslic_uBus"      //Used by wake lock
+#define DTMFCODEID                      "dtmfcode"
+#define DTMFCODE_NOTIFICATION_NAME      "audioif.dtmfcode"
+#define AUDIO_UBUS_VOLUME_SET           "volume_set"
+#define AUDIO_UBUS_VOLUME_GET           "volume_status"
+#define AUDIO_UBUS_MODE_SET             "audio_mode_set"
+#define AUDIO_UBUS_DSP_SET          	"config_dspgain"
+#define AUDIO_UBUS_LOOPBACK_EN          "loopback_enable"
+#define AUDIO_UBUS_LOOPBACK_DIS         "loopback_disable"
+
+// #define DEBUG 1
+
+#ifdef DEBUG
+	#define mbtk_audio_log(...)                    mbtk_audio_log(__VA_ARGS__)
+#else
+	#define mbtk_audio_log(...)
+#endif
+
+typedef enum {
+    PARAM_INT_POLICY_0,
+    PARAM_INT_POLICY_1,
+    PARAM_INT_POLICY_2,
+    PARAM_INT_POLICY_3,
+    PARAM_INT_POLICY_MAX,
+} PARAM_INT_POLICY;
+const struct blobmsg_policy int_policy[] ={
+	[PARAM_INT_POLICY_0] = {
+		.name = "param0",
+		.type = BLOBMSG_TYPE_INT32,
+	},
+};
+
+const struct blobmsg_policy dtmf_code_policy[] = {
+	[0] = {
+		.name = DTMFCODEID,
+		.type = BLOBMSG_TYPE_INT32,
+	},
+};
+
+static void mbtk_dtmf_add_subscriber_AudioIf(struct uloop_timeout *timeout);
+static struct uloop_timeout mbtk_dtmf_add_subscribe_timeout_AudioIf =
+{
+    .cb = mbtk_dtmf_add_subscriber_AudioIf,
+};
+
+static struct blob_buf audio_cm_b;
+pthread_mutex_t mbtk_dtmf_mutex;
+int  mbtk_dtmf_PMConstraintWorks;
+//For UBUS listening to RILD & audio_if
+struct mbtk_audio_ubus_db_t
+{
+    pthread_t  dtmf_pthread;
+    mbtk_dtmf_cb dtmf_cb;
+    mbtk_volume_cb audio_volume_get_cb;
+    int work_state;
+    struct ubus_context     *ctx;
+
+    /* Audio_If */
+    struct ubus_subscriber 	audioif_event;
+    uint32_t	 		    audioif_subscriber_id;
+    uint32_t	 		    audioif_request_id;
+};
+
+static struct mbtk_audio_ubus_db_t  *mbtk_audio_ubus_db = NULL;
+
+
+static int record_fd = 0;
+
+#define AUDIO_FILE_DIR	"/data"
+#define MBTK_AUD_DEMO_WAV "/data/demo.wav"
+
+int create_audio_dir(const char *dirname)
+{
+    DIR *p_dir;
+    int res = -1;
+
+    if(NULL == (p_dir = opendir((const char *)dirname)))
+    {
+        if(mkdir(dirname, 0777) == 0)
+        {
+            res = 0;
+        }
+        else
+        {
+            fprintf(stderr, "create audio dir error \n");
+            res = -1;
+        }
+    }
+    else
+    {
+        closedir(p_dir);
+        res = 0;
+    }
+    return res;
+}
+int mbtk_at_play(const char *args)
+{
+    int fd = 0;
+    int play_hdl = 0;
+    char databuf[1024];
+    int size;
+
+    LOGI("%s %d", __FUNCTION__, __LINE__);
+    // play_hdl = Ql_AudPlayer_Open(NULL, NULL);
+    play_hdl = mbtk_audio_open(0, 1, 8000, NULL);
+    if(0 == play_hdl)
+        printf("Ql_AudPlayer_Open fail\n");
+
+    fd = open(MBTK_AUD_DEMO_WAV, O_RDWR);
+    if (fd <= 0)
+    {
+        printf("file open error\n");
+        goto err;
+    }
+    memset(databuf, 0, sizeof(databuf));
+    while(0 < (size = read(fd, databuf, sizeof(databuf))))
+    {
+        if(-1 == mbtk_audio_play_stream(play_hdl, databuf, size))
+            break;
+    }
+    mbtk_audio_log("aplay Stream end \n");
+
+err:
+    if(fd > 0)
+        close(fd);
+    mbtk_audio_close(play_hdl);
+
+    return 0;
+}
+
+void record_cb_func(int cb_result, char* databuf, unsigned int len)
+{
+    int rc;
+
+    if(NULL != databuf && len > 0 && record_fd > 0)
+    {
+        //for debug:save into file
+        rc = write(record_fd, databuf, len);
+        if (rc < 0) {
+            printf("%s: error writing to file!\n", __FUNCTION__);
+        } else if (rc < len) {
+            printf("%s: wrote less the buffer size!\n", __FUNCTION__);
+        }
+    }
+}
+
+int mbtk_at_rec(const char *args)
+{
+    LOGI("%s %d", __FUNCTION__, __LINE__);
+    //hdl = Ql_AudRecorder_Open(NULL, record_cb_func);
+    void *record_hdl = mbtk_audio_open(1, 1, 8000, NULL);
+    if (record_hdl == NULL)
+    {
+        printf("AudRecorder open error\n");
+        return -1;
+    }
+
+    create_audio_dir(AUDIO_FILE_DIR);
+    record_fd = open(MBTK_AUD_DEMO_WAV, O_RDWR|O_CREAT|O_TRUNC, 0644);
+    if (record_fd <= 0)
+    {
+        printf("file open error\n");
+        goto err;
+    }
+
+    if(-1 == mbtk_audio_record(record_hdl, record_cb_func, NULL))
+    {
+        printf("file write error\n");
+        close(record_fd);
+        record_fd = 0;
+    }
+    sleep(10);
+err:
+    mbtk_audio_close(record_hdl);
+    record_hdl = NULL;
+    if(record_fd > 0)
+    {
+        close(record_fd);
+        record_fd = 0;
+    }
+
+    return 0;
+}
+
+static void mbtk_ubus_complete_cb(struct ubus_request *req, int rc)
+{
+    if(NULL == mbtk_audio_ubus_db)
+    {
+        printf("mbtk_dtmf_ubus not init!\n");
+        return;
+    }
+    if (req)
+    {
+        free(req);
+        req = NULL;
+    }
+    mbtk_audio_log("%s do nothing, rc=%d\n", __FUNCTION__, rc);
+    LOGI("%s do nothing, rc=%d\n", __FUNCTION__, rc);
+    if(mbtk_audio_ubus_db->work_state)
+        mbtk_audio_ubus_db->work_state--;
+}
+/**
+ * @brief      mbtk_audio_mode_set
+ *
+ * @details    detailed description
+ *
+ * @param      param
+ *             "param0": UINT32
+ *             typedef enum {
+ *                 AUDIO_MODE_INVALID = -2,
+ *                 AUDIO_MODE_CURRENT = -1,
+ *                 AUDIO_MODE_NORMAL = 0,
+ *                 AUDIO_MODE_RINGTONE = 1,
+ *                 AUDIO_MODE_IN_CALL = 2,
+ *                 AUDIO_MODE_IN_COMMUNICATION=3,
+ *                 AUDIO_MODE_IN_VT_CALL= 4,
+ *                 AUDIO_MODE_CNT,
+ *                 AUDIO_MODE_MAX = AUDIO_MODE_CNT-1,
+ *             } audio_mode_
+ * @return     return type
+ */
+static void mbtk_audio_mode_set(int mode)
+{
+    int rc = 0;
+    struct ubus_request *req = NULL;
+
+    if(NULL == mbtk_audio_ubus_db)
+    {
+        printf("mbtk_dtmf_ubus not init!\n");
+        return;
+    }
+    req = (struct ubus_request *)malloc(sizeof(struct ubus_request));
+    if (req == NULL)
+    {
+        printf("leave %s: lack of memory\n", __FUNCTION__);
+        return;
+    }
+    memset(req, 0, sizeof(struct ubus_request));
+    blob_buf_init(&audio_cm_b, 0);
+    blobmsg_add_u32(&audio_cm_b, "param0", mode);
+    if ((rc = ubus_invoke_async(mbtk_audio_ubus_db->ctx,
+                                mbtk_audio_ubus_db->audioif_request_id,
+                                AUDIO_UBUS_MODE_SET,
+                                audio_cm_b.head, req)) != UBUS_STATUS_OK)
+    {
+        free(req);
+        printf("%s, ubus_invoke_async %s failed %s\n", __FUNCTION__, AUDIO_UBUS_MODE_SET, ubus_strerror(rc));
+    }
+    else
+    {
+        printf("%s: ubus_invoke_async success\n", __FUNCTION__);
+        mbtk_audio_ubus_db->work_state++;
+        req->complete_cb = mbtk_ubus_complete_cb;
+        ubus_complete_request_async(mbtk_audio_ubus_db->ctx, req);
+    }
+}
+int mbtk_audio_dsp_set(int type, int gain)
+{
+    LOGE("1type:%d, gain:%d\n", type, gain);
+    int rc = 0;
+    struct ubus_request *req = NULL;
+
+    if(NULL == mbtk_audio_ubus_db)
+    {
+        LOGE("mbtk_dtmf_ubus not init!\n");
+        return -1;
+    }
+    req = (struct ubus_request *)malloc(sizeof(struct ubus_request));
+    if (req == NULL)
+    {
+        LOGE("leave %s: lack of memory\n", __FUNCTION__);
+        return -1;
+    }
+
+    memset(req, 0, sizeof(struct ubus_request));
+    blob_buf_init(&audio_cm_b, 0);
+    blobmsg_add_u32(&audio_cm_b, "type", type);
+	blobmsg_add_u32(&audio_cm_b, "gain", gain);
+    if ((rc = ubus_invoke_async(mbtk_audio_ubus_db->ctx,
+                                mbtk_audio_ubus_db->audioif_request_id,
+                                AUDIO_UBUS_DSP_SET,
+                                audio_cm_b.head, req)) != UBUS_STATUS_OK)
+    {
+        free(req);
+        LOGE("%s, ubus_invoke_async %s failed %s\n", __FUNCTION__, AUDIO_UBUS_DSP_SET, ubus_strerror(rc));
+        return -1;
+    }
+    else
+    {
+        LOGE("%s: ubus_invoke_async success\n", __FUNCTION__);
+        mbtk_audio_ubus_db->work_state++;
+        req->complete_cb = mbtk_ubus_complete_cb;
+        ubus_complete_request_async(mbtk_audio_ubus_db->ctx, req);
+    }
+    return 0;
+}
+/**
+ * @brief      mbtk_audio_loopback_start
+ *
+ * @details    detailed description
+ *
+ * @param      param
+ *             device: UINT32
+ *             0: earpiece
+ *             1: speaker
+ *             2: headset
+ * @return     return type
+ */
+static void mbtk_audio_loopback_start(int device)
+{
+    int rc = 0;
+    struct ubus_request *req = NULL;
+
+    if(NULL == mbtk_audio_ubus_db)
+    {
+        LOGI("mbtk_dtmf_ubus not init!\n");
+        return;
+    }
+    req = (struct ubus_request *)malloc(sizeof(struct ubus_request));
+    if (req == NULL)
+    {
+        LOGI("leave %s: lack of memory\n", __FUNCTION__);
+        return;
+    }
+    memset(req, 0, sizeof(struct ubus_request));
+    blob_buf_init(&audio_cm_b, 0);
+    blobmsg_add_u32(&audio_cm_b, "param0", device);
+    if ((rc = ubus_invoke_async(mbtk_audio_ubus_db->ctx,
+                                mbtk_audio_ubus_db->audioif_request_id,
+                                AUDIO_UBUS_LOOPBACK_EN,
+                                audio_cm_b.head, req)) != UBUS_STATUS_OK)
+    {
+        free(req);
+        LOGI("%s, ubus_invoke_async volume get failed %s\n", __FUNCTION__,  ubus_strerror(rc));
+    }
+    else
+    {
+        LOGI("%s: ubus_invoke_async success\n", __FUNCTION__);
+        req->complete_cb = mbtk_ubus_complete_cb;
+        ubus_complete_request_async(mbtk_audio_ubus_db->ctx, req);
+    }
+}
+
+static void mbtk_audio_loopback_stop(void)
+{
+    int rc = 0;
+
+    if(NULL == mbtk_audio_ubus_db)
+    {
+        printf("mbtk_dtmf_ubus not init!\n");
+        return;
+    }
+    blob_buf_init(&audio_cm_b, 0);
+
+    if ((rc = ubus_invoke(mbtk_audio_ubus_db->ctx,
+                          mbtk_audio_ubus_db->audioif_request_id,
+                          AUDIO_UBUS_LOOPBACK_DIS,
+                          audio_cm_b.head, NULL, 0, 0)) != UBUS_STATUS_OK)
+    {
+        LOGI("%s, ubus_invoke volume get failed %s\n", __FUNCTION__,  ubus_strerror(rc));
+    }
+    else
+    {
+        LOGI("%s: ubus_invoke success\n", __FUNCTION__);
+    }
+}
+
+int mbtk_at_loopback(int type)
+{
+    static mbtk_audio_client_handle_type audio_handle = 0;
+    int ret = 0;
+
+    LOGI("%s %d:%d", __FUNCTION__, __LINE__, type);
+    if(0 == type) // Stop
+    {
+        mbtk_audio_loopback_stop();
+        if(audio_handle)
+        {
+            mbtk_audio_ubus_client_deinit(audio_handle);
+            audio_handle = 0;
+        }
+    }
+    else // Start
+    {
+        if(NULL == mbtk_audio_ubus_db)
+            ret = mbtk_audio_ubus_client_init(&audio_handle, NULL);
+        if(ret)
+        {
+            return -1;
+        }
+        mbtk_audio_mode_set(0);
+        mbtk_audio_loopback_start(2);
+    }
+
+    return 0;
+}
+
+/*****************************************************  \
+ *   Retry mechanism to add subscriber for Audio_if
+\*****************************************************/
+static void mbtk_dtmf_add_subscriber_AudioIf(struct uloop_timeout *timeout)
+{
+    /* add subscriber for Audio_If */
+    if (ubus_lookup_id(mbtk_audio_ubus_db->ctx, DTMFCODE_NOTIFICATION_NAME, &mbtk_audio_ubus_db->audioif_subscriber_id))
+    {
+        printf("%s, Failed to look up %s\n", __FUNCTION__, DTMFCODE_NOTIFICATION_NAME);
+        uloop_timeout_set(timeout, 2000);
+        return;
+    }
+
+    ubus_subscribe(mbtk_audio_ubus_db->ctx, &mbtk_audio_ubus_db->audioif_event, mbtk_audio_ubus_db->audioif_subscriber_id);
+    mbtk_audio_log("Audio_If subscribe %s object ok\n", DTMFCODE_NOTIFICATION_NAME);
+    return;
+}
+/*******************************************************************************\
+*   Function:      mbtk_dtmf_uBus_pmConstraint
+*   Description:   Lock/unlock system power management.
+*                   0: unlock
+*                   1: lock
+*   Returns:
+\*******************************************************************************/
+static void mbtk_dtmf_uBus_PMConstraint(int set)
+{
+    FILE *flk;
+    if (mbtk_dtmf_PMConstraintWorks != 0)
+        return; //wake_lock unavailable or not exist. Do nothing
+
+#ifdef PROSLIC_ENABLEFREERUN
+    mbtk_audio_log("%s(%d): %s\n", __FUNCTION__, set, set ? "no sleep" : "sleep after 7s");
+#else
+    mbtk_audio_log("%s(%d): free-run is disabled, no sleep\n", __FUNCTION__, set);
+#endif
+
+    /* Do Not check fopen success. It must be ok, if failed
+    ** (for any reason) better to crash for logging and recovery
+    */
+    flk = fopen("/sys/power/wake_lock", "w");
+    if(set)
+    {
+        fprintf(flk, mbtk_dtmf_UBUS_NAME);
+    }
+    else
+    {
+#ifdef PROSLIC_ENABLEFREERUN
+        /* Clear constraint but with TimeOut enough
+        ** Stay awake for (mbtk_dtmf_DIAL_TIMER + 1) seconds, wait for ringing timer expire
+        */
+        fprintf(flk, mbtk_dtmf_UBUS_NAME " 7000000000"/*nsec*/);
+#endif
+    }
+
+    fclose(flk);
+}
+
+/*******************************************************************************\
+*   Function:       mbtk_dtmf_uBusInd_AudioIf_remove
+*   Description:    Handle upon Audio_if remove indication.
+*   Returns:
+\*******************************************************************************/
+static void mbtk_dtmf_uBusInd_AudioIf_remove(struct ubus_context *ctx, struct ubus_subscriber *s,
+                              uint32_t id)
+{
+    UNUSEDPARAM(ctx);
+    UNUSEDPARAM(s);
+    UNUSEDPARAM(id);
+
+    mbtk_audio_log("%s\n", __FUNCTION__);
+    uloop_timeout_set(&mbtk_dtmf_add_subscribe_timeout_AudioIf, 2000);
+}
+
+
+/*******************************************************************************\
+*   Function:       mbtk_dtmf_uBusInd_AudioIf
+*   Description:    Handle upon Audio_If incoming indication.
+*   Returns:        0 on success
+\*******************************************************************************/
+static int mbtk_dtmf_uBusInd_AudioIf(struct ubus_context *ctx, struct ubus_object *obj,
+                               struct ubus_request_data *req, const char *method,
+                               struct blob_attr *msg)
+{
+    UNUSEDPARAM(ctx);
+    UNUSEDPARAM(obj);
+    UNUSEDPARAM(req);
+    UNUSEDPARAM(method);
+
+    char DTMFCode = 0;
+    struct blob_attr *tb[1];
+    int rc = 0;
+
+    //Lock from mbtk_dtmf interrupt handler (mbtk_dtmf_MainLoop)
+    pthread_mutex_lock(&mbtk_dtmf_mutex);
+    mbtk_audio_log("==================================%s : Begin==================================\n", __FUNCTION__);
+    mbtk_dtmf_uBus_PMConstraint(1);
+
+    /*parsing blob to be accessed easily with tb array - parse "1" argument*/
+    rc = blobmsg_parse(dtmf_code_policy, 1, tb, blob_data(msg), blob_len(msg));
+
+    if (rc < 0) {
+    	printf("%s: parsing fail, rc = 0x%x\n", __FUNCTION__, rc);
+    }
+    else {
+        DTMFCode = (char)blobmsg_get_u32(tb[0]);
+        if(mbtk_audio_ubus_db->dtmf_cb)
+            mbtk_audio_ubus_db->dtmf_cb(DTMFCode);
+        mbtk_audio_log("%s got DTMF Code: Char[%c]=ASCII[0x%x]\n", __FUNCTION__, DTMFCode, DTMFCode);
+    }
+
+    mbtk_dtmf_uBus_PMConstraint(0);
+    mbtk_audio_log("==================================%s : End==================================", __FUNCTION__);
+    pthread_mutex_unlock(&mbtk_dtmf_mutex);
+
+    return rc;
+}
+
+/*******************************************************************************\
+*   Function:       mbtk_dtmf_uBusRegisterNotifications
+*   Description:    Register UBUS notifications of RIL and Audio_If.
+*   Returns:        0 on success
+\*******************************************************************************/
+static int mbtk_dtmf_uBusRegisterNotifications(void)
+{
+    int ret = 0;
+
+    /* register UBUS notifications of Audio_If */
+    ret = ubus_register_subscriber(mbtk_audio_ubus_db->ctx, &mbtk_audio_ubus_db->audioif_event);
+    if (ret)
+    {
+        printf("%s Failed to add audio_if watch handler: %s\n", __FUNCTION__, ubus_strerror(ret));
+        return -1;
+    }
+
+    /* specify callback to handle notifications */
+    mbtk_audio_ubus_db->audioif_event.remove_cb = mbtk_dtmf_uBusInd_AudioIf_remove;
+    mbtk_audio_ubus_db->audioif_event.cb = mbtk_dtmf_uBusInd_AudioIf;
+
+    /* add subscribe */
+    uloop_timeout_set(&mbtk_dtmf_add_subscribe_timeout_AudioIf, 0);
+
+    mbtk_audio_log("%s: Make use of DTMF detection in modem.\n", __FUNCTION__);
+
+    return 0;
+}
+
+void mbtk_switch_dtmf_detection_cb(struct ubus_request *req, int rc)
+{
+    if (req)
+    {
+        free(req);
+        req = NULL;
+    }
+    mbtk_audio_log("%s do nothing, rc=%d\n", __FUNCTION__, rc);
+}
+/**
+ * @brief      mbtk_switch_dtmf_detection
+ *
+ * @details    detailed description
+ *
+ * @param      param
+ *            “param0": UINT32 onoff
+ *              0: disbale Tx DTMF detection
+ *              1: enable Tx DTMF detection
+ *              2: disbale Rx DTMF detection
+ *              3: enable Rx DTMF detection
+ * @return     return type
+ */
+void mbtk_switch_dtmf_detection(unsigned short on_off, unsigned short param1,
+                                unsigned short param2, unsigned short param3)
+{
+#if PCM_CTRL_OVER_VCM
+    vcm_DTMFDetection(on_off, param1, param2, param3);
+#else
+    int rc = 0;
+    struct ubus_request *req = NULL;
+
+    if(NULL == mbtk_audio_ubus_db)
+    {
+        printf("mbtk_dtmf_ubus not init!\n");
+        return;
+    }
+    req = (struct ubus_request *)malloc(sizeof(struct ubus_request));
+    if (req == NULL)
+    {
+        printf("leave %s: lack of memory\n", __FUNCTION__);
+        return;
+    }
+    memset(req, 0, sizeof(struct ubus_request));
+    blob_buf_init(&audio_cm_b, 0);
+    blobmsg_add_u32(&audio_cm_b, "param0", on_off);
+    blobmsg_add_u32(&audio_cm_b, "param1", param1);
+    blobmsg_add_u32(&audio_cm_b, "param2", param2);
+    blobmsg_add_u32(&audio_cm_b, "param3", param3);
+
+    if ((rc = ubus_invoke_async(mbtk_audio_ubus_db->ctx, mbtk_audio_ubus_db->audioif_request_id, "dtmf_detection", audio_cm_b.head, req)) != UBUS_STATUS_OK)
+    {
+        free(req);
+        printf("%s, ubus_invoke dtmf_detection failed %s\n", __FUNCTION__,  ubus_strerror(rc));
+    }
+    else
+    {
+        mbtk_audio_log("%s: ubus_invoke_async success\n", __FUNCTION__);
+        req->complete_cb = mbtk_switch_dtmf_detection_cb;
+        ubus_complete_request_async(mbtk_audio_ubus_db->ctx, req);
+    }
+#endif
+}
+/*******************************************************************************\
+*   Function:       mbtk_dtmf_uBusInit
+*   Description:    Init UBUS context and register UBUS notifications of RIL.
+*   Returns:        0 on success
+\*******************************************************************************/
+int mbtk_dtmf_uBusInit(void)
+{
+    int rc = 0;
+
+    uloop_init();
+
+    mbtk_audio_ubus_db->ctx = ubus_connect(NULL);
+    if (mbtk_audio_ubus_db->ctx == NULL)
+    {
+        printf(" %s Failed to connect to ubus\n", __FUNCTION__);
+        return -1;
+    }
+
+    ubus_add_uloop(mbtk_audio_ubus_db->ctx);
+
+    /* lookup fail if audio_if is not ready */
+    while(1)
+    {
+        rc = ubus_lookup_id(mbtk_audio_ubus_db->ctx, AUDIO_UBUS_REQUEST_NAME, &mbtk_audio_ubus_db->audioif_request_id);
+        if (0 != rc)
+        {
+            printf("%s, Failed to look up(%s), rc=%d\n", __FUNCTION__, AUDIO_UBUS_REQUEST_NAME, rc);
+            usleep(600000); //600ms
+        }
+        else
+            break;
+    }
+    mbtk_audio_log("%s, ubus_lookup_id(%s) OK\n", __FUNCTION__, AUDIO_UBUS_REQUEST_NAME);
+
+    /* subscribe for RIL & audio_if notifications */
+    if (mbtk_dtmf_uBusRegisterNotifications() != 0)
+        return -1;
+
+    mbtk_audio_log("%s success!\n", __FUNCTION__);
+    return 0;
+}
+
+
+/*******************************************************************************\
+*   Function:       mbtk_dtmf_uBusRun
+*   Description:    Start running of UBUS.
+*   Returns:
+\*******************************************************************************/
+static void mbtk_audio_ubus_thread(void* hdl)
+{
+    pthread_detach(pthread_self());
+    uloop_run();
+    mbtk_audio_log("%s exit!\n", __FUNCTION__);
+    pthread_exit(NULL);
+}
+
+int mbtk_audio_ubus_client_init(mbtk_audio_client_handle_type *ph_audio, mbtk_dtmf_cb cb)
+{
+    int id;
+
+    // Set call handle.
+    if(ph_audio == NULL || mbtk_audio_ubus_db != NULL)
+    {
+        printf("ARG error or has inited.");
+        return -1;
+    }
+    mbtk_audio_ubus_db = malloc(sizeof(struct mbtk_audio_ubus_db_t));
+    if(NULL == mbtk_audio_ubus_db)
+    {
+        printf("malloc memory error\n");
+    }
+    memset(mbtk_audio_ubus_db, 0, sizeof(struct mbtk_audio_ubus_db_t));
+
+	mbtk_dtmf_PMConstraintWorks = access("/sys/power/wake_lock", R_OK | W_OK);
+    mbtk_dtmf_uBusInit();
+    mbtk_audio_ubus_db->dtmf_cb = cb;
+
+    mbtk_switch_dtmf_detection(3, 50, 4, 3);
+    pthread_create(&mbtk_audio_ubus_db->dtmf_pthread, NULL, (void *)mbtk_audio_ubus_thread, (void *)mbtk_audio_ubus_db);
+
+    *ph_audio = mbtk_audio_ubus_db;
+    LOGI("%s %d:%x", __FUNCTION__, __LINE__, mbtk_audio_ubus_db);
+
+    return 0;
+}
+
+int mbtk_audio_ubus_client_deinit(mbtk_audio_client_handle_type h_audio)
+{
+    int ret;
+    struct mbtk_audio_ubus_db_t *audio_ubus = (struct mbtk_audio_ubus_db_t *)h_audio;
+
+    mbtk_audio_log("%s \n", __FUNCTION__);
+    if(h_audio == NULL || mbtk_audio_ubus_db == NULL)
+    {
+        printf("ARG error or not inited.");
+        return -1;
+    }
+    LOGI("%s %d:%x", __FUNCTION__, __LINE__, audio_ubus);
+    ret = pthread_cancel(audio_ubus->dtmf_pthread);
+    mbtk_audio_log("kill pthread : %d \n", ret);
+    pthread_join(audio_ubus->dtmf_pthread, NULL);
+    do{
+        ret = pthread_kill(audio_ubus->dtmf_pthread, 0);
+        mbtk_audio_log("kill pthread: %d \n", ret);
+        if(ret == ESRCH)
+            mbtk_audio_log("The specified thread does not exist or has terminated\n");
+        else if(ret == EINVAL)
+            mbtk_audio_log("Useless signal\n");
+        else
+            mbtk_audio_log("The thread exists\n");
+        usleep(100000);
+    }while(0 == ret);
+    LOGI("%s %d", __FUNCTION__, __LINE__);
+
+    mbtk_switch_dtmf_detection(2, 0, 0, 0);
+    /*unregister uloop*/
+    /*thread will get here only if uloop stopped*/
+    ubus_free(mbtk_audio_ubus_db->ctx);
+    uloop_done();
+    LOGI("%s %d", __FUNCTION__, __LINE__);
+    free(h_audio);
+    mbtk_audio_ubus_db = NULL;
+
+    return 0;
+}
+
+/**********************************************************************\
+*   Function:      APP_Audio_VolumeSet
+*   Description:   This function is called to send command into audio_if.
+*   unsigned int volume(0~100)
+*   Returns:        0 on success
+\**********************************************************************/
+void mbtk_audio_ubus_volume_set(unsigned int volume)
+{
+    int rc = 0;
+    struct ubus_request *req = NULL;
+
+    if(NULL == mbtk_audio_ubus_db)
+    {
+        printf("mbtk_dtmf_ubus not init!\n");
+        return;
+    }
+    req = (struct ubus_request *)malloc(sizeof(struct ubus_request));
+    if (req == NULL)
+    {
+        printf("leave %s: lack of memory\n", __FUNCTION__);
+        return;
+    }
+    memset(req, 0, sizeof(struct ubus_request));
+    blob_buf_init(&audio_cm_b, 0);
+    blobmsg_add_u32(&audio_cm_b, "param0", volume);
+
+    if ((rc = ubus_invoke_async(mbtk_audio_ubus_db->ctx, mbtk_audio_ubus_db->audioif_request_id, AUDIO_UBUS_VOLUME_SET, audio_cm_b.head, req)) != UBUS_STATUS_OK)
+    {
+        free(req);
+        printf("%s, ubus_invoke_async volume set failed: %s\n", __FUNCTION__,  ubus_strerror(rc));
+    }
+    else
+    {
+        mbtk_audio_log("%s: ubus_invoke_async success\n", __FUNCTION__);
+        req->complete_cb = mbtk_ubus_complete_cb;
+        ubus_complete_request_async(mbtk_audio_ubus_db->ctx, req);
+    }
+}
+
+static void audio_volume_get_data_cb (struct ubus_request *req, int type, struct blob_attr *msg)
+{
+    UNUSEDPARAM(req);
+    UNUSEDPARAM(type);
+    struct blob_attr *tb[1];
+    unsigned int volume = 888;
+    int rc = 0;
+
+    rc = blobmsg_parse(int_policy, 1, tb, blob_data(msg), blob_len(msg));
+    if (rc < 0)
+    {
+    	printf("[%s] parsing blobmsg failed\n", __FUNCTION__);
+    	return;
+    }
+
+    if(tb[0])
+        volume = blobmsg_get_u32(tb[0]);
+    if (mbtk_audio_ubus_db->audio_volume_get_cb)
+        mbtk_audio_ubus_db->audio_volume_get_cb(volume);
+    mbtk_audio_log("%s; volume:%d\n", __FUNCTION__, volume);
+}
+
+void mbtk_audio_ubus_volume_get(mbtk_volume_cb cb)
+{
+    int rc = 0;
+    struct ubus_request *req = NULL;
+
+    if(NULL == mbtk_audio_ubus_db ||  NULL == cb)
+    {
+        printf("mbtk_dtmf_ubus not init or callback invalid!\n");
+        return;
+    }
+    mbtk_audio_ubus_db->audio_volume_get_cb = cb;
+    req = (struct ubus_request *)malloc(sizeof(struct ubus_request));
+    if (req == NULL)
+    {
+        printf("leave %s: lack of memory\n", __FUNCTION__);
+        return;
+    }
+    memset(req, 0, sizeof(struct ubus_request));
+    blob_buf_init(&audio_cm_b, 0);
+
+    if ((rc = ubus_invoke_async(mbtk_audio_ubus_db->ctx,
+                                mbtk_audio_ubus_db->audioif_request_id,
+                                AUDIO_UBUS_VOLUME_GET,
+                                audio_cm_b.head, req)) != UBUS_STATUS_OK)
+    {
+        free(req);
+        printf("%s, ubus_invoke_async volume get failed %s\n", __FUNCTION__,  ubus_strerror(rc));
+    }
+    else
+    {
+        mbtk_audio_log("%s: ubus_invoke_async success\n", __FUNCTION__);
+        req->data_cb = audio_volume_get_data_cb;
+        req->complete_cb = mbtk_ubus_complete_cb;
+        ubus_complete_request_async(mbtk_audio_ubus_db->ctx, req);
+    }
+}