| #include <pthread.h> |
| #include <time.h> |
| #include <sys/ioctl.h> |
| #include <fcntl.h> |
| #include <libubox/blobmsg_json.h> |
| #include <libubox/ustream.h> |
| #include <libubus.h> |
| #include "ril.h" |
| #include "rilutil.h" |
| #include <fcntl.h> |
| #include <unistd.h> |
| #include <string.h> |
| #include <fcntl.h> |
| #include <unistd.h> |
| #include <libubox/blobmsg_json.h> |
| #include "libubus.h" |
| #include <string.h> |
| #include "audio_if.h" |
| #include "audio_if_parameter.h" |
| #include "audio_if_types.h" |
| #include "audio_if_ubus.h" |
| #include "audio_if_api.h" |
| #include "audio_if_audio_hw_mrvl.h" |
| #include "utlEventHandler.h" |
| #include "udev_monitor.h" |
| #include <libubox/blobmsg_json.h> |
| #include <libubox/ustream.h> |
| #include <libubus.h> |
| |
| //#define DTMF_CODE_DEMO |
| #define VOICE_STATUS_DEMO |
| #define DEBUG_DTMF_CONTROL |
| |
| extern void* audio_hal_install(void); |
| extern void audio_hal_uninstall(void); |
| static audio_hw_device_t *ahw_dev_ubus; |
| static struct mrvl_audio_device *mrvl_ahw_dev_ubus; |
| /*-------------------------------------------------------------------*/ |
| #define AUDIOAPP_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 */ |
| }; |
| |
| //Call Index Status |
| typedef enum |
| { |
| AUDIOAPP_CALLINDEX_IDLE = 0, |
| AUDIOAPP_CALLINDEX_ACTIVE, |
| AUDIOAPP_CALLINDEX_HOLD, |
| AUDIOAPP_CALLINDEX_ALERTING, |
| } AUDIOAPP_CALLINDEX_S; |
| |
| /*****************************************************\ |
| * Call State |
| * 0: id |
| le |
| * 1: active |
| * 2: hold |
| * 3: alerting |
| \*****************************************************/ |
| int AUDIOAPP_CallIndexState[AUDIOAPP_CALLMAX] = {0}; |
| /*-------------------------------------------------------------------*/ |
| |
| //For UBUS listening to RILD & audio_if |
| typedef struct |
| { |
| struct ubus_context *ctx; |
| |
| /* RIL */ |
| struct ubus_subscriber ril_ind_event; |
| uint32_t ril_subscriber_id; |
| uint32_t ril_request_id; |
| |
| /* Audio_If */ |
| struct ubus_subscriber audioif_event; |
| uint32_t audioif_subscriber_id; |
| uint32_t audioif_request_id; |
| } AUDIOAPPUbusDb_t; |
| |
| #ifndef AUDIOAPP_DIAG_LOG |
| #define LOG_OUT(format, arg ...) RINFOMSG(format, ##arg) |
| #define LOG_OUT_D(format, arg ...) RDBGMSG(format, ##arg) |
| #define LOG_OUT_E(format, arg ...) RERRMSG(format, ##arg) |
| //re-define printf |
| #define printf(format, arg ...) LOG_OUT(format, ##arg) |
| #else |
| #define LOG_OUT(format, arg ...) printf(format, ##arg) |
| #define LOG_OUT_D(format, arg ...) printf(format, ##arg) |
| #define LOG_OUT_E(format, arg ...) printf(format, ##arg) |
| #endif |
| |
| #define RIL_UBUS_REQUEST_NAME "ril" |
| #define RIL_UBUS_NOTIFICATION_NAME "ril.unsol.cc" |
| #define AUDIO_UBUS_REQUEST_NAME "audio_if" |
| |
| #ifdef DTMF_CODE_DEMO |
| /*---------------------DTMF Code-------------------------*/ |
| #define DTMFCODEID "dtmfcode" |
| #define DTMFCODE_NOTIFICATION_NAME "audioif.dtmfcode" |
| |
| const struct blobmsg_policy DTMFCode_policy[] = { |
| [0] = { |
| .name = DTMFCODEID, |
| .type = BLOBMSG_TYPE_INT32, |
| }, |
| }; |
| #endif |
| |
| #ifdef VOICE_STATUS_DEMO |
| /*---------------------Voice Status-------------------------*/ |
| #define VOICESTATUSID "voicestatus" |
| #define VOICESTATUS_NOTIFICATION_NAME "audioif.voicestatus" |
| const struct blobmsg_policy VoiceStatus_policy[] = { |
| [0] = { |
| .name = VOICESTATUSID, |
| .type = BLOBMSG_TYPE_INT32, |
| }, |
| }; |
| #endif |
| |
| #ifdef DEBUG_DTMF_CONTROL |
| #define AUDIOAPP_DTMFControlTimer_frequency_interval 1 |
| |
| static timer_t AUDIOAPP_DTMFControl_timer_id; |
| static struct sigevent AUDIOAPP_DTMFControl_sigev; |
| static struct itimerspec AUDIOAPP_DTMFControl_ts; |
| |
| static unsigned int ForNoInbandTone_SecondCount = 0; |
| static unsigned int DTMFControlTimer_Starting = 0; |
| static unsigned int tone1_index_used = 0; |
| static unsigned int tone2_index_used = 0; |
| |
| extern void vcm_switch_pcm(unsigned int pcm_on); |
| extern int vcm_DTMFDetection(unsigned int onoff, unsigned int dialToneToOthersTones, unsigned int dialTonesToOthersDialTones, unsigned int dialVadDuration); |
| extern int vcm_DTMFControl(unsigned int onoff, unsigned int tone1_index, unsigned int tone2_index); |
| /*******************************************************************************\ |
| * Function: AUDIOAPP_DTMFControlTimer_Start |
| * Description: Start DTMF Control timer. |
| * Returns: 0 on success |
| \*******************************************************************************/ |
| static int AUDIOAPP_DTMFControlTimer_Start(void) |
| { |
| int rc = 0; |
| |
| LOG_OUT("%s\n", __FUNCTION__); |
| ForNoInbandTone_SecondCount = 0; |
| DTMFControlTimer_Starting = 1; |
| |
| memset (&AUDIOAPP_DTMFControl_ts, 0x00, sizeof (struct itimerspec)); |
| AUDIOAPP_DTMFControl_ts.it_interval.tv_sec = AUDIOAPP_DTMFControlTimer_frequency_interval;/* callback function is invoked frequently every 1 seconds */ |
| AUDIOAPP_DTMFControl_ts.it_interval.tv_nsec = 0; |
| AUDIOAPP_DTMFControl_ts.it_value.tv_sec = 1;/* countdown to invoke callback function */ |
| AUDIOAPP_DTMFControl_ts.it_value.tv_nsec = 0; |
| rc = timer_settime(AUDIOAPP_DTMFControl_timer_id, 0, &AUDIOAPP_DTMFControl_ts, NULL); |
| |
| return rc; |
| } |
| |
| /*******************************************************************************\ |
| * Function: AUDIOAPP_DTMFControlTimer_Stop |
| * Description: Stop DTMF Control timer. |
| * Returns: 0 on success |
| \*******************************************************************************/ |
| static int AUDIOAPP_DTMFControlTimer_Stop(void) |
| { |
| int rc = 0; |
| int OnOff = 0; |
| |
| LOG_OUT("%s\n", __FUNCTION__); |
| //clear the count for seconds |
| ForNoInbandTone_SecondCount = 0; |
| DTMFControlTimer_Starting = 0; |
| |
| AUDIOAPP_DTMFControl_ts.it_interval.tv_sec = 0; |
| AUDIOAPP_DTMFControl_ts.it_interval.tv_nsec = 0; |
| AUDIOAPP_DTMFControl_ts.it_value.tv_sec = 0;/* countdown to invoke callback function */ |
| AUDIOAPP_DTMFControl_ts.it_value.tv_nsec = 0; |
| rc = timer_settime(AUDIOAPP_DTMFControl_timer_id, 0, &AUDIOAPP_DTMFControl_ts, NULL); |
| |
| vcm_DTMFControl(OnOff, tone1_index_used, tone2_index_used); |
| return rc; |
| } |
| |
| /*******************************************************************************\ |
| * Function: AUDIOAPP_DTMFControlTimer_Handler |
| * Description: Handle call status while DTMFControl timer expire. |
| * Returns: |
| \*******************************************************************************/ |
| static void AUDIOAPP_DTMFControlTimer_Handler(__attribute__( (unused)) sigval_t sv) |
| { |
| int OnOff = 0; |
| |
| LOG_OUT("%s\n", __FUNCTION__); |
| tone1_index_used = F450; |
| tone2_index_used = F450; |
| |
| /* prevent from the handler function is invoked again, after the timer has been stopped */ |
| if(DTMFControlTimer_Starting == 0) |
| { |
| LOG_OUT("%s:The timer has been stopped.\n", __FUNCTION__); |
| return; |
| } |
| |
| if((ForNoInbandTone_SecondCount % 4) == 0) |
| { |
| OnOff = 1; //'Du' for one second, 450hz |
| } |
| else |
| { |
| OnOff = 0; //No 'Du' for 3 seconds |
| } |
| |
| vcm_DTMFControl(OnOff, tone1_index_used, tone2_index_used); |
| |
| ForNoInbandTone_SecondCount++; |
| return; |
| } |
| |
| /*******************************************************************************\ |
| * Function: AUDIOAPP_DTMFControlTimer_Init |
| * Description: Init DTMFControl timer. |
| * Returns: 0 on success |
| \*******************************************************************************/ |
| static int AUDIOAPP_DTMFControlTimer_Init(void) |
| { |
| int rc = 0; |
| LOG_OUT("%s\n", __FUNCTION__); |
| |
| memset (&AUDIOAPP_DTMFControl_sigev, 0x00, sizeof (struct sigevent)); |
| |
| //AUDIOAPP_DTMFControl_sigev.sigev_value.sival_ptr = &AUDIOAPP_DTMFControl_timer_id; |
| AUDIOAPP_DTMFControl_sigev.sigev_notify = SIGEV_THREAD; |
| //AUDIOAPP_DTMFControl_sigev.sigev_notify_attributes = NULL; |
| AUDIOAPP_DTMFControl_sigev.sigev_notify_function = AUDIOAPP_DTMFControlTimer_Handler; |
| |
| rc = timer_create(CLOCK_REALTIME, &AUDIOAPP_DTMFControl_sigev, &AUDIOAPP_DTMFControl_timer_id); |
| if (rc == -1) |
| { |
| LOG_OUT("Create timer error, exiting service....."); |
| } |
| |
| return rc; |
| } |
| #endif |
| |
| static pthread_t AUDIOAPP_MainLoopTask; |
| static AUDIOAPPUbusDb_t AUDIOAPP_UBUS_Db; |
| |
| //Used by Modem DTMF Detection |
| volatile int g_AUDIOAPP_Modem_DTMF_Detection = FALSE; |
| char g_Modem_DTMF_Detection_Char; |
| |
| /*****************************************************\ |
| * Retry mechanism to add subscriber for RIL |
| \*****************************************************/ |
| static void AUDIOAPP_add_subscriber_RIL(struct uloop_timeout *timeout) |
| { |
| /* add subscriber for ril */ |
| if (ubus_lookup_id(AUDIOAPP_UBUS_Db.ctx, RIL_UBUS_NOTIFICATION_NAME, &AUDIOAPP_UBUS_Db.ril_subscriber_id)) |
| { |
| LOG_OUT_E("%s, Failed to look up %s\n", __FUNCTION__, RIL_UBUS_NOTIFICATION_NAME); |
| uloop_timeout_set(timeout, 2000); |
| return; |
| } |
| |
| ubus_subscribe(AUDIOAPP_UBUS_Db.ctx, &AUDIOAPP_UBUS_Db.ril_ind_event, AUDIOAPP_UBUS_Db.ril_subscriber_id); |
| LOG_OUT("RIL subscribe %s object ok\n", RIL_UBUS_NOTIFICATION_NAME); |
| return; |
| } |
| |
| static struct uloop_timeout AUDIOAPP_add_subscribe_timeout_RIL = |
| { |
| .cb = AUDIOAPP_add_subscriber_RIL, |
| }; |
| |
| static void AUDIOAPP_uBusInd_RIL_remove(struct ubus_context *ctx, struct ubus_subscriber *s, |
| uint32_t id) |
| { |
| UNUSEDPARAM(ctx); |
| UNUSEDPARAM(s); |
| UNUSEDPARAM(id); |
| |
| LOG_OUT("%s\n", __FUNCTION__); |
| uloop_timeout_set(&AUDIOAPP_add_subscribe_timeout_RIL, 2000); |
| } |
| |
| /*******************************************************************************\ |
| * Function: AUDIOAPP_CallActiveCount |
| * Description: Return active call count. |
| * Returns: active call count |
| \*******************************************************************************/ |
| static int AUDIOAPP_CallActiveCount(void) |
| { |
| int i, cnt = 0; |
| for(i=0; i<AUDIOAPP_CALLMAX; i++) |
| { |
| if(AUDIOAPP_CallIndexState[i] == AUDIOAPP_CALLINDEX_ACTIVE) |
| { |
| LOG_OUT("%s, active call index=%d\n", __FUNCTION__, i); |
| cnt++; |
| } |
| } |
| LOG_OUT("%s, active call count=%d\n", __FUNCTION__, cnt); |
| return cnt; |
| } |
| |
| |
| /*******************************************************************************\ |
| * Function: AUDIOAPP_CallHoldCount |
| * Description: Return hold call count. |
| * Returns: hold call count |
| \*******************************************************************************/ |
| static int AUDIOAPP_CallHoldCount(void) |
| { |
| int i, cnt = 0; |
| for(i=0; i<AUDIOAPP_CALLMAX; i++) |
| { |
| if(AUDIOAPP_CallIndexState[i] == AUDIOAPP_CALLINDEX_HOLD) |
| { |
| LOG_OUT("%s, hold call index=%d\n", __FUNCTION__, i); |
| cnt++; |
| } |
| } |
| LOG_OUT("%s, hold call count=%d\n", __FUNCTION__, cnt); |
| return cnt; |
| } |
| |
| |
| /*******************************************************************************\ |
| * Function: AUDIOAPP_CallAlertingCount |
| * Description: Return alerting call count. |
| * Returns: alerting call count |
| \*******************************************************************************/ |
| static int AUDIOAPP_CallAlertingCount(void) |
| { |
| int i, cnt = 0; |
| for(i=0; i<AUDIOAPP_CALLMAX; i++) |
| { |
| if(AUDIOAPP_CallIndexState[i] == AUDIOAPP_CALLINDEX_ALERTING) |
| { |
| LOG_OUT("%s, alerting call index=%d\n", __FUNCTION__, i); |
| cnt++; |
| } |
| } |
| LOG_OUT("%s, alerting call count=%d\n", __FUNCTION__, cnt); |
| return cnt; |
| } |
| |
| /*******************************************************************************\ |
| * Function: AUDIOAPP_uBusInd_RIL |
| * Description: Handle RIL incoming indication. |
| * Returns: 0 on success |
| \*******************************************************************************/ |
| static int AUDIOAPP_uBusInd_RIL(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); |
| |
| unsigned int requestid; |
| unsigned int rilerrno; |
| void *data = NULL; |
| int datalen; |
| int ret = 0; |
| int callID = 0; |
| int active_cnt = 0, hold_cnt = 0, alerting_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) { |
| LOG_OUT("parse msg error\n"); |
| goto end; |
| } |
| if (rilerrno) { |
| LOG_OUT("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; |
| LOG_OUT("%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 < AUDIOAPP_CALLMAX) |
| { |
| LOG_OUT("%s, call index=%d connected!!\n", __FUNCTION__, callID); |
| AUDIOAPP_CallIndexState[callID] = AUDIOAPP_CALLINDEX_ACTIVE; |
| } |
| break; |
| |
| //MT call only |
| case RIL_CALL_INCOMING: |
| break; |
| |
| //MO call only |
| case RIL_CALL_ALERTING: |
| if(callID < AUDIOAPP_CALLMAX) |
| { |
| LOG_OUT("%s, call index=%d alerting!!\n", __FUNCTION__, callID); |
| AUDIOAPP_CallIndexState[callID] = AUDIOAPP_CALLINDEX_ALERTING; |
| } |
| break; |
| |
| //MT call only |
| case RIL_CALL_WAITING: |
| break; |
| |
| case RIL_CALL_DISCONNECTED: |
| if(callID < AUDIOAPP_CALLMAX) |
| { |
| LOG_OUT("%s, call index=%d disconnected!!\n", __FUNCTION__, callID); |
| AUDIOAPP_CallIndexState[callID] = AUDIOAPP_CALLINDEX_IDLE; |
| } |
| break; |
| |
| case RIL_CALL_HOLDING: |
| if(callID < AUDIOAPP_CALLMAX) |
| {//Call hold |
| LOG_OUT("%s, call index=%d hold!!\n", __FUNCTION__, callID); |
| AUDIOAPP_CallIndexState[callID] = AUDIOAPP_CALLINDEX_HOLD; |
| } |
| break; |
| |
| case RIL_CALL_DIALING: //MO call only |
| case RIL_CALL_OFFERING: |
| case RIL_CALL_DISCONNECTING: |
| default: |
| LOG_OUT("%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; |
| |
| LOG_OUT("%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 < AUDIOAPP_CALLMAX) |
| { |
| LOG_OUT("%s, call index=%d connected!!\n", __FUNCTION__, callID); |
| AUDIOAPP_CallIndexState[callID] = AUDIOAPP_CALLINDEX_ACTIVE; |
| } |
| break; |
| |
| //MT call only |
| case RIL_CALL_INCOMING: |
| break; |
| |
| //MO call only |
| case RIL_CALL_ALERTING: |
| if(callID < AUDIOAPP_CALLMAX) |
| { |
| LOG_OUT("%s, call index=%d alerting!!\n", __FUNCTION__, callID); |
| AUDIOAPP_CallIndexState[callID] = AUDIOAPP_CALLINDEX_ALERTING; |
| } |
| break; |
| |
| case RIL_CALL_WAITING: //MT call only |
| break; |
| |
| case RIL_CALL_DISCONNECTED: |
| if(callID < AUDIOAPP_CALLMAX) |
| { |
| LOG_OUT("%s, call index=%d disconnected!!\n", __FUNCTION__, callID); |
| AUDIOAPP_CallIndexState[callID] = AUDIOAPP_CALLINDEX_IDLE; |
| } |
| break; |
| |
| case RIL_CALL_HOLDING: |
| if(callID < AUDIOAPP_CALLMAX) |
| {//Call hold |
| LOG_OUT("%s, call index=%d hold!!\n", __FUNCTION__, callID); |
| AUDIOAPP_CallIndexState[callID] = AUDIOAPP_CALLINDEX_HOLD; |
| } |
| break; |
| |
| case RIL_CALL_DIALING: //MO call only |
| case RIL_CALL_OFFERING: |
| case RIL_CALL_DISCONNECTING: |
| default: |
| LOG_OUT("%s, state=%s ignored!!\n", __FUNCTION__, RIL_MessageMap[(int)rilCall->state]); |
| break; |
| } |
| } |
| break; |
| |
| case RIL_UNSOL_CALL_NO_CARRIER_EXT: /*"CC" 1511*/ |
| LOG_OUT("%s: id %d=RIL_UNSOL_CALL_NO_CARRIER_EXT (len=%d)\n", |
| __FUNCTION__, requestid, datalen); |
| break; |
| |
| case RIL_UNSOL_CALL_RING: /*"CC" 1018*/ |
| LOG_OUT("%s: id %d=RIL_UNSOL_CALL_RING (len=%d), ignored!!\n", |
| __FUNCTION__, requestid, datalen); |
| break; |
| |
| case RIL_UNSOL_DISCONNECT_CALLID: /*"CC" 1538*/ |
| LOG_OUT("%s: id %d=RIL_UNSOL_DISCONNECT_CALLID (len=%d), call index=%d!\n", |
| __FUNCTION__, requestid, datalen, *(int *)data); |
| callID = *(int *)data; |
| if(callID < AUDIOAPP_CALLMAX) |
| { |
| AUDIOAPP_CallIndexState[callID] = AUDIO_IF_CALLINDEX_IDLE; |
| } |
| break; |
| |
| default: |
| LOG_OUT("%s: id %d (len=%d), ignored!!\n", __FUNCTION__, requestid, datalen); //1505... |
| break; |
| } |
| |
| active_cnt = AUDIOAPP_CallActiveCount(); |
| hold_cnt = AUDIOAPP_CallHoldCount(); |
| alerting_cnt = AUDIOAPP_CallAlertingCount(); |
| |
| LOG_OUT("%s: id=%d, (state=%s), call index=%d, active_cnt=%d, hold_cnt=%d, alerting_cnt=%d!\n", |
| __FUNCTION__, requestid, RIL_MessageMap[(int)call_state], callID, |
| active_cnt, hold_cnt, alerting_cnt); |
| |
| #ifdef DEBUG_DTMF_CONTROL |
| 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; |
| LOG_OUT("%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 */ |
| LOG_OUT("%s: open codec voice path when RIL_CALL_DIALING.", __FUNCTION__); |
| #if 0 |
| mrvl_ahw_dev_ubus->device.set_mode(ahw_dev_ubus, AUDIO_MODE_IN_CALL); |
| /*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); |
| #endif |
| break; |
| case RIL_CALL_INCOMING: /* MT call only */ |
| LOG_OUT("%s: open codec voice path when RIL_CALL_INCOMING.", __FUNCTION__); |
| #if 0 |
| mrvl_ahw_dev_ubus->device.set_mode(ahw_dev_ubus, AUDIO_MODE_IN_CALL); |
| /*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); |
| #endif |
| /* open PCM Clk */ |
| vcm_switch_pcm(PCM_SWITCH_TYPE_PCM_ON_WITH_CODEC); |
| vcm_DTMFDetection(DTMF_DETECTION_TX_ON, 50, 4, 3); |
| usleep(200000);/* wait for the stable of clk */ |
| |
| AUDIOAPP_DTMFControlTimer_Start(); |
| break; |
| case RIL_CALL_ACTIVE: |
| case RIL_CALL_HOLDING: |
| case RIL_CALL_WAITING: |
| case RIL_CALL_OFFERING: |
| case RIL_CALL_DISCONNECTING: |
| case RIL_CALL_DISCONNECTED: |
| LOG_OUT("%s: state=%d(%s). AUDIOAPP_DTMFControlTimer_Stop()!!\n", __FUNCTION__, state, RIL_MessageMap[(int)state]); |
| AUDIOAPP_DTMFControlTimer_Stop(); |
| break; |
| case RIL_CALL_ALERTING: |
| default: |
| LOG_OUT("%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 == alerting_cnt)) |
| { |
| LOG_OUT("%s: id=%d(len=%d), close codec voice path", __FUNCTION__, requestid, datalen); |
| #if 0 |
| mrvl_ahw_dev_ubus->device.set_mode(ahw_dev_ubus, AUDIO_MODE_INVALID); |
| #endif |
| AUDIOAPP_DTMFControlTimer_Stop(); |
| |
| /* close PCM Clk */ |
| vcm_switch_pcm(PCM_SWITCH_TYPE_PCM_OFF_WITH_CODEC); |
| vcm_DTMFDetection(DTMF_DETECTION_TX_OFF, 50, 4, 3); |
| usleep(200000); |
| } |
| break; |
| |
| default: |
| LOG_OUT("%s: id=%d(len=%d) ignored ", __FUNCTION__, requestid, datalen); //1505... |
| break; |
| } |
| #else |
| 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; |
| LOG_OUT("%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 */ |
| LOG_OUT("%s: open codec voice path", __FUNCTION__); |
| #if 0 |
| mrvl_ahw_dev_ubus->device.set_mode(ahw_dev_ubus, AUDIO_MODE_IN_CALL); |
| /*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); |
| #endif |
| 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: |
| LOG_OUT("%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 == alerting_cnt)) |
| { |
| LOG_OUT("%s: id=%d(len=%d), close codec voice path", __FUNCTION__, requestid, datalen); |
| #if 0 |
| mrvl_ahw_dev_ubus->device.set_mode(ahw_dev_ubus, AUDIO_MODE_INVALID); |
| #endif |
| } |
| break; |
| |
| default: |
| LOG_OUT("%s: id=%d(len=%d) ignored ", __FUNCTION__, requestid, datalen); //1505... |
| break; |
| } |
| #endif |
| |
| end: |
| if (data) |
| rilutil_freeResponseData(requestid, data, datalen); |
| |
| return ret; |
| } |
| |
| #ifdef DTMF_CODE_DEMO |
| /*****************************************************\ |
| * Retry mechanism to add subscriber for Audio_if |
| \*****************************************************/ |
| static void AUDIOAPP_add_subscriber_AudioIf(struct uloop_timeout *timeout) |
| { |
| /* add subscriber for Audio_If */ |
| if (ubus_lookup_id(AUDIOAPP_UBUS_Db.ctx, DTMFCODE_NOTIFICATION_NAME, &AUDIOAPP_UBUS_Db.audioif_subscriber_id)) |
| { |
| LOG_OUT_E("%s, Failed to look up %s\n", __FUNCTION__, DTMFCODE_NOTIFICATION_NAME); |
| uloop_timeout_set(timeout, 2000); |
| return; |
| } |
| |
| ubus_subscribe(AUDIOAPP_UBUS_Db.ctx, &AUDIOAPP_UBUS_Db.audioif_event, AUDIOAPP_UBUS_Db.audioif_subscriber_id); |
| LOG_OUT("Audio_If subscribe %s object ok\n", DTMFCODE_NOTIFICATION_NAME); |
| return; |
| } |
| |
| static struct uloop_timeout AUDIOAPP_add_subscribe_timeout_AudioIf = |
| { |
| .cb = AUDIOAPP_add_subscriber_AudioIf, |
| }; |
| |
| static void AUDIOAPP_uBusInd_AudioIf_remove(struct ubus_context *ctx, struct ubus_subscriber *s, uint32_t id) |
| { |
| UNUSEDPARAM(ctx); |
| UNUSEDPARAM(s); |
| UNUSEDPARAM(id); |
| |
| LOG_OUT("%s\n", __FUNCTION__); |
| uloop_timeout_set(&AUDIOAPP_add_subscribe_timeout_AudioIf, 2000); |
| } |
| |
| /*******************************************************************************\ |
| * Function: AUDIOAPP_uBusInd_AudioIf |
| * Description: Handle upon Audio_If incoming indication. |
| * Returns: 0 on success |
| \*******************************************************************************/ |
| static int AUDIOAPP_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; |
| |
| LOG_OUT("\n===============================================================================\n"); |
| |
| /*parsing blob to be accessed easily with tb array - parse "1" argument*/ |
| rc = blobmsg_parse(DTMFCode_policy, 1, tb, blob_data(msg), blob_len(msg)); |
| |
| if (rc < 0) { |
| LOG_OUT_E("%s: parsing fail, rc = 0x%x\n", __FUNCTION__, rc); |
| } else { |
| DTMFCode = (char)blobmsg_get_u32(tb[0]); |
| LOG_OUT("%s got DTMF Code: Char[%c]=ASCII[0x%x]\n", __FUNCTION__, DTMFCode, DTMFCode); |
| } |
| |
| g_Modem_DTMF_Detection_Char = DTMFCode; |
| g_AUDIOAPP_Modem_DTMF_Detection = TRUE; |
| LOG_OUT("%s: Enable g_AUDIOAPP_Modem_DTMF_Detection.\n", __FUNCTION__); |
| |
| LOG_OUT("===============================================================================\n\n"); |
| |
| return rc; |
| } |
| #endif |
| |
| #ifdef VOICE_STATUS_DEMO |
| static void AUDIOAPP_add_subscriber_AudioIf_VoiceStatus(struct uloop_timeout *timeout) |
| { |
| /* add subscriber for Audio_If */ |
| if (ubus_lookup_id(AUDIOAPP_UBUS_Db.ctx, VOICESTATUS_NOTIFICATION_NAME, &AUDIOAPP_UBUS_Db.audioif_subscriber_id)) |
| { |
| LOG_OUT_E("%s, Failed to look up %s\n", __FUNCTION__, VOICESTATUS_NOTIFICATION_NAME); |
| uloop_timeout_set(timeout, 2000); |
| return; |
| } |
| |
| ubus_subscribe(AUDIOAPP_UBUS_Db.ctx, &AUDIOAPP_UBUS_Db.audioif_event, AUDIOAPP_UBUS_Db.audioif_subscriber_id); |
| LOG_OUT("Audio_If subscribe %s object ok\n", VOICESTATUS_NOTIFICATION_NAME); |
| return; |
| } |
| static struct uloop_timeout AUDIOAPP_add_subscribe_timeout_AudioIf_VoiceStatus = |
| { |
| .cb = AUDIOAPP_add_subscriber_AudioIf_VoiceStatus, |
| }; |
| |
| /*******************************************************************************\ |
| * Function: AUDIOAPP_uBusInd_AudioIf_remove |
| * Description: Handle upon Audio_if remove indication. |
| * Returns: |
| \*******************************************************************************/ |
| static void AUDIOAPP_uBusInd_AudioIf_VoiceStatus_remove(struct ubus_context *ctx, struct ubus_subscriber *s, |
| uint32_t id) |
| { |
| UNUSEDPARAM(ctx); |
| UNUSEDPARAM(s); |
| UNUSEDPARAM(id); |
| |
| LOG_OUT("%s\n", __FUNCTION__); |
| uloop_timeout_set(&AUDIOAPP_add_subscribe_timeout_AudioIf_VoiceStatus, 2000); |
| } |
| |
| |
| /*******************************************************************************\ |
| * Function: AUDIOAPP_uBusInd_AudioIf |
| * Description: Handle upon Audio_If incoming indication. |
| * Returns: 0 on success |
| \*******************************************************************************/ |
| static int AUDIOAPP_uBusInd_AudioIf_VoiceStatus(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); |
| |
| int voice_status = 0;/* bit1:record; bit0:playback; */ |
| struct blob_attr *tb[1]; |
| int rc = 0; |
| |
| LOG_OUT("\n===============================================================================\n"); |
| |
| /*parsing blob to be accessed easily with tb array - parse "1" argument*/ |
| rc = blobmsg_parse(VoiceStatus_policy, 1, tb, blob_data(msg), blob_len(msg)); |
| |
| if (rc < 0) { |
| LOG_OUT_E("%s: parsing fail, rc = 0x%x\n", __FUNCTION__, rc); |
| } else { |
| voice_status = (char)blobmsg_get_u32(tb[0]); |
| LOG_OUT("%s:voice_status=%d.\n", __FUNCTION__, voice_status); |
| } |
| |
| LOG_OUT("===============================================================================\n\n"); |
| |
| return rc; |
| } |
| #endif |
| |
| static int AUDIOAPP_uBusRegisterNotifications(void) |
| { |
| int ret = 0; |
| |
| /* register UBUS notifications of RIL */ |
| ret = ubus_register_subscriber(AUDIOAPP_UBUS_Db.ctx, &AUDIOAPP_UBUS_Db.ril_ind_event); |
| if (ret) |
| { |
| LOG_OUT_E("%s Failed to add RIL watch handler: %s\n", __FUNCTION__, ubus_strerror(ret)); |
| return -1; |
| } |
| |
| /* specify callback to handle notifications */ |
| AUDIOAPP_UBUS_Db.ril_ind_event.remove_cb = AUDIOAPP_uBusInd_RIL_remove; |
| AUDIOAPP_UBUS_Db.ril_ind_event.cb = AUDIOAPP_uBusInd_RIL; |
| |
| /* add subscribe */ |
| uloop_timeout_set(&AUDIOAPP_add_subscribe_timeout_RIL, 0); |
| |
| #ifdef DTMF_CODE_DEMO |
| /* register UBUS notifications of Audio_If */ |
| ret = ubus_register_subscriber(AUDIOAPP_UBUS_Db.ctx, &AUDIOAPP_UBUS_Db.audioif_event); |
| if (ret) |
| { |
| LOG_OUT_E("%s Failed to add audio_if watch handler: %s\n", __FUNCTION__, ubus_strerror(ret)); |
| return -1; |
| } |
| |
| /* specify callback to handle notifications */ |
| AUDIOAPP_UBUS_Db.audioif_event.remove_cb = AUDIOAPP_uBusInd_AudioIf_remove; |
| AUDIOAPP_UBUS_Db.audioif_event.cb = AUDIOAPP_uBusInd_AudioIf; |
| |
| /* add subscribe */ |
| uloop_timeout_set(&AUDIOAPP_add_subscribe_timeout_AudioIf, 0); |
| #endif |
| |
| /* NOTES: The following code is demo for reporting the status of record and playback. |
| * MODEM_DTMF_DETECTION exclude with VOICE_STATUS_DEMO.If enable VOICE_STATUS_DEMO, please disable MODEM_DTMF_DETECTION. |
| */ |
| #ifdef VOICE_STATUS_DEMO |
| /* register UBUS notifications of Audio_If */ |
| ret = ubus_register_subscriber(AUDIOAPP_UBUS_Db.ctx, &AUDIOAPP_UBUS_Db.audioif_event); |
| if (ret) |
| { |
| LOG_OUT_E("%s Failed to add audio_if watch handler: %s\n", __FUNCTION__, ubus_strerror(ret)); |
| return -1; |
| } |
| |
| /* specify callback to handle notifications */ |
| AUDIOAPP_UBUS_Db.audioif_event.remove_cb = AUDIOAPP_uBusInd_AudioIf_VoiceStatus_remove; |
| AUDIOAPP_UBUS_Db.audioif_event.cb = AUDIOAPP_uBusInd_AudioIf_VoiceStatus; |
| |
| /* add subscribe */ |
| uloop_timeout_set(&AUDIOAPP_add_subscribe_timeout_AudioIf_VoiceStatus, 0); |
| #endif |
| |
| LOG_OUT("%s: Make use of DTMF detection in modem.\n", __FUNCTION__); |
| |
| return 0; |
| } |
| |
| /*******************************************************************************\ |
| * Function: AUDIOAPP_uBusInit |
| * Description: Init UBUS context and register UBUS notifications of RIL. |
| * Returns: 0 on success |
| \*******************************************************************************/ |
| static int AUDIOAPP_uBusInit(void) |
| { |
| int rc = 0; |
| |
| memset(&AUDIOAPP_UBUS_Db, 0, sizeof(AUDIOAPPUbusDb_t)); |
| |
| uloop_init(); |
| |
| AUDIOAPP_UBUS_Db.ctx = ubus_connect(NULL); |
| if (AUDIOAPP_UBUS_Db.ctx == NULL) |
| { |
| LOG_OUT_E(" %s Failed to connect to ubus\n", __FUNCTION__); |
| return -1; |
| } |
| |
| ubus_add_uloop(AUDIOAPP_UBUS_Db.ctx); |
| |
| /* lookup fail if ril is not ready */ |
| while(1) |
| { |
| rc = ubus_lookup_id(AUDIOAPP_UBUS_Db.ctx, RIL_UBUS_REQUEST_NAME, &AUDIOAPP_UBUS_Db.ril_request_id); |
| if (0 != rc) |
| { |
| LOG_OUT_E("%s, Failed to look up(%s), rc=%d\n", __FUNCTION__, RIL_UBUS_REQUEST_NAME, rc); |
| usleep(600000); //600ms |
| } |
| else |
| break; |
| } |
| LOG_OUT("%s, ubus_lookup_id(%s) OK\n", __FUNCTION__, RIL_UBUS_REQUEST_NAME); |
| |
| /* lookup fail if audio_if is not ready */ |
| while(1) |
| { |
| rc = ubus_lookup_id(AUDIOAPP_UBUS_Db.ctx, AUDIO_UBUS_REQUEST_NAME, &AUDIOAPP_UBUS_Db.audioif_request_id); |
| if (0 != rc) |
| { |
| LOG_OUT_E("%s, Failed to look up(%s), rc=%d\n", __FUNCTION__, AUDIO_UBUS_REQUEST_NAME, rc); |
| usleep(600000); //600ms |
| } |
| else |
| break; |
| } |
| LOG_OUT("%s, ubus_lookup_id(%s) OK\n", __FUNCTION__, AUDIO_UBUS_REQUEST_NAME); |
| |
| /* subscribe for RIL & audio_if notifications */ |
| if (AUDIOAPP_uBusRegisterNotifications() != 0) |
| return -1; |
| |
| #ifdef DEBUG_DTMF_CONTROL |
| AUDIOAPP_DTMFControlTimer_Init(); |
| #endif |
| |
| LOG_OUT("%s success!\n", __FUNCTION__); |
| return 0; |
| } |
| |
| |
| static void AUDIOAPP_MainLoop(void) |
| { |
| int poll_interval = 5000; /* decrease to 5ms. */ |
| |
| while(1) |
| { |
| usleep(poll_interval); |
| |
| if(g_AUDIOAPP_Modem_DTMF_Detection == TRUE) |
| { |
| //control from AUDIOAPP_uBusInd_AudioIf() when config "Software DTMF Detection" in UI. |
| LOG_OUT("----------------------------------Software_DTMF_Detection----------------------------------\n"); |
| |
| //AUDIOAPP_Handle_DTMF(g_Modem_DTMF_Detection_Char); |
| g_AUDIOAPP_Modem_DTMF_Detection = FALSE; |
| |
| LOG_OUT("-------------------------------------------------------------------------------\n\n"); |
| } |
| |
| }//While(1) |
| |
| return; |
| } |
| |
| /*******************************************************************************\ |
| * Function: AUDIOAPP_uBusRun |
| * Description: Start running of UBUS. |
| * Returns: |
| \*******************************************************************************/ |
| static void AUDIOAPP_uBusRun(void) |
| { |
| LOG_OUT("%s!\n", __FUNCTION__); |
| uloop_run(); |
| |
| /*unregister uloop*/ |
| /*thread will get here only if uloop stopped*/ |
| ubus_free(AUDIOAPP_UBUS_Db.ctx); |
| uloop_done(); |
| } |
| |
| static void AUDIOAPP_Main() |
| { |
| pthread_attr_t tattr; |
| |
| /*Create thread to poll interrupts*/ |
| pthread_attr_init(&tattr); |
| pthread_attr_setdetachstate(&tattr, PTHREAD_CREATE_DETACHED); |
| pthread_create(&AUDIOAPP_MainLoopTask, &tattr, (void *)AUDIOAPP_MainLoop, NULL); |
| |
| AUDIOAPP_uBusRun(); |
| |
| /* It will get here only if uloop stopped in AUDIOAPP_uBusRun()*/ |
| |
| //Cancel pooling thread |
| pthread_cancel(AUDIOAPP_MainLoopTask); |
| |
| //wait for the exit of AUDIOAPP_MainLoop() |
| pthread_join(AUDIOAPP_MainLoopTask, NULL); |
| |
| return; |
| } |
| |
| /*******************************************************************************\ |
| * Function: main |
| * Description: Main function of this APP. |
| * It could work with proslic or mislic at the same time, it is a demo app. |
| * Returns: 0 on success |
| \*******************************************************************************/ |
| int main (int argc ,char *argv[]) |
| { |
| UNUSEDPARAM(argc); |
| UNUSEDPARAM(argv); |
| set_service_log_tag("audioapp_demo"); |
| |
| LOG_OUT("starting audioapp_demo.\n"); |
| |
| //init global variables |
| ahw_dev_ubus = audio_hal_install(); |
| if (ahw_dev_ubus == NULL) { |
| LOG_OUT("%s: audio_hal_install failed!\n", __FUNCTION__); |
| exit (-1); |
| } |
| |
| mrvl_ahw_dev_ubus = (struct mrvl_audio_device*)ahw_dev_ubus; |
| |
| /*Init ubus server*/ |
| if(AUDIOAPP_uBusInit()) |
| return -1; |
| |
| AUDIOAPP_Main(); |
| |
| audio_hal_uninstall(); |
| return 0; |
| } |