Add mbtk/liblynq_lib_v2/ mbtk/libql_lib_v2/

Change-Id: Idbb802cd805b34603ccf65bff9818725a6955e51
diff --git a/mbtk/libql_lib_v2/src/ql_call.c b/mbtk/libql_lib_v2/src/ql_call.c
new file mode 100755
index 0000000..700f93d
--- /dev/null
+++ b/mbtk/libql_lib_v2/src/ql_call.c
@@ -0,0 +1,821 @@
+/**
+ *   \file ql_call.c
+ *   \brief A Documented file.
+ *
+ *  Detailed description
+ *   \Author:  js.wang<js.wang@mobiletek.cn>
+ *   \Version: 1.0.0
+ *   \Date: 2022-01-18
+ */
+#include "ql/ql_mcm_call.h"
+#include <telephony/ril.h>
+#include <telephony/ril_ext.h>
+#include "ql/ql_mcm.h"
+#include "rilutil.h"
+#include "mbtk_log.h"
+
+// #define DEBUG 1
+
+#ifdef DEBUG
+	#define mbtk_call_log(...)                    printf(__VA_ARGS__)
+#else
+	#define mbtk_call_log(...)
+#endif
+
+struct ql_call_ubus_t
+{
+    struct ubus_context     *ctx;
+
+    /* RIL */
+    struct ubus_subscriber 	ril_ind_event;
+    uint32_t	 		    ril_subscriber_id;
+    uint32_t	 		    ril_request_id;
+    uint8_t	 		        auto_answer;
+    uint32_t                answer_time;
+    pthread_t  call_status_pthread;
+    ql_mcm_voice_calls_state_t  call_state;
+    QL_VoiceCall_CommonStateHandlerFunc_t _voice_call_common_state_handler;
+    QL_VoiceCall_StateHandlerFunc_t   _voice_call_state_handler;
+};
+
+const char *RIL_MessageMap[] =
+{
+        "RIL_CALL_ACTIVE",       //0,
+        "RIL_CALL_HOLDING",      //1,
+        "RIL_CALL_DIALING",      //2,    /* MO call only */
+        "RIL_CALL_ALERTING",     //3,    /* MO call only */
+        "RIL_CALL_INCOMING",     //4,    /* MT call only */
+        "RIL_CALL_WAITING",      //5,    /* MT call only */
+        "RIL_CALL_OFFERING",     //6,    /* MT call offering (call setup) */
+        "RIL_CALL_DISCONNECTING",//7,    /* call in disconnect procedure */
+        "RIL_CALL_DISCONNECTED"  //8,    /* call is disconnected */
+};
+static struct ql_call_ubus_t *ql_call_ubus = NULL;
+static void ql_voice_call_answer(struct uloop_timeout *timeout);
+static struct uloop_timeout voice_call_answer_timeout =
+{
+    .cb = ql_voice_call_answer,
+};
+
+static void ql_voice_call_answer(struct uloop_timeout *timeout)
+{
+    QL_Voice_Call_Answer(ql_call_ubus, 0);
+    // uloop_timeout_set(timeout, 2000);
+    return;
+}
+
+int ql_call_handle_ril_ind(struct ubus_context *ctx, unsigned int rilid, unsigned int rilerror, char *data, int data_len)
+{
+	UNUSED(data_len);
+	UNUSED(ctx);
+
+    int datalen = 0, callID = 0;
+	int ret = 0;
+
+	if (rilerror) {
+		return -1;
+	}
+
+	mbtk_call_log("call_handle_ril_ind: rcv %d\n", rilid);
+
+	 switch(rilid)
+	 {
+		case RIL_UNSOL_ECALLDATA:								//+ecalldata
+			// ecallHandleEcalldata(data);
+			break;
+
+		case RIL_UNSOL_ECALLONLY:								//+ecallonly
+			// ecallHandleEcallonly(data);
+			break;
+
+        case RIL_UNSOL_RESPONSE_CALL_STATE_CHANGED_EXT: /*"CC" 1510*/
+        {
+            RIL_Call *rilCall = (RIL_Call *)data;
+            callID = rilCall->index;
+
+            mbtk_call_log("%s: id %d=RIL_UNSOL_RESPONSE_CALL_STATE_CHANGED_EXT (len=%d) (state=%s), call index=%d\n",
+                    __FUNCTION__, rilid, datalen, RIL_MessageMap[(int)rilCall->state], callID);
+
+            mbtk_call_log("Received from Ril, name=%s, num=%s\n", rilCall->name, rilCall->number);
+            ql_call_ubus->call_state.calls_len = 1;
+            ql_call_ubus->call_state.calls[0].call_id;
+            memcpy(ql_call_ubus->call_state.calls[0].number, rilCall->number, strlen(rilCall->number));
+            ql_call_ubus->call_state.calls[0].state = rilCall->state;
+            switch (rilCall->state)
+            {
+                //Call connected,  for MO & MT both
+                case RIL_CALL_ACTIVE:
+                    mbtk_call_log("%s, RIL_CALL_ACTIVE, call index=%d connected!!\n", __FUNCTION__, callID);
+                    ql_call_ubus->call_state.calls[0].state = E_QL_MCM_VOICE_CALL_STATE_ACTIVE;
+                    break;
+
+                //MT call only
+                case RIL_CALL_INCOMING:
+                    mbtk_call_log("%s, RIL_CALL_INCOMING!!\n", __FUNCTION__);
+                    ql_call_ubus->call_state.calls[0].state = E_QL_MCM_VOICE_CALL_STATE_INCOMING;
+                    if(!ql_call_ubus->auto_answer)
+                    {
+                        mbtk_call_log("%s, auto_answer:%d!!\n", __FUNCTION__, ql_call_ubus->answer_time);
+                        uloop_timeout_set(&voice_call_answer_timeout, ql_call_ubus->answer_time);
+                    }
+                    break;
+
+                //MO call only
+                case RIL_CALL_ALERTING:
+                    mbtk_call_log("%s, RIL_CALL_ALERTING, call index=%d alerting!!\n", __FUNCTION__, callID);
+                    ql_call_ubus->call_state.calls[0].state = E_QL_MCM_VOICE_CALL_STATE_ALERTING;
+                    break;
+
+                case RIL_CALL_WAITING:  //MT call only
+                    mbtk_call_log("%s, RIL_CALL_WAITING, call index=%d alerting!!\n", __FUNCTION__, callID);
+                    ql_call_ubus->call_state.calls[0].state = E_QL_MCM_VOICE_CALL_STATE_WAITING;
+                    break;
+
+                case RIL_CALL_DISCONNECTED:
+                    mbtk_call_log("%s, RIL_CALL_DISCONNECTED, call index=%d disconnected!!\n", __FUNCTION__, callID);
+                    ql_call_ubus->call_state.calls[0].state = E_QL_MCM_VOICE_CALL_STATE_END;
+                    break;
+
+                case RIL_CALL_HOLDING:
+                    ql_call_ubus->call_state.calls[0].state = E_QL_MCM_VOICE_CALL_STATE_HOLDING;
+                    mbtk_call_log("%s, RIL_CALL_HOLDING, call index=%d hold!!\n", __FUNCTION__, callID);
+                    break;
+
+                case RIL_CALL_DIALING:  //MO call only
+                    ql_call_ubus->call_state.calls[0].state = E_QL_MCM_VOICE_CALL_STATE_DIALING;
+                    mbtk_call_log("%s, RIL_CALL_DIALING, call index=%d hold!!\n", __FUNCTION__, callID);
+                    break;
+                case RIL_CALL_OFFERING:
+                case RIL_CALL_DISCONNECTING:
+                default:
+                    printf("%s, state=%s ignored!!\n", __FUNCTION__, RIL_MessageMap[(int)rilCall->state]);
+                    ql_call_ubus->call_state.calls[0].state = E_QL_MCM_VOICE_CALL_STATE_END;
+                    break;
+            }
+            if(ql_call_ubus->_voice_call_common_state_handler && ql_call_ubus)
+            {
+                ql_call_ubus->_voice_call_common_state_handler(E_QL_MCM_VOICE_CALL_IND, &ql_call_ubus->call_state, sizeof(ql_mcm_voice_call_ind));
+            }
+        }
+        break;
+        case RIL_UNSOL_CALL_NO_CARRIER_EXT: /*"CC" 1511*/
+            mbtk_call_log("%s: id %d=RIL_UNSOL_CALL_NO_CARRIER_EXT (len=%d)\n",
+                    __FUNCTION__, rilid, datalen);
+            ql_call_ubus->call_state.calls[0].state = E_QL_MCM_VOICE_CALL_STATE_END;
+            if(ql_call_ubus->_voice_call_common_state_handler && ql_call_ubus)
+            {
+                ql_call_ubus->_voice_call_common_state_handler(E_QL_MCM_VOICE_CALL_IND, &ql_call_ubus->call_state, sizeof(ql_mcm_voice_call_ind));
+            }
+            break;
+
+        case RIL_UNSOL_CALL_RING: /*"CC" 1018*/
+            printf("%s: id %d=RIL_UNSOL_CALL_RING (len=%d), ignored!!\n",
+                    __FUNCTION__, rilid, datalen);
+            break;
+
+        case RIL_UNSOL_DISCONNECT_CALLID: /*"CC" 1538*/
+            callID = *(int *)data;
+            ql_call_ubus->call_state.calls[0].state = E_QL_MCM_VOICE_CALL_STATE_END;
+            mbtk_call_log("%s: id %d=RIL_UNSOL_DISCONNECT_CALLID (len=%d), call index=%d!\n",
+                        __FUNCTION__, rilid, datalen, *(int *)data);
+            break;
+		default:
+			break;
+	 }
+
+	 return ret;
+}
+static void ql_call_requset_cb(struct ubus_request *req, int type, struct blob_attr *msg)
+{
+    unsigned int requestid;
+    unsigned int rilerrno;
+    void *response = NULL;
+    int responselen;
+    int ret = 0;
+
+    ret = rilutil_parseResponse(msg, &requestid, &rilerrno, &response, &responselen);
+    if(ret)
+    {
+        fprintf(stderr, "parse blob error\n");
+        goto done;
+    }
+
+    if(rilerrno)
+    {
+        // RIL_REQUEST_RELEASE_CALL
+        fprintf(stderr, "unsolicited id %d, error code %d\n", requestid, rilerrno);
+        goto done;
+    }
+
+    //process response here
+
+done:
+    if(response)
+        rilutil_freeResponseData(requestid, response, responselen);
+
+    return;
+}
+
+int ql_call_subscriber_cb(struct ubus_context *ctx, struct ubus_object *obj,
+			    struct ubus_request_data *req, const char *method, struct blob_attr *msg)
+{
+	UNUSED(ctx);
+	UNUSED(obj);
+	UNUSED(req);
+	UNUSED(method);
+
+	unsigned int requestid = 0;
+	unsigned int rilerrno = 0;
+	void *response = NULL;
+	int responselen = 0;
+	int ret = 0;
+
+	ret = rilutil_parseResponse(msg, &requestid, &rilerrno, &response, &responselen);
+	if (ret)
+		goto end;
+
+	mbtk_call_log("call_subscriber_cb: rcv %d\n", requestid);
+
+    ql_call_handle_ril_ind(ctx, requestid, rilerrno, response, responselen);
+
+end:
+	if (response)
+		rilutil_freeResponseData(requestid,response,responselen);
+
+	return 0;
+}
+
+void ql_call_subscriber_remove_cb(struct ubus_context *ctx, struct ubus_subscriber *obj, uint32_t id)
+{
+	UNUSED(ctx);
+	UNUSED(obj);
+	UNUSED(id);
+	mbtk_call_log("ql_call_subscriber_remove_cb\n");
+}
+
+static void ql_call_register_ril(void* hdl)
+{
+    static struct ubus_request req;
+    struct ql_call_ubus_t *voice_call_ubus = (struct ql_call_ubus_t *)hdl;
+    int ret;
+
+    if(hdl == NULL || ql_call_ubus == NULL)
+    {
+        printf("ARG error or not inited.");
+        return -1;
+    }
+    pthread_detach(pthread_self());
+	ret = ubus_register_subscriber(voice_call_ubus->ctx, &voice_call_ubus->ril_ind_event);
+	if (ret) {
+		printf("call_daemon: Failed to add ecall_subscriber: %s\n", ubus_strerror(ret));
+        return ret;
+    }
+
+	voice_call_ubus->ril_ind_event.cb = ql_call_subscriber_cb;
+	voice_call_ubus->ril_ind_event.remove_cb = ql_call_subscriber_remove_cb;
+
+	//register for CC ind
+	if (ubus_lookup_id(voice_call_ubus->ctx, "ril.unsol.cc", &voice_call_ubus->ril_subscriber_id)) {
+		printf("call_daemon: Failed to look up ril.unsol.cc object\n");
+        return ret;
+	}
+
+	ubus_subscribe(voice_call_ubus->ctx, &voice_call_ubus->ril_ind_event, voice_call_ubus->ril_subscriber_id);
+	mbtk_call_log("call_daemon: subscribe ril.unsol.cc object ok\n");
+    mbtk_call_log("%s!\n", __FUNCTION__);
+    while(1)
+    {
+        uloop_run();
+        printf("%s uloop_run done!\n", __FUNCTION__);
+    }
+    pthread_exit(NULL);
+}
+/* Init voice module and return h_voice, this should be called before any other APIs */
+int QL_Voice_Call_Client_Init(voice_client_handle_type *ph_voice)
+{
+    int id;
+    // Set call handle.
+    //*ph_voice = 1;
+    if(ph_voice == NULL)
+    {
+        printf("ARG error or has inited.");
+        return -1;
+    }
+    ql_call_ubus = malloc(sizeof(struct ql_call_ubus_t));
+    if(NULL == ql_call_ubus)
+    {
+        printf("malloc memory error\n");
+    }
+    memset(ql_call_ubus, 0, sizeof(struct ql_call_ubus_t));
+    uloop_init();
+
+    ql_call_ubus->ctx = ubus_connect(NULL);
+    if(!ql_call_ubus->ctx)
+    {
+        printf("Failed to connect to ubus");
+        goto out;
+    }
+
+    ubus_add_uloop(ql_call_ubus->ctx);
+
+    if (ubus_lookup_id(ql_call_ubus->ctx, "ril", &ql_call_ubus->ril_request_id)) {
+    	fprintf(stderr, "%s, Failed to look up test object\n", __FUNCTION__);
+    	return -1;
+    }
+    ql_call_ubus->auto_answer = E_QL_MCM_VOICE_AUTO_ANSWER_DISABLE;
+    ql_call_ubus->call_state.calls[0].state = E_QL_MCM_VOICE_CALL_STATE_END;
+    pthread_create(&ql_call_ubus->call_status_pthread, NULL, (void *)ql_call_register_ril, (void *)ql_call_ubus);
+    *ph_voice = ql_call_ubus;
+
+    return 0;
+out:
+    //uloop_done();
+
+    return 0;
+}
+
+/* DeInit voice module and release resources, this should be called at last */
+int QL_Voice_Call_Client_Deinit(voice_client_handle_type h_voice)
+{
+    int ret;
+    struct ql_call_ubus_t *voice_call_ubus = (struct ql_call_ubus_t *)h_voice;
+    // Free handle.
+
+    if(h_voice == NULL || ql_call_ubus == NULL)
+    {
+        LOGE("ARG error or not inited.");
+        printf("ARG error or not inited.");
+        return -1;
+    }
+    ret = pthread_cancel(voice_call_ubus->call_status_pthread);
+    mbtk_call_log("kill pthread : %d \n", ret);
+    pthread_join(voice_call_ubus->call_status_pthread, NULL);
+    do{
+        ret = pthread_kill(voice_call_ubus->call_status_pthread, 0);
+        mbtk_call_log("kill pthread: %d \n", ret);
+        if(ret == ESRCH)
+            printf("The specified thread does not exist or has terminated\n");
+        else if(ret == EINVAL)
+            printf("Useless signal\n");
+        else
+            mbtk_call_log("The thread exists\n");
+        usleep(100000);
+    }while(0 == ret);
+    free(h_voice);
+    ql_call_ubus = NULL;
+    uloop_done();
+    ubus_free(voice_call_ubus->ctx);
+    return 0;
+}
+
+/* Add callback function, if any call state changed, handlerPtr will be called to notify App */
+int QL_Voice_Call_AddStateHandler(voice_client_handle_type h_voice,
+                                  QL_VoiceCall_StateHandlerFunc_t   handlerPtr,
+                                  void*                             contextPtr)
+{
+    static struct ubus_request req;
+    struct ql_call_ubus_t *voice_call_ubus = (struct ql_call_ubus_t *)h_voice;
+    int ret;
+
+    if(h_voice == NULL || ql_call_ubus == NULL)
+    {
+        printf("ARG error or not inited.");
+        return -1;
+    }
+    ret = pthread_kill(voice_call_ubus->call_status_pthread, 0);
+    mbtk_call_log("kill pthread: %d \n", ret);
+    if(ret == ESRCH)
+        mbtk_call_log("The specified thread does not exist or has terminated\n");
+    else if(ret == EINVAL)
+        printf("Useless signal\n");
+    else
+        mbtk_call_log("The thread exists\n");
+    if(voice_call_ubus->ril_subscriber_id)
+    {
+        voice_call_ubus->_voice_call_state_handler = handlerPtr;
+    }
+    else
+    {
+        printf("%s error!!\n", __func__);
+        return -1;
+    }
+
+    return 0;
+}
+
+/* Remove callback function, won't receive any notify anymore */
+int QL_Voice_Call_RemoveStateHandler(voice_client_handle_type        h_voice)
+{
+	struct ql_call_ubus_t *voice_call_ubus = (struct ql_call_ubus_t *)h_voice;
+
+    if(h_voice == NULL || ql_call_ubus == NULL)
+    {
+        LOGE("ARG error or not inited.");
+        return -1;
+    }
+    voice_call_ubus->_voice_call_state_handler = NULL;
+
+    return 0;
+}
+
+
+/* Add callback function, if any call state changed, handlerPtr will be called to notify App */
+int QL_Voice_Call_AddCommonStateHandler(voice_client_handle_type h_voice,
+                                  QL_VoiceCall_CommonStateHandlerFunc_t   handlerPtr)
+{
+    static struct ubus_request req;
+    struct ql_call_ubus_t *voice_call_ubus = (struct ql_call_ubus_t *)h_voice;
+    int ret;
+
+    if(h_voice == NULL || ql_call_ubus == NULL)
+    {
+        LOGE("ARG error or not inited.");
+        return -1;
+    }
+    ret = pthread_kill(voice_call_ubus->call_status_pthread, 0);
+    mbtk_call_log("kill pthread: %d \n", ret);
+    if(ret == ESRCH)
+        mbtk_call_log("The specified thread does not exist or has terminated\n");
+    else if(ret == EINVAL)
+        printf("Useless signal\n");
+    else
+        mbtk_call_log("The thread exists\n");
+    if(voice_call_ubus->ril_subscriber_id)
+    {
+        voice_call_ubus->_voice_call_common_state_handler = handlerPtr;
+    }
+    else
+    {
+        printf("%s error!!\n", __func__);
+        return -1;
+    }
+
+
+    return 0;
+}
+
+/* Remove callback function, won't receive any notify anymore */
+int QL_Voice_Call_RemoveCommonStateHandler(voice_client_handle_type          h_voice)
+{
+	struct ql_call_ubus_t *voice_call_ubus = (struct ql_call_ubus_t *)h_voice;
+
+    if(h_voice == NULL || ql_call_ubus == NULL)
+    {
+        LOGE("ARG error or not inited.");
+        return -1;
+    }
+    voice_call_ubus->_voice_call_common_state_handler = NULL;
+
+    return 0;
+}
+
+
+/* Start call and return call_id, this can be used in the later */
+int QL_Voice_Call_Start(voice_client_handle_type    h_voice,
+                        E_QL_VCALL_ID_T             simId,
+                        char*                       phone_number,   ///< [IN] Destination identifier for the voice
+                        int                         *call_id)      ///< [OUT] call id
+{
+    static struct ubus_request req;
+    struct ql_call_ubus_t *voice_call_ubus = (struct ql_call_ubus_t *)h_voice;
+    static struct blob_buf b;
+    int id, ret;
+	RIL_Dial dial_data;
+
+    if(h_voice == NULL || ql_call_ubus == NULL)
+    {
+        printf("ARG error or not inited.");
+        return -1;
+    }
+    if(voice_call_ubus->call_state.calls[0].state == E_QL_MCM_VOICE_CALL_STATE_ACTIVE ||
+       voice_call_ubus->call_state.calls[0].state == E_QL_MCM_VOICE_CALL_STATE_INCOMING ||
+       voice_call_ubus->call_state.calls[0].state == E_QL_MCM_VOICE_CALL_STATE_ALERTING)
+    {
+        printf("A call already exists, Voice Call incoming or active!!\n");
+        return -1;
+    }
+    memset(&dial_data, 0, sizeof(RIL_Dial));
+    dial_data.address = phone_number;
+    printf("call number %s\n", dial_data.address);
+    if (ubus_lookup_id(ql_call_ubus->ctx, "ril", &ql_call_ubus->ril_request_id)) {
+    	fprintf(stderr, "%s, Failed to look up test object\n", __FUNCTION__);
+    	return -1;
+    }
+    rilutil_makeRequestBlob(&b, RIL_REQUEST_DIAL, &dial_data, 0);
+    ret = ubus_invoke(voice_call_ubus->ctx, voice_call_ubus->ril_request_id, "ril_request", b.head, ql_call_requset_cb, 0,0);
+    if(ret != 0)
+    {
+        printf("sim_get_imsi,ubus_invoke Failed %s\n", ubus_strerror(ret));
+        return E_QL_ERROR_GENERIC;
+    }
+
+    return 0;
+}
+
+/* End call of call_id, which returned by QL_Voice_Call_Start or callback func register via QL_Voice_Call_AddStateHandler */
+int QL_Voice_Call_End(voice_client_handle_type    h_voice,
+                      int                         call_id)        ///< [IN] call id, return by QL_Voice_Start
+{
+    static struct ubus_request req;
+    static struct blob_buf b;
+    int ret;
+    struct ql_call_ubus_t *voice_call_ubus = (struct ql_call_ubus_t *)h_voice;
+
+    if(h_voice == NULL || ql_call_ubus == NULL)
+    {
+        printf("ARG error or not inited.");
+        return -1;
+    }
+    mbtk_call_log("Voice Call State:%s, %d\n", voice_call_ubus->call_state.calls[0].number, voice_call_ubus->call_state.calls[0].state);
+    if(voice_call_ubus->call_state.calls[0].state != E_QL_MCM_VOICE_CALL_STATE_ACTIVE &&
+       voice_call_ubus->call_state.calls[0].state != E_QL_MCM_VOICE_CALL_STATE_INCOMING &&
+       voice_call_ubus->call_state.calls[0].state != E_QL_MCM_VOICE_CALL_STATE_ALERTING)
+    {
+        printf("No Voice Call incoming or active!!\n");
+        return -1;
+    }
+    //use rilutil's API, just a example
+    rilutil_makeRequestBlob(&b, RIL_REQUEST_RELEASE_CALL, NULL, 0);
+    ret = ubus_invoke(voice_call_ubus->ctx, voice_call_ubus->ril_request_id, "ril_request", b.head, ql_call_requset_cb, 0,0);
+    if(ret != 0)
+    {
+        printf("sim_get_imsi,ubus_invoke Failed %s", ubus_strerror(ret));
+        return E_QL_ERROR_GENERIC;
+    }
+    return 0;
+}
+
+/* Answer the call of call_id, which returned by callback func register via QL_Voice_Call_AddStateHandler */
+int QL_Voice_Call_Answer(voice_client_handle_type    h_voice,
+                         int                         call_id )
+{
+    static struct ubus_request req;
+    static struct blob_buf b;
+    struct ql_call_ubus_t *voice_call_ubus = (struct ql_call_ubus_t *)h_voice;
+    int ret;
+
+    if(h_voice == NULL || ql_call_ubus == NULL)
+    {
+        printf("ARG error or not inited.");
+        return -1;
+    }
+    rilutil_makeRequestBlob(&b, RIL_REQUEST_ANSWER, NULL, 0);
+    ret = ubus_invoke(voice_call_ubus->ctx, voice_call_ubus->ril_request_id, "ril_request", b.head, ql_call_requset_cb, 0,0);
+    if(ret != 0)
+    {
+        printf("ql call, ubus_invoke Failed %s", ubus_strerror(ret));
+        return E_QL_ERROR_GENERIC;
+    }
+    return 0;
+}
+
+int QL_Voice_Call_Hold( voice_client_handle_type    h_voice)
+{
+    static struct ubus_request req;
+    struct ql_call_ubus_t *voice_call_ubus = (struct ql_call_ubus_t *)h_voice;
+    static struct blob_buf b;
+    int ret;
+
+    if(h_voice == NULL || ql_call_ubus == NULL)
+    {
+        printf("ARG error or not inited.");
+        return -1;
+    }
+    rilutil_makeRequestBlob(&b, RIL_REQUEST_HANGUP, NULL, 0);
+    ret = ubus_invoke(voice_call_ubus->ctx, voice_call_ubus->ril_request_id, "ril_request", b.head, ql_call_requset_cb, 0,0);
+    if(ret != 0)
+    {
+        printf("ql call, ubus_invoke Failed %s", ubus_strerror(ret));
+        return E_QL_ERROR_GENERIC;
+    }
+    return 0;
+}
+
+int QL_Voice_Call_UnHold( voice_client_handle_type h_voice)
+{
+
+    return 0;
+}
+
+int QL_Voice_Call_Conference( voice_client_handle_type h_voice)
+{
+    static struct ubus_request req;
+    struct ql_call_ubus_t *voice_call_ubus = (struct ql_call_ubus_t *)h_voice;
+    static struct blob_buf b;
+    int ret;
+
+    if(h_voice == NULL || ql_call_ubus == NULL)
+    {
+        printf("ARG error or not inited.");
+        return -1;
+    }
+    rilutil_makeRequestBlob(&b, RIL_REQUEST_CONFERENCE, NULL, 0);
+    ret = ubus_invoke(voice_call_ubus->ctx, voice_call_ubus->ril_request_id, "ril_request", b.head, ql_call_requset_cb, 0,0);
+    if(ret != 0)
+    {
+        printf("ql call, ubus_invoke Failed %s", ubus_strerror(ret));
+        return E_QL_ERROR_GENERIC;
+    }
+    return 0;
+}
+
+int QL_Voice_Call_EndConference( voice_client_handle_type   h_voice)
+{
+
+    return 0;
+}
+
+int QL_Voice_Call_Ecall(voice_client_handle_type    h_voice,
+                        E_QL_VCALL_ID_T             simId,
+                        char*                       phone_number,
+                        ql_mcm_ecall_info           ecall_info,
+                        int                         *call_id)
+{
+// RIL_REQUEST_SET_CECALL
+// RIL_REQUEST_GET_CECALL
+//         RIL_REQUEST_SET_ECALLONLY
+//         RIL_REQUEST_GET_ECALLONLY
+//         RIL_REQUEST_SET_ECALLREG
+    static struct ubus_request req;
+    struct ql_call_ubus_t *voice_call_ubus = (struct ql_call_ubus_t *)h_voice;
+    static struct blob_buf b;
+    int ret;
+
+    if(h_voice == NULL || ql_call_ubus == NULL)
+    {
+        printf("ARG error or not inited.");
+        return -1;
+    }
+    //use rilutil's API, just a example
+    rilutil_makeRequestBlob(&b, RIL_REQUEST_CONFERENCE, NULL, 0);
+    ret = ubus_invoke(voice_call_ubus->ctx, voice_call_ubus->ril_request_id, "ril_request", b.head, ql_call_requset_cb, 0,0);
+    if(ret != 0)
+    {
+        printf("ql call, ubus_invoke Failed %s", ubus_strerror(ret));
+        return E_QL_ERROR_GENERIC;
+    }
+    return 0;
+}
+
+
+int QL_Voice_Call_SetAutoAnswer(voice_client_handle_type        h_voice,
+                                E_QL_MCM_VOICE_AUTO_ANSWER_T    eAnswerType,
+                                uint32_t                        uAnswerTime)
+{
+    struct ql_call_ubus_t *voice_call_ubus = (struct ql_call_ubus_t *)h_voice;
+
+    if(h_voice == NULL || ql_call_ubus == NULL)
+    {
+        printf("ARG error or not inited.");
+        return -1;
+    }
+    voice_call_ubus->auto_answer = eAnswerType;
+    voice_call_ubus->answer_time = uAnswerTime;
+
+    return 0;
+}
+
+int QL_Voice_Call_Ecall_HangUp(voice_client_handle_type h_voice)
+{
+    return 0;
+}
+
+int QL_Voice_Call_Ecall_UpdateMsd(voice_client_handle_type    h_voice,const char *msd,uint32_t   msd_len)
+{
+    return 0;
+}
+
+//Ecall Push caommand
+int QL_Voice_Call_Ecall_MsdPush(voice_client_handle_type h_voice,
+                                        E_QL_MCM_ECALL_STATE_T *ecall_state)
+{
+    return 0;
+}
+
+//Get Ecall config info
+int QL_Voice_Call_Ecall_GetConfigInfo(voice_client_handle_type h_voice,
+                                        ql_mcm_ecall_config_info *ecall_config)
+{
+//         RIL_REQUEST_SET_ECALLCFG
+//         RIL_REQUEST_GET_ECALLCFG
+    return 0;
+}
+
+int QL_Voice_Call_Ecall_SetConfigInfo(voice_client_handle_type h_voice,
+                                        E_QL_MCM_ECALL_CONFIG_T ecall_config_type,
+                                        uint8_t value)
+{
+    return 0;
+}
+
+//Cancel dial
+int QL_Voice_Call_CancelDial( voice_client_handle_type   h_voice)
+{
+    static struct ubus_request req;
+    static struct blob_buf b;
+    int ret;
+    struct ql_call_ubus_t *voice_call_ubus = (struct ql_call_ubus_t *)h_voice;
+
+    if(h_voice == NULL || ql_call_ubus == NULL)
+    {
+        printf("ARG error or not inited.");
+        return -1;
+    }
+    //use rilutil's API, just a example
+    rilutil_makeRequestBlob(&b, RIL_REQUEST_RELEASE_CALL, NULL, 0);
+    ret = ubus_invoke(voice_call_ubus->ctx, voice_call_ubus->ril_request_id, "ril_request", b.head, ql_call_requset_cb, 0,0);
+    if(ret != 0)
+    {
+        printf("sim_get_imsi,ubus_invoke Failed %s", ubus_strerror(ret));
+        return E_QL_ERROR_GENERIC;
+    }
+    return 0;
+}
+
+//VTS API
+int QL_Voice_Call_Dtmf(voice_client_handle_type h_voice, uint8_t digit, int call_id)
+{
+    static struct ubus_request req;
+    struct ql_call_ubus_t *voice_call_ubus = (struct ql_call_ubus_t *)h_voice;
+    static struct blob_buf b;
+    int ret;
+    char code = digit;
+
+    if(h_voice == NULL || ql_call_ubus == NULL)
+    {
+        printf("ARG error or not inited.");
+        return -1;
+    }
+    rilutil_makeRequestBlob(&b, RIL_REQUEST_DTMF, &code, 0);
+    ret = ubus_invoke(voice_call_ubus->ctx, voice_call_ubus->ril_request_id, "ril_request", b.head, ql_call_requset_cb, 0,0);
+    if(ret != 0)
+    {
+        printf("ql call, ubus_invoke Failed %s", ubus_strerror(ret));
+        return E_QL_ERROR_GENERIC;
+    }
+    return 0;
+}
+
+int QL_Voice_Call_GetCallStatus
+(
+    int                         h_voice,
+    int                         call_id, // If call_id<0, means to get all calls state, or get specified call_id info
+    ql_mcm_voice_calls_state_t  *pt_callstate
+)
+{
+    struct ql_call_ubus_t *voice_call_ubus = (struct ql_call_ubus_t *)h_voice;
+
+    if(h_voice == NULL || ql_call_ubus == NULL)
+    {
+        printf("ARG error or not inited.");
+        return -1;
+    }
+    memcpy((void *)pt_callstate, &voice_call_ubus->call_state, sizeof(ql_mcm_voice_calls_state_t));
+    return 0;
+}
+
+//Set forwarding
+int QL_Voice_Call_SetForwarding
+(
+    int                             h_voice,
+    E_QL_MCM_VOICE_CALL_SERVICE_T   service,
+    E_QL_MCM_VOICE_CALL_FORWARDING_REASON_T  reason,
+    char *number
+)
+{
+
+    return 0;
+}
+
+//Get forwarding status
+int QL_Voice_Call_GetForwardingStatus(
+        int                             h_voice,
+        E_QL_MCM_VOICE_CALL_FORWARDING_REASON_T  reason,
+        ql_mcm_voice_call_forwarding_status_list_t *pt_status)
+{
+
+    return 0;
+}
+
+
+//Set voice call waiting
+int QL_Voice_Call_SetWaiting
+(
+    int                                 h_voice,
+    ql_mcm_voice_call_waiting_service_t e_service
+)
+{
+// RIL_REQUEST_HANGUP_FOREGROUND_RESUME_BACKGROUND
+    return 0;
+}
+
+//Get voice call waiting status
+int QL_Voice_Call_GetWaitingStatus
+(
+    int                                 h_voice,
+    ql_mcm_voice_call_waiting_service_t *pe_service
+)
+{
+
+    return 0;
+}