blob: 76a94d0ef0d816e81da4279038542f4f338342b0 [file] [log] [blame]
#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;
}