blob: 4df1ed54886bcbfe0a8396707c8255cb24775b76 [file] [log] [blame]
/*audio_if.c*/
#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"
/*************************************************
* Defines
**************************************************/
/*************************************************
* Prototype
**************************************************/
extern void AudioIf_uBusFdAdd(int fd);
extern void AudioIf_uBusUloopRun(void);
extern int AudioIf_uBusSubscribeEvents(char isSubscribe);
extern void* audio_hal_install(void); //returning ahw_dev handler
extern void audio_hal_uninstall(void);
extern int aud_hal_set_hw_device(int audio_device);
extern void aud_hal_select_output_device(void);
extern int vcm_ctl_read(void *buffer, unsigned int bytes);
/**************************************************
* Global variables
**************************************************/
AUDIO_IF_DATABASE audioIfDb;
struct uloop_timeout timeout;
audioIfReqDb_t audioIfReqDb;
audioIfUbusDb_t audioIfUbusDb;
audio_hw_device_t *ahw_dev_ubus;
struct mrvl_audio_device *mrvl_ahw_dev_ubus;
pthread_mutex_t req_data_mutex;
pthread_mutex_t AudioIf_mutex;
pthread_mutex_t AudioIf_Ubus_mutex_play;
pthread_mutex_t AudioIf_Ubus_mutex_rec;
/* Global variables for headset detection result */
#if defined(CODEC_PM812)
//#define HS_STATUS_DEV "/sys/devices/soc.0/d4000000.apb/pxa2xx-i2c.1/i2c-1/1-0030/88pm800-headset/hs_status"
//#define HK_STATUS_DEV "/sys/devices/soc.0/d4000000.apb/pxa2xx-i2c.1/i2c-1/1-0030/88pm800-headset/hk_status"
#define HS_STATUS_DEV "/sys/devices/platform/soc/d4000000.apb/pxa2xx-i2c.1/i2c-1/1-0030/88pm800-headset/hs_status"
#define HK_STATUS_DEV "/sys/devices/platform/soc/d4000000.apb/pxa2xx-i2c.1/i2c-1/1-0030/88pm800-headset/hk_status"
#elif defined(CODEC_ALC5616)
#ifdef TARGET_mmp_asr1901_KSTR901
#define HS_STATUS_DEV "/sys/devices/platform/soc/d4000000.apb/pxa2xx-i2c.1/i2c-1/1-001b/alc5616-headset/hs_status"
#define HK_STATUS_DEV "/sys/devices/platform/soc/d4000000.apb/pxa2xx-i2c.1/i2c-1/1-001b/alc5616-headset/hk_status"
#else
#define HS_STATUS_DEV "/sys/devices/platform/soc/d4000000.apb/pxa2xx-i2c.0/i2c-0/0-001b/alc5616-headset/hs_status"
#define HK_STATUS_DEV "/sys/devices/platform/soc/d4000000.apb/pxa2xx-i2c.0/i2c-0/0-001b/alc5616-headset/hk_status"
#endif
#else
//#define HS_STATUS_DEV "/sys/devices/soc.0/d4000000.apb/pxa2xx-i2c.1/i2c-1/1-0030/88pm800-headset/hs_status"
//#define HK_STATUS_DEV "/sys/devices/soc.0/d4000000.apb/pxa2xx-i2c.1/i2c-1/1-0030/88pm800-headset/hk_status"
#define HS_STATUS_DEV "/sys/devices/platform/soc/d4000000.apb/pxa2xx-i2c.1/i2c-1/1-0030/88pm800-headset/hs_status"
#define HK_STATUS_DEV "/sys/devices/platform/soc/d4000000.apb/pxa2xx-i2c.1/i2c-1/1-0030/88pm800-headset/hk_status"
#endif
#define IOCTL_DEV "/dev/audiostub_ctl"
/* Global variables for UTL messages */
#define AudioIf_UEVENT_BUFFER_SIZE 1024
static pthread_t AudioIf_utid;
static int AudioIf_ueventfd = -1;
static utlEventHandlerId_T AudioIf_ueventHandler;
static char AudioIf_ueventBuffer[AudioIf_UEVENT_BUFFER_SIZE];
/* Global variables for DTMF Detection */
#define DTMFCODEID "dtmfcode"
#define DTMFCODE_NOTIFICATION_NAME "audioif.dtmfcode"
static struct blob_buf DTMFCodeNotify_blob;
static void AudioIf_subscribe_cb(struct ubus_context *ctx, struct ubus_object *obj)
{
UNUSEDPARAM(ctx);
UNUSEDPARAM(obj);
AUDIO_IF_LOGD("%s, Subscribers active: %s", __FUNCTION__, obj->has_subscribers?"true":"false");
}
static struct ubus_object_type DTMFCode_object_type;
static struct ubus_object DTMFCode_notify_obj = {
.name = DTMFCODE_NOTIFICATION_NAME,
.type = &DTMFCode_object_type,
.subscribe_cb = AudioIf_subscribe_cb,
};
/*----------------voice status----------------*/
extern unsigned int voice_status;/* bit1:record; bit0:playback; */
unsigned int old_voice_status = 0;/* bit1:record; bit0:playback; */
/* Global variables for voice status */
#define VOICESTATUSID "voicestatus"
#define VOICESTATUS_NOTIFICATION_NAME "audioif.voicestatus"
static struct blob_buf VoiceStatusNotify_blob;
static void AudioIf_VoiceStatus_subscribe_cb(struct ubus_context *ctx, struct ubus_object *obj)
{
UNUSEDPARAM(ctx);
UNUSEDPARAM(obj);
AUDIO_IF_LOGD("%s, Subscribers active: %s", __FUNCTION__, obj->has_subscribers?"true":"false");
}
static struct ubus_object_type VoiceStatus_object_type;
static struct ubus_object VoiceStatus_notify_obj = {
.name = VOICESTATUS_NOTIFICATION_NAME,
.type = &VoiceStatus_object_type,
.subscribe_cb = AudioIf_VoiceStatus_subscribe_cb,
};
/*******************************************************************************\
* Function: AudioIf_ReadFromDevice
* Description: This function handle events in ubus context that were sent
from audio-HAL through pipe audioIfDb.pipes_fd[1].
* Returns: void
\*******************************************************************************/
void AudioIf_ReadFromDevice(int fd)
{
// here do:
// 1. read from audioHAL: (dataLen = read(fd, inbuff, maxControlTransfer)
// 2. chheck if dataLen!= 0
// 3. handle the data and process the command
// see reference code for thi function in MBIM
int dataLen, i;
char inBuf[AUDIO_IF_AUDIO_STUB_CTRL_BUFF_MAX_LEN];
memset(inBuf, 0, sizeof(inBuf));
//Read from audio_if internal pipe driver
if ( (dataLen = read(fd, inBuf, sizeof(inBuf))) < 0 )
{
AUDIO_IF_LOGE("Error while reading from AUDIO_IF device return\n");
return;
}
AUDIO_IF_LOGD("%s: read %d bytes from socket %d", __FUNCTION__, dataLen, fd);
if (dataLen == 0)
{
AUDIO_IF_LOGD("Read Zero\n");
return;
}
//Dump the data been read
for(i = 0; i < dataLen; i++)
{
AUDIO_IF_LOGD("%s: [%d]=0x%x\n", __FUNCTION__, i, inBuf[i]);
}
}
/*******************************************************************************\
* Function: AudioIf_BroadcastDTMFCode
* Description: Broadcast DTMF code using uBus notification
* Returns: 0: success, -1: fail
\*******************************************************************************/
int AudioIf_BroadcastDTMFCode(unsigned short Code)
{
int ret =0;
blob_buf_init(&DTMFCodeNotify_blob, 0);
blobmsg_add_u32(&DTMFCodeNotify_blob, DTMFCODEID, Code);
ret = ubus_notify(audioIfUbusDb.ctx, &DTMFCode_notify_obj, DTMFCode_notify_obj.name, DTMFCodeNotify_blob.head, -1);
return ret;
}
/*******************************************************************************\
* Function: AudioIf_MainLoopTask
* Description: This function is a preparation for audio HAL usage in case
audio HAL wants to send indications/responses toward audio_if
ubus-clients.
the function that handle the input from audio HAL in ubus context is
AudioIf_ReadFromDevice()
* Returns: void
\*******************************************************************************/
void *AudioIf_MainLoopTask(void *arg)
{
UNUSEDPARAM(arg);
int dataLen, i;
int ret = 0;
int sock_fd;
char inBuf[AUDIO_IF_AUDIO_STUB_CTRL_BUFF_MAX_LEN];
struct ATCMsg *p_atc_msg = (struct ATCMsg *)inBuf;
unsigned short *p_ecall_msg;
char cmd_code, sub_cmd, cmd_type;
unsigned short DTMF_code;
unsigned short eCall_cmd;
sock_fd = audioIfDb.pipes_fd[1];
memset(inBuf, 0, sizeof(inBuf));
AUDIO_IF_LOGD("%s: returned socket fd = %d\n", __FUNCTION__, sock_fd);
/*This is a thread that listen to audioHAL input into audio_if*/
while (TRUE) {
AUDIO_IF_LOGD("%s: thread alive\n", __FUNCTION__);
//reset received buffer
memset(inBuf, 0, sizeof(inBuf));
if ( (dataLen = vcm_ctl_read(inBuf, sizeof(inBuf))) < 0 ) {
AUDIO_IF_LOGE("%s Error while reading from audio control device return\n", __FUNCTION__);
sleep(2);
continue;
}
if (dataLen == 0) {
AUDIO_IF_LOGD("%s Read Zero\n", __FUNCTION__);
sleep(2);
continue;
}
//Dump the data been read
for(i = 0; i < dataLen; i++)
{
AUDIO_IF_LOGD("%s: [%d]=0x%x\n", __FUNCTION__, i, inBuf[i]);
}
//Get header info
cmd_code = p_atc_msg->header.cmd_code; // audio is fixed as 9
sub_cmd = p_atc_msg->header.sub_cmd; // 0xa: eCall, 0xc: DTMF detection
cmd_type = p_atc_msg->header.cmd_type; // 1: confirm, 2: indication
//Check whether it is audio cmd
if(cmd_code != ATC_AUDIO_CMD) {
AUDIO_IF_LOGD("Warning: it is not audio command(%d), cmd_code=%d", ATC_AUDIO_CMD, cmd_code);
sleep(2);
continue;
}
switch (sub_cmd) {
case ATC_ECALLCTL:
//Check whether it is eCall indication
if(cmd_type != CMD_TYPE_INDICATION) {
AUDIO_IF_LOGD("Warning: it is not eCall indication(%d), cmd_type=%d", CMD_TYPE_INDICATION, cmd_type);
sleep(2);
continue;
}
p_ecall_msg = (unsigned short *) &(p_atc_msg->eCallPayload);
eCall_cmd = *(unsigned short *)p_ecall_msg;
switch(eCall_cmd){
case ACIPC_CODE_AUDIO_VCM_ECALL_DATA_GET_CNF:
audio_if_ecall_data_status_response(p_ecall_msg);
break;
case ACIPC_CODE_AUDIO_VCM_ECALL_VOICE_GET_CNF:
audio_if_ecall_voice_status_response(p_ecall_msg);
break;
default:
AUDIO_IF_LOGD("Unsupport eCall_cmd: 0x%x", eCall_cmd);
break;
}
break;
case ATC_DTMFDETECTIONCTL:
DTMF_code = p_atc_msg->DTMF_code;
AUDIO_IF_LOGD("Got DTMF code: 0x%x", DTMF_code);
ret = AudioIf_BroadcastDTMFCode(DTMF_code);
if(ret != 0)
AUDIO_IF_LOGD("%s failed to broadcast DTMF code onto uBus, ret=0x%x", __FUNCTION__, ret);
break;
default:
AUDIO_IF_LOGD("Unsupport sub_cmd: 0x%x", sub_cmd);
break;
}
AUDIO_IF_LOGD("%s: wrote %d bytes to socket %d\n", __FUNCTION__, dataLen, sock_fd);
ret = write(sock_fd, inBuf, dataLen);
};
}
int AudioIf_BroadcastVoiceStatus(unsigned int status)
{
int ret =0;
blob_buf_init(&VoiceStatusNotify_blob, 0);
blobmsg_add_u32(&VoiceStatusNotify_blob, VOICESTATUSID, status);
ret = ubus_notify(audioIfUbusDb.ctx, &VoiceStatus_notify_obj, VoiceStatus_notify_obj.name, VoiceStatusNotify_blob.head, -1);
return ret;
}
void AudioIf_report_voice_status(void)
{
if (old_voice_status != voice_status) {
AUDIO_IF_LOGD("%s:Got Voice status: %d", __FUNCTION__, voice_status);
AudioIf_BroadcastVoiceStatus(voice_status);
old_voice_status = voice_status;
}
return;
}
/***************************************************************************************\
* Function: AudioIf_HanldeHeadsetEvent
* Description: This function handles headset driver reports:
* /sys/devices/soc.0/d4000000.apb/pxa2xx-i2c.1/i2c-1/1-0030/88pm800-headset/hs_status
* /sys/devices/soc.0/d4000000.apb/pxa2xx-i2c.1/i2c-1/1-0030/88pm800-headset/hk_status
*
*
* Jack types which can be reported.(Defined in Jack.h)
* enum snd_jack_types {
* SND_JACK_HEADPHONE = 0x0001,
* SND_JACK_MICROPHONE = 0x0002,
* SND_JACK_HEADSET = SND_JACK_HEADPHONE | SND_JACK_MICROPHONE,
* SND_JACK_LINEOUT = 0x0004,
* SND_JACK_MECHANICAL = 0x0008,
* SND_JACK_VIDEOOUT = 0x0010,
* SND_JACK_AVOUT = SND_JACK_LINEOUT | SND_JACK_VIDEOOUT,
* SND_JACK_LINEIN = 0x0020,
* SND_JACK_BTN_0 = 0x4000,
* SND_JACK_BTN_1 = 0x2000,
* SND_JACK_BTN_2 = 0x1000,
* SND_JACK_BTN_3 = 0x0800,
* SND_JACK_BTN_4 = 0x0400,
* SND_JACK_BTN_5 = 0x0200,
* };
* Returns: void
\***************************************************************************************/
static void AudioIf_HanldeHeadsetEvent(void)
{
int mDev, hk_status, hs_status = 0;
char value[32]; //written as '%d'
/*************************************************************************************
* Set correct audio device in boot up phase.
* -----------------------------------------------------------------------------------
*
* In boot up phase, headset driver(88pm800-headset.c) will report headset status, using UEvent.
* But, audio_if is started later than headset driver, and miss this UEvent.
*
* So, audio_if should check the files(HK_STATUS_DEV & HS_STATUS_DEV) created by headset driver
* and set the correct audio device.
*************************************************************************************/
/* Open HK_STATUS_DEV */
mDev = open(HK_STATUS_DEV, O_RDONLY);
if (mDev < 0)
{
AUDIO_IF_LOGE("%s: Failed to open %s!err=%s\n", __FUNCTION__, HK_STATUS_DEV,strerror(errno));
}
else
{
read(mDev, &value, sizeof(value));
close(mDev);
hk_status = atoi(value);
AUDIO_IF_LOGD("%s: Success to open %s, value=%s, hk_status=%d\n", __FUNCTION__, HK_STATUS_DEV, value, hk_status);
}
/* Open HS_STATUS_DEV */
mDev = open(HS_STATUS_DEV, O_RDONLY);
if (mDev < 0)
{
AUDIO_IF_LOGE("%s: Failed to open %s!err=%s\n", __FUNCTION__, HS_STATUS_DEV,strerror(errno));
}
else
{
read(mDev, &value, sizeof(value));
close(mDev);
hs_status = atoi(value);
AUDIO_IF_LOGD("%s: Success to open %s, value=%s, hs_status=%d\n", __FUNCTION__, HS_STATUS_DEV, value, hs_status);
}
/*************************************************************************************
* Set correct audio device according to hs_status
* -----------------------------------------------------------------------------------
*
* hs_status=0, hk_status=0 ==>no headset
* hs_status=1, hk_status=0 ==>headphone(without mic)
* hs_status=3, hk_status=0 ==>headset(with mic)
*************************************************************************************/
switch (hs_status)
{
case 1:
#ifdef TARGET_mmp_asr1901_KSTR901
//For test
aud_hal_set_hw_device((int)AUDIO_DEVICE_OUT_WIRED_HEADSET);
AUDIO_IF_LOGD("%s: Set audio device = AUDIO_DEVICE_OUT_WIRED_HEADSET \n", __FUNCTION__);
#else
aud_hal_set_hw_device((int)AUDIO_DEVICE_OUT_WIRED_HEADPHONE);
AUDIO_IF_LOGD("%s: Set audio device = AUDIO_DEVICE_OUT_WIRED_HEADPHONE \n", __FUNCTION__);
#endif
break;
case 3:
aud_hal_set_hw_device((int)AUDIO_DEVICE_OUT_WIRED_HEADSET);
AUDIO_IF_LOGD("%s: Set audio device = AUDIO_DEVICE_OUT_WIRED_HEADSET \n", __FUNCTION__);
break;
case 0:
default:
/* Align with default audio device in CP audio */
aud_hal_set_hw_device((int)AUDIO_DEVICE_OUT_EARPIECE);
AUDIO_IF_LOGD("%s: Set audio device = AUDIO_DEVICE_OUT_EARPIECE \n", __FUNCTION__);
break;
}
}
/***************************************************************************************\
* Function: AudioIf_HandleDataFromUevent
* Description: This function handles Uevent
* For PM812
* len=430, online@/devices/soc.0/d4000000.apb/pxa2xx-i2c.1/i2c-1/1-0030/88pm800-headset
* len=424, add@/devices/soc.0/d4000000.apb/pxa2xx-i2c.1/i2c-1/1-0030/88pm800-headset
* len=430, remove@/devices/soc.0/d4000000.apb/pxa2xx-i2c.1/i2c-1/1-0030/88pm800-headset
* For ALC5616
* len=270, add@/devices/soc.0/d4000000.apb/pxa2xx-i2c.0/i2c-0/0-001b/alc5616-headset
* len=276, remove@/devices/soc.0/d4000000.apb/pxa2xx-i2c.0/i2c-0/0-001b/alc5616-headset
* Returns: void
\***************************************************************************************/
static int AudioIf_HandleDataFromUevent(char * buf, int buflen)
{
const char * device;
const char * action;
AUDIO_IF_LOGD("%s: len=%d, %s", __FUNCTION__, buflen, buf);
device = search_key("DRIVER", buf, buflen);
action = search_key("ACTION", buf, buflen);
#if defined(CODEC_PM812)
if(device && (!strcmp(device, "88pm800-headset")))
#elif defined(CODEC_ALC5616)
if(device && (!strcmp(device, "alc5616-headset")))
#else
if(0)
#endif
{
AUDIO_IF_LOGD("%s: device=%s, action=%s!", __FUNCTION__, device, action);
if(action && ( (!strcmp(action, "add"))||(!strcmp(action, "remove"))))
{ //headset plugged or unplugged
AudioIf_HanldeHeadsetEvent();
//Make new audio device take effect, no matter it is in call or not
pthread_mutex_lock(&AudioIf_mutex);
aud_hal_select_output_device();
pthread_mutex_unlock(&AudioIf_mutex);
}
}
return 0;
}
static utlReturnCode_T AudioIf_ReceiveDataFromUevent(const utlEventHandlerType_T handler_type,
const utlEventHandlerType_T event_type,
const int fd,
const utlRelativeTime_P2c period_p,
void *arg_p)
{
UNUSEDPARAM(handler_type)
UNUSEDPARAM(event_type)
UNUSEDPARAM(period_p)
UNUSEDPARAM(arg_p)
int ret;
ret = read(fd, AudioIf_ueventBuffer, AudioIf_UEVENT_BUFFER_SIZE);
if(ret > 0)
AudioIf_HandleDataFromUevent(AudioIf_ueventBuffer, ret);
return utlSUCCESS;
}
static int AudioIf_OpenEventLink(void)
{
while(AudioIf_ueventfd < 0)
{
AudioIf_ueventfd = open_uevent_socket();
if(AudioIf_ueventfd < 0)
AUDIO_IF_LOGD("open EventLink error:%s\n", strerror(errno));
}
AudioIf_ueventHandler = utlSetFdEventHandler(utlEVENT_HANDLER_TYPE_READ, utlEVENT_HANDLER_PRIORITY_MEDIUM, AudioIf_ueventfd, AudioIf_ReceiveDataFromUevent, NULL);
return AudioIf_ueventfd;
}
static void AudioIf_CloseEventLink(void)
{
utlDeleteEventHandler(AudioIf_ueventHandler);
close(AudioIf_ueventfd);
AudioIf_ueventfd = -1;
}
/*******************************************************************************\
* Function: AudioIf_UTLTask
* Description: This function is the main task for UTL message.
* It will firstly set correct audio device;
* AudioIf_ReceiveDataFromUevent() will handle the input from UTL socket.
* Returns: void
\*******************************************************************************/
static void AudioIf_UTLTask(void)
{
AudioIf_HanldeHeadsetEvent();
AudioIf_OpenEventLink();
if (utlEventLoop(true) != utlSUCCESS)
{
AUDIO_IF_LOGE("Event loop reports failure!!!");
AudioIf_CloseEventLink();
return;
}
}
/*******************************************************************************\
* Function: main
\*******************************************************************************/
int main(int argc, char **argv)
{
UNUSEDPARAM(argc);
UNUSEDPARAM(argv);
int ioctl_fd, err;
/* Set log tag for logcat */
set_service_log_tag("audio_if");
/* Wait until audiostub ready */
while(1)
{
ioctl_fd = open(IOCTL_DEV, O_RDONLY);
if(ioctl_fd < 0)
{
err = errno;
AUDIO_IF_LOGE("Fail to open %s:%s\n", IOCTL_DEV, strerror(err));
sleep(1);
continue;
}
else
{
AUDIO_IF_LOGD("Success to open %s\n", IOCTL_DEV);
close(ioctl_fd);
break;
}
}
/* Create mutex for Ril and headset interrupt handlers */
pthread_mutex_init(&AudioIf_mutex, NULL);
pthread_mutex_init(&AudioIf_Ubus_mutex_play, NULL);
pthread_mutex_init(&AudioIf_Ubus_mutex_rec, NULL);
/* Init ubus server */
if (AudioIf_uBusInit() != 0) {
AUDIO_IF_LOGE("%s: Init ubus server failed!", __FUNCTION__);
exit (-1);
}
/* Init global variables */
ahw_dev_ubus = audio_hal_install();
if (ahw_dev_ubus == NULL) {
AUDIO_IF_LOGE("%s: audio_hal_install failed!", __FUNCTION__);
exit (-1);
}
mrvl_ahw_dev_ubus = (struct mrvl_audio_device*)ahw_dev_ubus;
/* Init ubus subscriber */
AudioIf_uBusSubscribeEvents(TRUE);
/* Create a pipe to communicate between (1)ubus thread and (2)audio HAL listner thread */
if (pipe(audioIfDb.pipes_fd) != 0) {
AUDIO_IF_LOGE("%s: pipe failed with error %d [ %s ].", __FUNCTION__, errno, strerror(errno));
exit (-1);
}
/* Create thread to listen on Audio HAL */
pthread_create(&audioIfDb.tid, NULL, AudioIf_MainLoopTask, NULL);
/*add fd to the ubus contex. this fd is listen on audioHAL */
AudioIf_uBusFdAdd(audioIfDb.pipes_fd[0]);
/* Add notify object onto bus */
ubus_add_object(audioIfUbusDb.ctx, &DTMFCode_notify_obj);
ubus_add_object(audioIfUbusDb.ctx, &VoiceStatus_notify_obj);
/* Create thread to listen to UTL socket */
pthread_create(&AudioIf_utid, NULL, (void *)AudioIf_UTLTask, NULL);
/* Start uloop */
AudioIf_uBusUloopRun();
/* Destroy mutex */
pthread_mutex_destroy(&AudioIf_mutex);
pthread_mutex_destroy(&AudioIf_Ubus_mutex_play);
pthread_mutex_destroy(&AudioIf_Ubus_mutex_rec);
/* Unregister uloop */
/* Thread will get here only if uloop stopped */
ubus_remove_object(audioIfUbusDb.ctx, &audioIfUbusDb.server_obj);
ubus_free(audioIfUbusDb.ctx);
uloop_done();
/* Unregister subscriber */
AudioIf_uBusSubscribeEvents(FALSE);
/* Unregister server */
pthread_cancel(audioIfDb.tid);
audio_hal_uninstall();
exit(0);
}