| /****************************************************************************** |
| *(C) Copyright 2014 Marvell International Ltd. |
| * All Rights Reserved |
| ******************************************************************************/ |
| /* ------------------------------------------------------------------------------------------------------------------- |
| * |
| * Filename: audio_if_ubus.c |
| * |
| * Authors: tzahi stern |
| * |
| * Description: This file handle all interface with UBUS for audio_if such as: |
| * 1. open ubus server for audio_if |
| * 2. register as ubus clent for RIL indication |
| * 3. create a thread for handling requests from audioHAL toward ubus |
| * |
| * HISTORY: |
| * |
| * |
| * Notes: |
| * |
| ******************************************************************************/ |
| |
| /****************************************************************************** |
| * Include files |
| ******************************************************************************/ |
| #include "audio_if_types.h" |
| #include "audio_if_ubus.h" |
| #include "audio_if_parameter.h" |
| #include "audio_if.h" |
| #include "audio_if_api.h" |
| #include "telephony/ril.h" |
| #include "audio_if_audio_hw_mrvl.h" |
| #include "audio_pa.h" |
| #include "rilutil.h" |
| #include <signal.h> |
| #include <time.h> |
| |
| /****************************************************************************** |
| * Macros / Defines |
| ******************************************************************************/ |
| #define RIL_UBUS_ID "ril" |
| #define RIL_UBUS_REQ "ril_request" |
| /*#define RIL_EVENT_PREFIX "ril.unsol."*/ |
| |
| #define AUDIOIFREQID "reqid" |
| #define AUDIOIFRESPID "audioifid" |
| #define AUDIOIFRESPERRNO "resperrno" |
| #define AUDIO_IF_CALLMAX 9 //Max call index is 8 |
| |
| 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 */ |
| }; |
| |
| #define AUDIO_IF_UBUS_SUBSCRIBE_EVENT(x,s) \ |
| { \ |
| int local_ret; \ |
| uint32_t local_id; \ |
| if (ubus_lookup_id(x.ctx, s, &local_id)) { \ |
| AUDIO_IF_LOGE("ubus subscribe FAILED to lookup object: %s", s); \ |
| } else { \ |
| local_ret = ubus_subscribe(x.ctx, &x.ind_event, local_id); \ |
| AUDIO_IF_LOGD("ubus subscribe Watching object %s %08x: %s", s, \ |
| local_id, ubus_strerror(local_ret)); \ |
| } \ |
| }/*endM*/ |
| |
| #define AUDIO_IF_UBUS_UNSUBSCRIBE_EVENT(x,s) \ |
| { \ |
| uint32_t local_id; \ |
| if (!ubus_lookup_id(x.ctx, s, &local_id)) \ |
| ubus_subscribe(x.ctx, &x.ind_event, local_id); \ |
| }/*endM*/ |
| |
| /****************************************************************************** |
| * enum |
| ******************************************************************************/ |
| |
| enum { |
| AUDIO_IF_REQID, |
| AUDIO_IF_DATA, |
| _AUDIO_IF_MAX |
| }; |
| /****************************************************************************** |
| * Prototypes |
| ******************************************************************************/ |
| /**************** ubus utility API ************/ |
| static void AudioIf_uBussubscribeCb(struct ubus_context *ctx, struct ubus_object *obj); |
| static int AudioIf_uBusInd_RIL(struct ubus_context *ctx, struct ubus_object *obj, |
| struct ubus_request_data *req, const char *method, |
| struct blob_attr *msg); |
| extern void AudioIf_ReadFromDevice(int fd); |
| |
| /****************************************************************************** |
| * Globals |
| ******************************************************************************/ |
| extern audio_hw_device_t *ahw_dev_ubus; |
| extern struct mrvl_audio_device *mrvl_ahw_dev_ubus; |
| |
| static struct uloop_fd audio_if_fd; |
| extern audioIfReqDb_t audioIfReqDb; |
| extern audioIfUbusDb_t audioIfUbusDb; |
| extern AUDIO_IF_DATABASE audioIfDb; |
| extern pthread_mutex_t req_data_mutex; |
| extern pthread_mutex_t AudioIf_mutex; |
| |
| /*****************************************************\ |
| * Call State |
| * 0: idle |
| * 1: active |
| * 2: hold |
| * 3: alerting |
| \*****************************************************/ |
| int AUDIO_IF_CallIndexState[AUDIO_IF_CALLMAX] = {0}; |
| |
| /**************** supported policies ************/ |
| const struct blobmsg_policy int_policy[PARAM_INT_POLICY_MAX] ={ |
| [PARAM_INT_POLICY_0] = { |
| .name = "param0", |
| .type = BLOBMSG_TYPE_INT32, |
| }, |
| [PARAM_INT_POLICY_1] = { |
| .name = "param1", |
| .type = BLOBMSG_TYPE_INT32, |
| }, |
| [PARAM_INT_POLICY_2] = { |
| .name = "param2", |
| .type = BLOBMSG_TYPE_INT32, |
| }, |
| [PARAM_INT_POLICY_3] = { |
| .name = "param3", |
| .type = BLOBMSG_TYPE_INT32, |
| }, |
| }; |
| |
| const struct blobmsg_policy ecall_data_set_policy[] ={ |
| [PARAM_ECALL_DATA_SET_POLICY_0] = { |
| .name = "length", /* op+param1+data total length */ |
| .type = BLOBMSG_TYPE_INT32, |
| }, |
| [PARAM_ECALL_DATA_SET_POLICY_1] = { |
| .name = "op", /* Operation to perform */ |
| .type = BLOBMSG_TYPE_INT32, |
| }, |
| [PARAM_ECALL_DATA_SET_POLICY_2] = { |
| .name = "param1", /* The meaning depends on the op parameter. */ |
| .type = BLOBMSG_TYPE_INT32, |
| }, |
| [PARAM_ECALL_DATA_SET_POLICY_3] = { |
| .name = "data", /* 140 bytes of data, corresponds to the MSD data to be sent */ |
| .type = BLOBMSG_TYPE_STRING, |
| }, |
| }; |
| |
| const struct blobmsg_policy ecall_data_get_policy[] ={ |
| [PARAM_ECALL_DATA_GET_POLICY_0] = { |
| .name = "length", /* op+param1 total length */ |
| .type = BLOBMSG_TYPE_INT32, |
| }, |
| [PARAM_ECALL_DATA_GET_POLICY_1] = { |
| .name = "op", /* Operation to perform */ |
| .type = BLOBMSG_TYPE_INT32, |
| }, |
| [PARAM_ECALL_DATA_GET_POLICY_2] = { |
| .name = "param1", /* The meaning depends on the op parameter. */ |
| .type = BLOBMSG_TYPE_INT32, |
| }, |
| }; |
| |
| const struct blobmsg_policy ecall_data_get_reply_policy[] ={ |
| [PARAM_ECALL_DATA_GET_REPLY_POLICY_0] = { |
| .name = "op", /* Operation to perform */ |
| .type = BLOBMSG_TYPE_INT32, |
| }, |
| [PARAM_ECALL_DATA_GET_REPLY_POLICY_1] = { |
| .name = "param1", /* The meaning depends on the op parameter. */ |
| .type = BLOBMSG_TYPE_INT32, |
| }, |
| [PARAM_ECALL_DATA_GET_REPLY_POLICY_2] = { |
| .name = "value1", /* Contains a returned eIM value according to eCall specifications. */ |
| .type = BLOBMSG_TYPE_INT32, |
| }, |
| [PARAM_ECALL_DATA_GET_REPLY_POLICY_3] = { |
| .name = "value2", /* Contains an optional returned eIM value according to eCall specifications. */ |
| .type = BLOBMSG_TYPE_INT32, |
| }, |
| }; |
| |
| const struct blobmsg_policy ecall_voice_set_policy[] ={ |
| [PARAM_ECALL_VOICE_SET_POLICY_0] = { |
| .name = "cmd_id", /* Type of operation */ |
| .type = BLOBMSG_TYPE_INT32, |
| }, |
| [PARAM_ECALL_VOICE_SET_POLICY_1] = { |
| .name = "res_id", /* Voice resource identifier */ |
| .type = BLOBMSG_TYPE_INT32, |
| }, |
| [PARAM_ECALL_VOICE_SET_POLICY_2] = { |
| .name = "param2", /* The meaning depends on the res_id parameter. */ |
| .type = BLOBMSG_TYPE_INT32, |
| }, |
| }; |
| |
| const struct blobmsg_policy ecall_voice_get_policy[] ={ |
| [PARAM_ECALL_VOICE_GET_POLICY_0] = { |
| .name = "cmd_id", /* Type of operation */ |
| .type = BLOBMSG_TYPE_INT32, |
| }, |
| [PARAM_ECALL_VOICE_GET_POLICY_1] = { |
| .name = "res_id", /* Voice resource identifier */ |
| .type = BLOBMSG_TYPE_INT32, |
| }, |
| }; |
| |
| const struct blobmsg_policy ecall_voice_get_reply_policy[] ={ |
| [PARAM_ECALL_VOICE_GET_REPLY_POLICY_0] = { |
| .name = "cmd_id", /* Type of operation */ |
| .type = BLOBMSG_TYPE_INT32, |
| }, |
| [PARAM_ECALL_VOICE_GET_REPLY_POLICY_1] = { |
| .name = "res_id", /* Voice resource identifier */ |
| .type = BLOBMSG_TYPE_INT32, |
| }, |
| [PARAM_ECALL_VOICE_GET_REPLY_POLICY_2] = { |
| .name = "param2", /* The meaning depends on the res_id parameter. */ |
| .type = BLOBMSG_TYPE_INT32, |
| }, |
| }; |
| |
| |
| const struct blobmsg_policy vcm_play_rec_policy[] ={ |
| [PARAM_VCM_PLAY_REC_POLICY_0] = { |
| .name = "path", /* Up to 256 char path */ |
| .type = BLOBMSG_TYPE_STRING, |
| }, |
| }; |
| |
| const struct blobmsg_policy cp_loopback_enable_policy[] ={ |
| [PARAM_INT_POLICY_0] = { |
| .name = "param0", /* Device. 0 - earpiece, 1 - speaker, 2 - headset */ |
| .type = BLOBMSG_TYPE_INT32, |
| }, |
| [PARAM_INT_POLICY_1] = { |
| .name = "mode", /* Mode. 1 - loopback pcm, 2 - loopback packet/vocoder loop, * |
| * 3 - pcm loop without enhancement, 4 - vocoder loop without enhancement */ |
| .type = BLOBMSG_TYPE_INT32, |
| }, |
| }; |
| |
| const struct blobmsg_policy vcm_config_policy[] ={ /*TODO add difference configs for rec/playback */ |
| [PARAM_VCM_CONFIG_POLICY_0] = { |
| .name = "direction", /* Chosen direction to configure. 0 - Output, 1 - Input */ |
| .type = BLOBMSG_TYPE_INT32, |
| }, |
| [PARAM_VCM_CONFIG_POLICY_1] = { |
| .name = "type", /* Type of data package. 0 - PCM, 1 - PCM_WB */ |
| .type = BLOBMSG_TYPE_INT32, |
| }, |
| [PARAM_VCM_CONFIG_POLICY_2] = { |
| .name = "srcdst", /* Location to rec/play from/to. 0 - None, 1 - Near end, * |
| * 2 - Far end, 3 - Both ends */ |
| .type = BLOBMSG_TYPE_INT32, |
| }, |
| [PARAM_VCM_CONFIG_POLICY_3] = { |
| .name = "priority", /* Combine with call option. 0 - Do not combine (override), 1 - Combine * |
| * Not used in vcm recording */ |
| .type = BLOBMSG_TYPE_INT32, |
| }, |
| [PARAM_VCM_CONFIG_POLICY_4] = { |
| .name = "dest", /* Which side of the dsp to connect. 0 - Near codec, 1 - Near vocoder */ |
| .type = BLOBMSG_TYPE_INT32, |
| }, |
| }; |
| |
| |
| const struct blobmsg_policy switch_pcm_policy[] ={ |
| [PARAM_INT_POLICY_0] = { |
| .name = "param0", |
| .type = BLOBMSG_TYPE_INT32, |
| }, |
| }; |
| |
| const struct blobmsg_policy config_pcm_policy[] ={ |
| [PARAM_INT_POLICY_0] = { |
| .name = "role", |
| .type = BLOBMSG_TYPE_INT32, |
| }, |
| [PARAM_INT_POLICY_1] = { |
| .name = "rate", |
| .type = BLOBMSG_TYPE_INT32, |
| }, |
| [PARAM_INT_POLICY_2] = { |
| .name = "bitclk", |
| .type = BLOBMSG_TYPE_INT32, |
| }, |
| [PARAM_INT_POLICY_3] = { |
| .name = "2slots", |
| .type = BLOBMSG_TYPE_INT32, |
| }, |
| [PARAM_INT_POLICY_4] = { |
| .name = "controller", |
| .type = BLOBMSG_TYPE_INT32, |
| }, |
| }; |
| |
| const struct blobmsg_policy config_dspgain_policy[] ={ |
| [PARAM_INT_POLICY_0] = { |
| .name = "type", |
| .type = BLOBMSG_TYPE_INT32, |
| }, |
| [PARAM_INT_POLICY_1] = { |
| .name = "gain", |
| .type = BLOBMSG_TYPE_INT32, |
| }, |
| }; |
| |
| const struct blobmsg_policy config_pcmexpert_policy[] ={ |
| [PARAM_PCMEXPERT_CONFIG_POLICY_0] = { |
| .name = "frame_format", |
| .type = BLOBMSG_TYPE_INT32, |
| }, |
| [PARAM_PCMEXPERT_CONFIG_POLICY_1] = { |
| .name = "invert_frame", |
| .type = BLOBMSG_TYPE_INT32, |
| }, |
| [PARAM_PCMEXPERT_CONFIG_POLICY_2] = { |
| .name = "frame_polarity", |
| .type = BLOBMSG_TYPE_INT32, |
| }, |
| [PARAM_PCMEXPERT_CONFIG_POLICY_3] = { |
| .name = "bitclk_polarity", |
| .type = BLOBMSG_TYPE_INT32, |
| }, |
| [PARAM_PCMEXPERT_CONFIG_POLICY_4] = { |
| .name = "fsyc_shift", |
| .type = BLOBMSG_TYPE_INT32, |
| }, |
| }; |
| |
| const struct blobmsg_policy vcm_dtmfcontrol_policy[] ={ |
| [PARAM_PCMEXPERT_CONFIG_POLICY_0] = { |
| .name = "on", |
| .type = BLOBMSG_TYPE_INT32, |
| }, |
| [PARAM_PCMEXPERT_CONFIG_POLICY_1] = { |
| .name = "tone1_index", |
| .type = BLOBMSG_TYPE_INT32, |
| }, |
| [PARAM_PCMEXPERT_CONFIG_POLICY_2] = { |
| .name = "tone2_index", |
| .type = BLOBMSG_TYPE_INT32, |
| }, |
| }; |
| |
| const struct blobmsg_policy config_pa_policy[] ={ |
| [PARAM_PCMEXPERT_CONFIG_POLICY_0] = { |
| .name = "on", |
| .type = BLOBMSG_TYPE_INT32, |
| }, |
| [PARAM_PCMEXPERT_CONFIG_POLICY_1] = { |
| .name = "gpio", |
| .type = BLOBMSG_TYPE_INT32, |
| }, |
| [PARAM_PCMEXPERT_CONFIG_POLICY_2] = { |
| .name = "delay_start", |
| .type = BLOBMSG_TYPE_INT32, |
| }, |
| [PARAM_PCMEXPERT_CONFIG_POLICY_3] = { |
| .name = "delay_stop", |
| .type = BLOBMSG_TYPE_INT32, |
| }, |
| }; |
| |
| #ifdef TARGET_mmp_asr1901_KSTR901 |
| const struct blobmsg_policy adsp_set_policy[] ={ |
| [PARAM_ADSP_SET_POLICY_0] = { |
| .name = "cmd", /* Up to 256 char*/ |
| .type = BLOBMSG_TYPE_STRING, |
| }, |
| }; |
| #endif |
| |
| /**************** supported methods ************/ |
| static const struct ubus_method audio_if_methods[] = { |
| UBUS_METHOD(AUDIO_IF_UBUS_AUDIO_MODE_SET, audio_if_audio_mode_set, int_policy), |
| UBUS_METHOD(AUDIO_IF_UBUS_AUDIO_MODE_STATUS, audio_if_audio_mode_status, int_policy), |
| UBUS_METHOD(AUDIO_IF_UBUS_AUDIO_DEVICE_SET, audio_if_audio_device_set, int_policy), |
| UBUS_METHOD(AUDIO_IF_UBUS_AUDIO_DEVICE_STATUS, audio_if_audio_device_status, int_policy), |
| UBUS_METHOD(AUDIO_IF_UBUS_TTY_SET, audio_if_tty_set, int_policy), |
| UBUS_METHOD(AUDIO_IF_UBUS_VOLUME_SET, audio_if_volume_set, int_policy), |
| UBUS_METHOD(AUDIO_IF_UBUS_VOLUME_STATUS, audio_if_volume_status, int_policy), |
| UBUS_METHOD(AUDIO_IF_UBUS_MUTE_SET, audio_if_mute_set, int_policy), |
| UBUS_METHOD(AUDIO_IF_UBUS_MUTE_STATUS, audio_if_mute_status, int_policy), |
| UBUS_METHOD(AUDIO_IF_UBUS_ECALL_DATA_SET, audio_if_ecall_data_set, ecall_data_set_policy), |
| UBUS_METHOD(AUDIO_IF_UBUS_ECALL_DATA_STATUS, audio_if_ecall_data_status, ecall_data_get_policy), |
| UBUS_METHOD(AUDIO_IF_UBUS_ECALL_VOICE_SET, audio_if_ecall_voice_set, ecall_voice_set_policy ), |
| UBUS_METHOD(AUDIO_IF_UBUS_ECALL_VOICE_STATUS, audio_if_ecall_voice_status, ecall_voice_get_policy), |
| UBUS_METHOD(AUDIO_IF_UBUS_SWITCH_PCM, audio_if_switch_pcm, switch_pcm_policy), |
| UBUS_METHOD(AUDIO_IF_UBUS_VCM_REC_START, audio_if_vcm_rec_start, vcm_play_rec_policy), |
| UBUS_METHOD_NOARG(AUDIO_IF_UBUS_VCM_REC_STOP, audio_if_vcm_rec_stop), |
| UBUS_METHOD(AUDIO_IF_UBUS_VCM_PLAY_START, audio_if_vcm_play_start, vcm_play_rec_policy), |
| UBUS_METHOD_NOARG(AUDIO_IF_UBUS_VCM_PLAY_STOP, audio_if_vcm_play_stop), |
| UBUS_METHOD(AUDIO_IF_UBUS_CP_LOOPBACK_ENABLE, audio_if_cp_loopback_enable, cp_loopback_enable_policy), |
| UBUS_METHOD_NOARG(AUDIO_IF_UBUS_CP_LOOPBACK_DISABLE, audio_if_cp_loopback_disable), |
| UBUS_METHOD(AUDIO_IF_UBUS_VCM_CONFIG, audio_if_vcm_configure, vcm_config_policy), |
| UBUS_METHOD(AUDIO_IF_UBUS_DTMFDETECTION, audio_if_DTMFDetection, int_policy), |
| UBUS_METHOD(AUDIO_IF_UBUS_PCMLOOPBACK_START, audio_if_pcmloopback_start, vcm_play_rec_policy), |
| UBUS_METHOD_NOARG(AUDIO_IF_UBUS_PCMLOOPBACK_STOP, audio_if_pcmloopback_stop), |
| UBUS_METHOD(AUDIO_IF_UBUS_CONFIG_PCM, audio_if_config_pcm, config_pcm_policy), |
| UBUS_METHOD(AUDIO_IF_UBUS_CONFIG_DSPGAIN, audio_if_config_dspgain, config_dspgain_policy), |
| UBUS_METHOD(AUDIO_IF_UBUS_CONFIG_PCMEXPERT, audio_if_config_pcmexpert, config_pcmexpert_policy), |
| UBUS_METHOD(AUDIO_IF_UBUS_DTMFCONTROL, audio_if_DTMFControl, vcm_dtmfcontrol_policy), |
| UBUS_METHOD(AUDIO_IF_UBUS_REPORT_VOICE_STATUS, audio_if_report_voice_status, int_policy), |
| UBUS_METHOD(AUDIO_IF_UBUS_RELOAD_NVM, audio_if_reload_nvm, int_policy), |
| UBUS_METHOD(AUDIO_IF_UBUS_CONFIG_PA, audio_if_config_pa, config_pa_policy), |
| #ifdef TARGET_mmp_asr1901_KSTR901 |
| UBUS_METHOD(AUDIO_IF_UBUS_ADSP_SET, audio_if_adsp_set, adsp_set_policy), |
| UBUS_METHOD_NOARG(AUDIO_IF_UBUS_ADSP_SEND_VE, audio_if_adsp_send_ve), |
| UBUS_METHOD(AUDIO_IF_UBUS_ADSP_DUMP_FULL_DDR, audio_if_adsp_dump_full_ddr, int_policy), |
| #endif |
| }; |
| |
| static struct ubus_object_type server_object_type = |
| UBUS_OBJECT_TYPE(AUDIO_IF_UBUS_ID, audio_if_methods); |
| |
| static bool Codec_Enabled = FALSE; |
| |
| /****************************************************************************** |
| * Code |
| ******************************************************************************/ |
| void AudioIf_uBussubscribeCb(struct ubus_context *ctx, struct ubus_object *obj) |
| { |
| UNUSEDPARAM(ctx); |
| UNUSEDPARAM(obj); |
| AUDIO_IF_LOGD("has_subscribers:%s\n", __FUNCTION__, obj->has_subscribers?"true":"false"); |
| } |
| |
| /*******************************************************************************\ |
| * Function: AUDIO_IF_CallActiveCount |
| * Description: Return active call count. |
| * Returns: active call count |
| \*******************************************************************************/ |
| static int AUDIO_IF_CallActiveCount(void) |
| { |
| int i, cnt = 0; |
| for(i=0; i<AUDIO_IF_CALLMAX; i++) |
| { |
| if(AUDIO_IF_CallIndexState[i] == AUDIO_IF_CALLINDEX_ACTIVE) |
| { |
| AUDIO_IF_LOGD("%s, active call index=%d\n", __FUNCTION__, i); |
| cnt++; |
| } |
| } |
| AUDIO_IF_LOGD("%s, active call count=%d\n", __FUNCTION__, cnt); |
| return cnt; |
| } |
| |
| |
| /*******************************************************************************\ |
| * Function: AUDIO_IF_CallHoldCount |
| * Description: Return hold call count. |
| * Returns: hold call count |
| \*******************************************************************************/ |
| static int AUDIO_IF_CallHoldCount(void) |
| { |
| int i, cnt = 0; |
| for(i=0; i<AUDIO_IF_CALLMAX; i++) |
| { |
| if(AUDIO_IF_CallIndexState[i] == AUDIO_IF_CALLINDEX_HOLD) |
| { |
| AUDIO_IF_LOGD("%s, hold call index=%d\n", __FUNCTION__, i); |
| cnt++; |
| } |
| } |
| AUDIO_IF_LOGD("%s, hold call count=%d\n", __FUNCTION__, cnt); |
| return cnt; |
| } |
| |
| |
| /*******************************************************************************\ |
| * Function: AUDIO_IF_CallAlertingCount |
| * Description: Return alerting call count. |
| * Returns: alerting call count |
| \*******************************************************************************/ |
| static int AUDIO_IF_CallAlertingCount(void) |
| { |
| int i, cnt = 0; |
| for(i=0; i<AUDIO_IF_CALLMAX; i++) |
| { |
| if(AUDIO_IF_CallIndexState[i] == AUDIO_IF_CALLINDEX_ALERTING) |
| { |
| AUDIO_IF_LOGD("%s, alerting call index=%d\n", __FUNCTION__, i); |
| cnt++; |
| } |
| } |
| AUDIO_IF_LOGD("%s, alerting call count=%d\n", __FUNCTION__, cnt); |
| return cnt; |
| } |
| |
| /*******************************************************************************\ |
| * Function: AUDIO_IF_CallWaitingCount |
| * Description: Return waiting call count. |
| * Returns: waiting call count |
| \*******************************************************************************/ |
| static int AUDIO_IF_CallWaitingCount(void) |
| { |
| int i, cnt = 0; |
| for(i=0; i<AUDIO_IF_CALLMAX; i++) |
| { |
| if(AUDIO_IF_CallIndexState[i] == AUDIO_IF_CALLINDEX_WAITING) |
| { |
| AUDIO_IF_LOGD("%s, waiting call index=%d\n", __FUNCTION__, i); |
| cnt++; |
| } |
| } |
| AUDIO_IF_LOGD("%s, waiting call count=%d\n", __FUNCTION__, cnt); |
| return cnt; |
| } |
| |
| /*******************************************************************************\ |
| * Function: AudioIf_uBusInd_RIL |
| * Description: This function is called upon RIL incoming indication. |
| * Returns: 0 on success |
| \*******************************************************************************/ |
| static int AudioIf_uBusInd_RIL(struct ubus_context *ctx, struct ubus_object *obj, |
| struct ubus_request_data *req, const char *method, |
| struct blob_attr *msg) |
| { |
| unsigned int requestid; |
| unsigned int rilerrno; |
| void *data = NULL; |
| int datalen; |
| int ret; |
| int callID = 0; |
| int active_cnt = 0, hold_cnt = 0, alerting_cnt = 0, waiting_cnt = 0; |
| RIL_CallState call_state = RIL_CALL_DISCONNECTED; |
| UNUSEDPARAM(ctx); |
| UNUSEDPARAM(obj); |
| UNUSEDPARAM(req); |
| UNUSEDPARAM(method); |
| |
| ret = rilutil_parseResponse(msg, &requestid, &rilerrno, &data, &datalen); |
| if (ret) { |
| AUDIO_IF_LOGE("parse msg error\n"); |
| goto end; |
| } |
| if (rilerrno) { |
| AUDIO_IF_LOGE("unsolicited id %d, error code %d\n", requestid, rilerrno); |
| ret = -1; |
| goto end; |
| } |
| |
| /* |
| * RIL indication relevant for audio_if |
| * to be implemented in audio_if/audio_if_api.c |
| */ |
| switch (requestid) |
| { |
| case RIL_UNSOL_CALL_STATUS_INFO: /*"CC" 1530*/ |
| { |
| RIL_Call_Ext *rilCall_Ext = (RIL_Call_Ext *)data; |
| callID = rilCall_Ext->index; |
| call_state = rilCall_Ext->state; |
| AUDIO_IF_LOGD("%s: id %d=RIL_UNSOL_CALL_STATUS_INFO (len=%d) (state=%s), call index=%d\n", |
| __FUNCTION__, requestid, datalen,RIL_MessageMap[(int)rilCall_Ext->state], callID); |
| |
| switch (rilCall_Ext->state) |
| { |
| //Call connected, for MO & MT both |
| case RIL_CALL_ACTIVE: |
| if(callID < AUDIO_IF_CALLMAX) |
| { |
| AUDIO_IF_LOGD("%s, call index=%d connected!!\n", __FUNCTION__, callID); |
| AUDIO_IF_CallIndexState[callID] = AUDIO_IF_CALLINDEX_ACTIVE; |
| } |
| break; |
| |
| //MT call only |
| case RIL_CALL_INCOMING: |
| break; |
| |
| //MO call only |
| case RIL_CALL_ALERTING: |
| if(callID < AUDIO_IF_CALLMAX) |
| { |
| AUDIO_IF_LOGD("%s, call index=%d alerting!!\n", __FUNCTION__, callID); |
| AUDIO_IF_CallIndexState[callID] = AUDIO_IF_CALLINDEX_ALERTING; |
| } |
| break; |
| |
| //MT call only |
| case RIL_CALL_WAITING: |
| if(callID < AUDIO_IF_CALLMAX) |
| { |
| AUDIO_IF_LOGD("%s, call index=%d waiting!!\n", __FUNCTION__, callID); |
| AUDIO_IF_CallIndexState[callID] = AUDIO_IF_CALLINDEX_WAITING; |
| } |
| break; |
| |
| case RIL_CALL_DISCONNECTED: |
| if(callID < AUDIO_IF_CALLMAX) |
| { |
| AUDIO_IF_LOGD("%s, call index=%d disconnected!!\n", __FUNCTION__, callID); |
| AUDIO_IF_CallIndexState[callID] = AUDIO_IF_CALLINDEX_IDLE; |
| } |
| break; |
| |
| case RIL_CALL_HOLDING: |
| if(callID < AUDIO_IF_CALLMAX) |
| {//Call hold |
| AUDIO_IF_LOGD("%s, call index=%d hold!!\n", __FUNCTION__, callID); |
| AUDIO_IF_CallIndexState[callID] = AUDIO_IF_CALLINDEX_HOLD; |
| } |
| break; |
| |
| case RIL_CALL_DIALING: //MO call only |
| case RIL_CALL_OFFERING: |
| case RIL_CALL_DISCONNECTING: |
| default: |
| AUDIO_IF_LOGD("%s, state=%s ignored!!\n", __FUNCTION__, RIL_MessageMap[(int)rilCall_Ext->state]); |
| break; |
| } |
| } |
| break; |
| |
| case RIL_UNSOL_RESPONSE_CALL_STATE_CHANGED_EXT: /*"CC" 1510*/ |
| { |
| RIL_Call *rilCall = (RIL_Call *)data; |
| callID = rilCall->index; |
| call_state = rilCall->state; |
| |
| AUDIO_IF_LOGD("%s: id %d=RIL_UNSOL_RESPONSE_CALL_STATE_CHANGED_EXT (len=%d) (state=%s), call index=%d\n", |
| __FUNCTION__, requestid, datalen,RIL_MessageMap[(int)rilCall->state], callID); |
| |
| switch (rilCall->state) |
| { |
| //Call connected, for MO & MT both |
| case RIL_CALL_ACTIVE: |
| if(callID < AUDIO_IF_CALLMAX) |
| { |
| AUDIO_IF_LOGD("%s, call index=%d connected!!\n", __FUNCTION__, callID); |
| AUDIO_IF_CallIndexState[callID] = AUDIO_IF_CALLINDEX_ACTIVE; |
| } |
| break; |
| |
| //MT call only |
| case RIL_CALL_INCOMING: |
| break; |
| |
| //MO call only |
| case RIL_CALL_ALERTING: |
| if(callID < AUDIO_IF_CALLMAX) |
| { |
| AUDIO_IF_LOGD("%s, call index=%d alerting!!\n", __FUNCTION__, callID); |
| AUDIO_IF_CallIndexState[callID] = AUDIO_IF_CALLINDEX_ALERTING; |
| } |
| break; |
| |
| case RIL_CALL_WAITING: //MT call only |
| if(callID < AUDIO_IF_CALLMAX) |
| { |
| AUDIO_IF_LOGD("%s, call index=%d waiting!!\n", __FUNCTION__, callID); |
| AUDIO_IF_CallIndexState[callID] = AUDIO_IF_CALLINDEX_WAITING; |
| } |
| break; |
| |
| case RIL_CALL_DISCONNECTED: |
| if(callID < AUDIO_IF_CALLMAX) |
| { |
| AUDIO_IF_LOGD("%s, call index=%d disconnected!!\n", __FUNCTION__, callID); |
| AUDIO_IF_CallIndexState[callID] = AUDIO_IF_CALLINDEX_IDLE; |
| } |
| break; |
| |
| case RIL_CALL_HOLDING: |
| if(callID < AUDIO_IF_CALLMAX) |
| {//Call hold |
| AUDIO_IF_LOGD("%s, call index=%d hold!!\n", __FUNCTION__, callID); |
| AUDIO_IF_CallIndexState[callID] = AUDIO_IF_CALLINDEX_HOLD; |
| } |
| break; |
| |
| case RIL_CALL_DIALING: //MO call only |
| case RIL_CALL_OFFERING: |
| case RIL_CALL_DISCONNECTING: |
| default: |
| AUDIO_IF_LOGD("%s, state=%s ignored!!\n", __FUNCTION__, RIL_MessageMap[(int)rilCall->state]); |
| break; |
| } |
| } |
| break; |
| |
| case RIL_UNSOL_CALL_NO_CARRIER_EXT: /*"CC" 1511*/ |
| AUDIO_IF_LOGD("%s: id %d=RIL_UNSOL_CALL_NO_CARRIER_EXT (len=%d)\n", |
| __FUNCTION__, requestid, datalen); |
| break; |
| |
| case RIL_UNSOL_CALL_RING: /*"CC" 1018*/ |
| AUDIO_IF_LOGD("%s: id %d=RIL_UNSOL_CALL_RING (len=%d), ignored!!\n", |
| __FUNCTION__, requestid, datalen); |
| break; |
| |
| case RIL_UNSOL_DISCONNECT_CALLID: /*"CC" 1538*/ |
| AUDIO_IF_LOGD("%s: id %d=RIL_UNSOL_DISCONNECT_CALLID (len=%d), call index=%d!\n", |
| __FUNCTION__, requestid, datalen, *(int *)data); |
| callID = *(int *)data; |
| if(callID < AUDIO_IF_CALLMAX) |
| { |
| AUDIO_IF_CallIndexState[callID] = AUDIO_IF_CALLINDEX_IDLE; |
| } |
| break; |
| |
| default: |
| AUDIO_IF_LOGD("%s: id %d (len=%d), ignored!!\n", __FUNCTION__, requestid, datalen); //1505... |
| break; |
| } |
| |
| active_cnt = AUDIO_IF_CallActiveCount(); |
| hold_cnt = AUDIO_IF_CallHoldCount(); |
| alerting_cnt = AUDIO_IF_CallAlertingCount(); |
| waiting_cnt = AUDIO_IF_CallWaitingCount(); |
| |
| AUDIO_IF_LOGD("%s: id=%d, (state=%s), call index=%d, active_cnt=%d, hold_cnt=%d, alerting_cnt=%d, waiting_cnt=%d!\n", |
| __FUNCTION__, requestid, RIL_MessageMap[(int)call_state], callID, |
| active_cnt, hold_cnt, alerting_cnt, waiting_cnt); |
| |
| switch (requestid) |
| { |
| case RIL_UNSOL_CALL_STATUS_INFO: /*"CC" 1530*/ |
| case RIL_UNSOL_RESPONSE_CALL_STATE_CHANGED_EXT: /*"CC" 1510*/ |
| { |
| RIL_CallState state = *(RIL_CallState *)data; |
| AUDIO_IF_LOGD("%s: id=%d(len=%d), state=%d(%s)", __FUNCTION__, requestid, datalen,state, RIL_MessageMap[(int)state]); |
| switch (state) |
| { |
| case RIL_CALL_DIALING: /* MO call only */ |
| case RIL_CALL_INCOMING: /* MT call only */ |
| if(FALSE == Codec_Enabled) |
| { |
| AUDIO_IF_LOGD("%s: open codec voice path, out_device=%d, madev->in_call=%d, madev->in_hfp=%d, madev->mode=%d", |
| __FUNCTION__, mrvl_ahw_dev_ubus->out_device, mrvl_ahw_dev_ubus->in_call, mrvl_ahw_dev_ubus->in_hfp, mrvl_ahw_dev_ubus->mode); |
| pthread_mutex_lock(&AudioIf_mutex); |
| mrvl_ahw_dev_ubus->device.set_mode(ahw_dev_ubus, AUDIO_MODE_IN_CALL); |
| |
| if(AUDIO_DEVICE_OUT_EARPIECE == mrvl_ahw_dev_ubus->out_device |
| || AUDIO_DEVICE_OUT_SPEAKER == mrvl_ahw_dev_ubus->out_device) { |
| audio_pa_enable(AUDIO_PA_VOICE); |
| } |
| |
| /*Set Volume after starting call just like doing in APSE (android)*/ |
| mrvl_ahw_dev_ubus->device.set_voice_volume(ahw_dev_ubus, mrvl_ahw_dev_ubus->voice_volume); |
| pthread_mutex_unlock(&AudioIf_mutex); |
| |
| Codec_Enabled = TRUE; |
| } |
| break; |
| case RIL_CALL_ALERTING: |
| case RIL_CALL_ACTIVE: |
| case RIL_CALL_HOLDING: |
| case RIL_CALL_WAITING: |
| case RIL_CALL_OFFERING: |
| case RIL_CALL_DISCONNECTING: |
| case RIL_CALL_DISCONNECTED: |
| default: |
| AUDIO_IF_LOGD("%s: state=%d(%s) ignored!!\n", __FUNCTION__, state, RIL_MessageMap[(int)state]); |
| break; |
| } |
| } |
| break; |
| |
| case RIL_UNSOL_CALL_NO_CARRIER_EXT: /*"CC" 1511*/ |
| if ((0 == active_cnt) && (0 == hold_cnt) && (0 == waiting_cnt)) |
| { |
| if(TRUE == Codec_Enabled) |
| { |
| AUDIO_IF_LOGD("%s: id=%d(len=%d), close codec voice path, out_device=%d, madev->in_call=%d, madev->in_hfp=%d, madev->mode=%d", |
| __FUNCTION__, requestid, datalen, mrvl_ahw_dev_ubus->out_device, mrvl_ahw_dev_ubus->in_call, mrvl_ahw_dev_ubus->in_hfp, mrvl_ahw_dev_ubus->mode); |
| pthread_mutex_lock(&AudioIf_mutex); |
| |
| if(AUDIO_DEVICE_OUT_EARPIECE == mrvl_ahw_dev_ubus->out_device |
| || AUDIO_DEVICE_OUT_SPEAKER == mrvl_ahw_dev_ubus->out_device) { |
| audio_pa_disable(AUDIO_PA_VOICE); |
| } |
| |
| mrvl_ahw_dev_ubus->device.set_mode(ahw_dev_ubus, AUDIO_MODE_INVALID); |
| pthread_mutex_unlock(&AudioIf_mutex); |
| |
| Codec_Enabled = FALSE; |
| } |
| } |
| break; |
| |
| default: |
| AUDIO_IF_LOGD("%s: id=%d(len=%d) ignored ", __FUNCTION__, requestid, datalen); //1505... |
| break; |
| } |
| |
| end: |
| if (data) |
| rilutil_freeResponseData(requestid, data, datalen); |
| |
| return ret; |
| } |
| |
| int AudioIf_uBusSubscribeEvents(char isSubscribe) |
| { |
| if (audioIfUbusDb.ind_enabled != isSubscribe) { |
| audioIfUbusDb.ind_enabled = isSubscribe; |
| |
| if (isSubscribe) { |
| AUDIO_IF_UBUS_SUBSCRIBE_EVENT(audioIfUbusDb, "ril.unsol.cc"); |
| } else { |
| AUDIO_IF_UBUS_UNSUBSCRIBE_EVENT(audioIfUbusDb, "ril.unsol.cc"); |
| } |
| } |
| |
| return 0; |
| } |
| |
| static int AudioIf_uBusRegisterNotifications(void) |
| { |
| int ret; |
| |
| ret = ubus_register_subscriber(audioIfUbusDb.ctx, &audioIfUbusDb.ind_event); |
| if (ret) { |
| AUDIO_IF_LOGE("Failed to add watch handler: %s\n", ubus_strerror(ret)); |
| return -1; |
| } |
| |
| audioIfUbusDb.ind_event.cb = AudioIf_uBusInd_RIL; |
| |
| return 0; |
| } |
| |
| int AudioIf_uBusInit(void) |
| { |
| pthread_mutexattr_t oAttr; |
| pthread_mutexattr_t *pAttr = NULL; |
| |
| memset(&audioIfUbusDb, 0, sizeof(audioIfUbusDb_t)); |
| memset(&audioIfReqDb.reqdata, 0, sizeof(audioIfReqDb.reqdata)); |
| audioIfReqDb.pMutexLock = &req_data_mutex; |
| |
| if (!pthread_mutexattr_init(&oAttr) && !pthread_mutexattr_settype(&oAttr, PTHREAD_MUTEX_RECURSIVE)) { |
| pAttr = &oAttr; |
| } |
| |
| if (pthread_mutex_init(audioIfReqDb.pMutexLock, pAttr)) |
| ALOGE("init mutex fail \n"); |
| |
| pthread_mutex_lock(audioIfReqDb.pMutexLock); |
| audioIfReqDb.occupy = 0; |
| pthread_mutex_unlock(audioIfReqDb.pMutexLock); |
| |
| uloop_init(); |
| |
| audioIfUbusDb.ctx = ubus_connect(NULL); |
| if (audioIfUbusDb.ctx == NULL) { |
| AUDIO_IF_LOGE("Failed to connect to ubus"); |
| return -1; |
| } |
| |
| ubus_add_uloop(audioIfUbusDb.ctx); |
| |
| /*set server object*/ |
| audioIfUbusDb.server_obj.name = AUDIO_IF_UBUS_ID; |
| audioIfUbusDb.server_obj.type = &server_object_type; |
| audioIfUbusDb.server_obj.methods = audio_if_methods; |
| audioIfUbusDb.server_obj.n_methods = ARRAY_SIZE(audio_if_methods); |
| audioIfUbusDb.server_obj.subscribe_cb = AudioIf_uBussubscribeCb; |
| |
| /*add audio_if server object*/ |
| if (ubus_add_object(audioIfUbusDb.ctx, &audioIfUbusDb.server_obj)) { |
| AUDIO_IF_LOGE("Failed to add server"); |
| ubus_free(audioIfUbusDb.ctx); |
| uloop_done(); |
| return -1; |
| } |
| |
| /* lookup fail if ril is not ready */ |
| while(1) |
| { |
| /*look for RIL id */ |
| if (ubus_lookup_id(audioIfUbusDb.ctx, RIL_UBUS_ID, &audioIfUbusDb.ril_subscriber_id)) { |
| AUDIO_IF_LOGE("Failed to look up RILD object"); |
| usleep(600000); //600ms |
| } else { |
| break; |
| } |
| } |
| AUDIO_IF_LOGD("%s, ubus_lookup_id(%s) OK\n", __FUNCTION__, RIL_UBUS_ID); |
| |
| /*subscribe for RIL notifications*/ |
| if (AudioIf_uBusRegisterNotifications() != 0) |
| return -1; |
| |
| AUDIO_IF_LOGD("AudioIf_uBusInit done!\n"); |
| return 0; |
| } |
| |
| void audio_if_recv(struct uloop_fd *u, unsigned int events) |
| { |
| UNUSEDPARAM(events); |
| AudioIf_ReadFromDevice(u->fd); |
| } |
| |
| void AudioIf_uBusFdAdd(int fd) |
| { |
| int ret; |
| |
| audio_if_fd.cb = audio_if_recv; |
| audio_if_fd.fd = fd; |
| |
| ret = uloop_fd_add(&audio_if_fd, ULOOP_READ); |
| |
| AUDIO_IF_LOGD("%s: uloop_fd_add returned %d", __FUNCTION__, ret); |
| } |
| void AudioIf_uBusUloopRun(void) |
| { |
| uloop_run(); |
| } |