blob: 2b9988aacfd714bd6fbc85c69f96aa474e8c4804 [file] [log] [blame]
/**
* \file mbtk_audio.c
* \brief A Documented file.
*
* Detailed description
* \Author: js.wang <js.wang@mobiletek.cn>
* \Version: 1.0.0
* \Date: 2022-03-31
*/
#include <fcntl.h>
#include <stdint.h>
#include <limits.h>
#include <termios.h>
#include <stdarg.h>
#include <dirent.h>
#include <sys/stat.h>
#include <sys/statfs.h>
#include <sys/types.h>
#include "mbtk_log.h"
#include "mbtk_type.h"
#include <libubox/blobmsg_json.h>
#include "libubus.h"
#include "mbtk_audio.h"
/******************************************************************************\
* Macros / Defines
\******************************************************************************/
#ifndef UNUSEDPARAM
#define UNUSEDPARAM(a) (void)(a)
#endif
#define AUDIO_UBUS_REQUEST_NAME "audio_if"
#define mbtk_dtmf_UBUS_NAME "proslic_uBus" //Used by wake lock
#define DTMFCODEID "dtmfcode"
#define DTMFCODE_NOTIFICATION_NAME "audioif.dtmfcode"
#define AUDIO_UBUS_VOLUME_SET "volume_set"
#define AUDIO_UBUS_VOLUME_GET "volume_status"
#define AUDIO_UBUS_MODE_SET "audio_mode_set"
#define AUDIO_UBUS_PATH_ENABLE "audio_path_enable"
#define AUDIO_UBUS_SWITCH_PCM "switch_pcm"
#define AUDIO_UBUS_DSP_SET "config_dspgain"
#define AUDIO_UBUS_LOOPBACK_EN "loopback_enable"
#define AUDIO_UBUS_LOOPBACK_DIS "loopback_disable"
#define AUDIO_UBUS_AUDIO_GAIN_SET "audio_gain_set"
#define AUDIO_UBUS_AUDIO_REG_SET "audio_reg_set"
// #define DEBUG 1
#ifdef DEBUG
#define mbtk_audio_log(...) mbtk_audio_log(__VA_ARGS__)
#else
#define mbtk_audio_log(...)
#endif
typedef enum {
PARAM_INT_POLICY_0,
PARAM_INT_POLICY_1,
PARAM_INT_POLICY_2,
PARAM_INT_POLICY_3,
PARAM_INT_POLICY_MAX,
} PARAM_INT_POLICY;
#define FAILURE -1
#define ID_RIFF 0x46464952
#define ID_WAVE 0x45564157
#define ID_FMT 0x20746d66
#define ID_DATA 0x61746164
#define FORMAT_PCM 1
struct wav_header {
uint32_t riff_id;
uint32_t riff_sz;
uint32_t riff_fmt;
uint32_t fmt_id;
uint32_t fmt_sz;
uint16_t audio_format;
uint16_t num_channels;
uint32_t sample_rate;
uint32_t byte_rate; /* sample_rate * num_channels * bps / 8 */
uint16_t block_align; /* num_channels * bps / 8 */
uint16_t bits_per_sample;
uint32_t data_id;
uint32_t data_sz;
};
const struct blobmsg_policy int_policy[] ={
[PARAM_INT_POLICY_0] = {
.name = "param0",
.type = BLOBMSG_TYPE_INT32,
},
};
const struct blobmsg_policy dtmf_code_policy[] = {
[0] = {
.name = DTMFCODEID,
.type = BLOBMSG_TYPE_INT32,
},
};
static void mbtk_dtmf_add_subscriber_AudioIf(struct uloop_timeout *timeout);
static struct uloop_timeout mbtk_dtmf_add_subscribe_timeout_AudioIf =
{
.cb = mbtk_dtmf_add_subscriber_AudioIf,
};
static struct blob_buf audio_cm_b;
pthread_mutex_t mbtk_dtmf_mutex;
int mbtk_dtmf_PMConstraintWorks;
//For UBUS listening to RILD & audio_if
struct mbtk_audio_ubus_db_t
{
pthread_t dtmf_pthread;
mbtk_dtmf_cb dtmf_cb;
mbtk_volume_cb audio_volume_get_cb;
int work_state;
struct ubus_context *ctx;
/* Audio_If */
struct ubus_subscriber audioif_event;
uint32_t audioif_subscriber_id;
uint32_t audioif_request_id;
};
static struct mbtk_audio_ubus_db_t *mbtk_audio_ubus_db = NULL;
#ifdef MBTK_YX_SUPPORT
static struct ubus_context *audio_ctx = NULL;
static uint32_t ubus_id_audio_if = 0;
#endif
static int record_fd = 0;
#define AUDIO_FILE_DIR "/data"
#define MBTK_AUD_DEMO_WAV "/data/demo.wav"
int MBTK_wav_pcm16Le_set(int fd)
{
struct wav_header hdr;
if (fd <= 0)
return -1;
memset(&hdr, 0, sizeof(struct wav_header));
hdr.riff_id = ID_RIFF;
hdr.riff_fmt = ID_WAVE;
hdr.fmt_id = ID_FMT;
hdr.fmt_sz = 16;
hdr.audio_format = FORMAT_PCM;
hdr.num_channels = 1;
hdr.sample_rate = 8000;
hdr.bits_per_sample = 16;
hdr.byte_rate = (8000 * 1 * hdr.bits_per_sample) / 8;
hdr.block_align = (hdr.bits_per_sample * 1) / 8;
hdr.data_id = ID_DATA;
hdr.data_sz = 0;
hdr.riff_sz = hdr.data_sz + 44 - 8;
if (write(fd, &hdr, sizeof(hdr)) != sizeof(hdr)) {
return -1;
}
return 0;
}
int create_audio_dir(const char *dirname)
{
DIR *p_dir;
int res = -1;
if(NULL == (p_dir = opendir((const char *)dirname)))
{
if(mkdir(dirname, 0777) == 0)
{
res = 0;
}
else
{
fprintf(stderr, "create audio dir error \n");
res = -1;
}
}
else
{
closedir(p_dir);
res = 0;
}
return res;
}
int mbtk_at_play(const char *args)
{
int fd = 0;
int play_hdl = 0;
char databuf[1024];
int size;
LOGI("%s %d", __FUNCTION__, __LINE__);
// play_hdl = Ql_AudPlayer_Open(NULL, NULL);
play_hdl = mbtk_audio_open(0, 1, 8000, NULL);
if(0 == play_hdl)
printf("Ql_AudPlayer_Open fail\n");
fd = open(MBTK_AUD_DEMO_WAV, O_RDWR);
if (fd <= 0)
{
printf("file open error\n");
goto err;
}
memset(databuf, 0, sizeof(databuf));
while(0 < (size = read(fd, databuf, sizeof(databuf))))
{
if(-1 == mbtk_audio_play_stream(play_hdl, databuf, size))
break;
}
mbtk_audio_log("aplay Stream end \n");
err:
if(fd > 0)
close(fd);
mbtk_audio_close(play_hdl);
return 0;
}
void record_cb_func(int cb_result, char* databuf, unsigned int len)
{
int rc;
if(NULL != databuf && len > 0 && record_fd > 0)
{
//for debug:save into file
rc = write(record_fd, databuf, len);
if (rc < 0) {
printf("%s: error writing to file!\n", __FUNCTION__);
} else if (rc < len) {
printf("%s: wrote less the buffer size!\n", __FUNCTION__);
}
}
}
int mbtk_at_rec(const char *args)
{
LOGI("%s %d", __FUNCTION__, __LINE__);
//hdl = Ql_AudRecorder_Open(NULL, record_cb_func);
void *record_hdl = mbtk_audio_open(1, 1, 8000, NULL);
if (record_hdl == NULL)
{
printf("AudRecorder open error\n");
return -1;
}
create_audio_dir(AUDIO_FILE_DIR);
record_fd = open(MBTK_AUD_DEMO_WAV, O_RDWR|O_CREAT|O_TRUNC, 0644);
if (record_fd <= 0)
{
printf("file open error\n");
goto err;
}
if(0 == MBTK_wav_pcm16Le_set(record_fd))// 设置格式,否则音频播放不了
{
if( 0 != mbtk_audio_record(record_hdl, record_cb_func, NULL))
{
printf("file write error\n");
close(record_fd);
record_fd = 0;
}
}
else
{
printf("arec set file header error\n");
close(record_fd);
record_fd = 0;
}
sleep(10);// 录音 10S
err:
mbtk_audio_close(record_hdl);// 关闭录音
record_hdl = NULL;
if(record_fd > 0)
{
close(record_fd);
record_fd = 0;
}
return 0;
}
static void mbtk_ubus_complete_cb(struct ubus_request *req, int rc)
{
if(NULL == mbtk_audio_ubus_db)
{
printf("mbtk_dtmf_ubus not init!\n");
return;
}
if (req)
{
free(req);
req = NULL;
}
mbtk_audio_log("%s do nothing, rc=%d\n", __FUNCTION__, rc);
LOGI("%s do nothing, rc=%d\n", __FUNCTION__, rc);
if(mbtk_audio_ubus_db->work_state)
mbtk_audio_ubus_db->work_state--;
}
/**
* @brief mbtk_audio_mode_set
*
* @details detailed description
*
* @param param
* "param0": UINT32
* typedef enum {
* AUDIO_MODE_INVALID = -2,
* AUDIO_MODE_CURRENT = -1,
* AUDIO_MODE_NORMAL = 0,
* AUDIO_MODE_RINGTONE = 1,
* AUDIO_MODE_IN_CALL = 2,
* AUDIO_MODE_IN_COMMUNICATION=3,
* AUDIO_MODE_IN_VT_CALL= 4,
* AUDIO_MODE_CNT,
* AUDIO_MODE_MAX = AUDIO_MODE_CNT-1,
* } audio_mode_
* @return return type
*/
void mbtk_audio_mode_set(int mode)
{
int rc = 0;
#ifndef MBTK_YX_SUPPORT
if(NULL == mbtk_audio_ubus_db)
{
printf("mbtk_dtmf_ubus not init!\n");
return;
}
blob_buf_init(&audio_cm_b, 0);
blobmsg_add_u32(&audio_cm_b, "param0", mode);
if ((rc = ubus_invoke(mbtk_audio_ubus_db->ctx,
mbtk_audio_ubus_db->audioif_request_id,
AUDIO_UBUS_MODE_SET,
audio_cm_b.head, NULL, NULL, 2 * 1000)) != UBUS_STATUS_OK)
{
printf("%s, ubus_invoke_async %s failed %s\n", __FUNCTION__, AUDIO_UBUS_MODE_SET, ubus_strerror(rc));
}
else
{
printf("%s: ubus_invoke_async success\n", __FUNCTION__);
}
#else
static struct ubus_context *ctx;
ctx = ubus_connect(NULL);
if (!ctx) {
printf("Failed to connect to ubus\n");
return;
}
static struct blob_buf b;
uint32_t id;
int ret;
ret = ubus_lookup_id(ctx, AUDIO_UBUS_REQUEST_NAME, &id);
if (ret) {
printf("ubus_lookup_id() fail.\n");
return ret;
}
blob_buf_init(&b, 0);
blobmsg_add_u32(&b, "param0", mode);
if((ret = ubus_invoke(ctx, id, AUDIO_UBUS_MODE_SET, b.head, NULL, NULL, 0)) != UBUS_STATUS_OK) {
printf("ubus_invoke fail:%d.\n", ret);
} else {
printf("ubus_invoke success.\n");
}
#endif
}
void mbtk_audio_path_enable(int mode)
{
int rc = 0;
#ifndef MBTK_YX_SUPPORT
if(NULL == mbtk_audio_ubus_db)
{
printf("mbtk_dtmf_ubus not init!\n");
return;
}
blob_buf_init(&audio_cm_b, 0);
blobmsg_add_u32(&audio_cm_b, "param0", mode);
if ((rc = ubus_invoke(mbtk_audio_ubus_db->ctx,
mbtk_audio_ubus_db->audioif_request_id,
AUDIO_UBUS_PATH_ENABLE,
audio_cm_b.head, NULL, NULL, 0)) != UBUS_STATUS_OK)
{
printf("%s, ubus_invoke_async %s failed %s\n", __FUNCTION__, AUDIO_UBUS_PATH_ENABLE, ubus_strerror(rc));
}
else
{
printf("%s: ubus_invoke_async success\n", __FUNCTION__);
}
#else
static struct ubus_context *ctx;
ctx = ubus_connect(NULL);
if (!ctx) {
printf("Failed to connect to ubus\n");
return;
}
static struct blob_buf b;
uint32_t id;
int ret;
ret = ubus_lookup_id(ctx, AUDIO_UBUS_REQUEST_NAME, &id);
if (ret) {
printf("ubus_lookup_id() fail.\n");
return ret;
}
blob_buf_init(&b, 0);
blobmsg_add_u32(&b, "param0", mode);
if((ret = ubus_invoke(ctx, id, AUDIO_UBUS_PATH_ENABLE, b.head, NULL, NULL, 0)) != UBUS_STATUS_OK) {
printf("ubus_invoke fail:%d.\n", ret);
} else {
printf("ubus_invoke success.\n");
}
#endif
}
/**
* @brief mbtk_audio_switch_pcm
*
* @details detailed description
*
* @param param
* "param0":UINT32 mode
* 0: Turn off MSA PCM
* 1: Turn on MSA PCM as NB PCM(i.e. 8KHz sample rate)
* 2: Turn on MSA PCM as WB PCM(i.e. 16KHz sample rate)
* @return return type
*/
void mbtk_audio_switch_pcm(int mode)
{
int rc = 0;
#ifndef MBTK_YX_SUPPORT
if(NULL == mbtk_audio_ubus_db)
{
printf("mbtk_dtmf_ubus not init!\n");
return;
}
blob_buf_init(&audio_cm_b, 0);
blobmsg_add_u32(&audio_cm_b, "param0", mode);
if ((rc = ubus_invoke(mbtk_audio_ubus_db->ctx,
mbtk_audio_ubus_db->audioif_request_id,
AUDIO_UBUS_SWITCH_PCM,
audio_cm_b.head, NULL, NULL, 0/*2 * 1000*/)) != UBUS_STATUS_OK)
{
printf("%s, ubus_invoke %s failed %s\n", __FUNCTION__, AUDIO_UBUS_SWITCH_PCM, ubus_strerror(rc));
}
else
{
printf("%s: ubus_invoke success\n", __FUNCTION__);
}
#else
static struct blob_buf b;
int ret;
if(audio_ctx == NULL || ubus_id_audio_if == 0) {
return;
}
blob_buf_init(&b, 0);
blobmsg_add_u32(&b, "param0", mode);
if((ret = ubus_invoke(audio_ctx, ubus_id_audio_if, AUDIO_UBUS_SWITCH_PCM, b.head, NULL, NULL, 2000)) != UBUS_STATUS_OK) {
printf("ubus_invoke fail:%d.\n", ret);
} else {
printf("ubus_invoke success.\n");
}
#endif
}
int mbtk_audio_dsp_set(int type, int gain)
{
LOGE("1type:%d, gain:%d\n", type, gain);
int rc = 0;
struct ubus_request *req = NULL;
if(NULL == mbtk_audio_ubus_db)
{
LOGE("mbtk_dtmf_ubus not init!\n");
return -1;
}
req = (struct ubus_request *)malloc(sizeof(struct ubus_request));
if (req == NULL)
{
LOGE("leave %s: lack of memory\n", __FUNCTION__);
return -1;
}
memset(req, 0, sizeof(struct ubus_request));
blob_buf_init(&audio_cm_b, 0);
blobmsg_add_u32(&audio_cm_b, "type", type);
blobmsg_add_u32(&audio_cm_b, "gain", gain);
if ((rc = ubus_invoke_async(mbtk_audio_ubus_db->ctx,
mbtk_audio_ubus_db->audioif_request_id,
AUDIO_UBUS_DSP_SET,
audio_cm_b.head, req)) != UBUS_STATUS_OK)
{
free(req);
LOGE("%s, ubus_invoke_async %s failed %s\n", __FUNCTION__, AUDIO_UBUS_DSP_SET, ubus_strerror(rc));
return -1;
}
else
{
LOGE("%s: ubus_invoke_async success\n", __FUNCTION__);
mbtk_audio_ubus_db->work_state++;
req->complete_cb = mbtk_ubus_complete_cb;
ubus_complete_request_async(mbtk_audio_ubus_db->ctx, req);
}
return 0;
}
/**
* @brief mbtk_audio_loopback_start
*
* @details detailed description
*
* @param param
* device: UINT32
* 0: earpiece
* 1: speaker
* 2: headset
* @return return type
*/
static void mbtk_audio_loopback_start(int device)
{
int rc = 0;
struct ubus_request *req = NULL;
if(NULL == mbtk_audio_ubus_db)
{
LOGI("mbtk_dtmf_ubus not init!\n");
return;
}
req = (struct ubus_request *)malloc(sizeof(struct ubus_request));
if (req == NULL)
{
LOGI("leave %s: lack of memory\n", __FUNCTION__);
return;
}
memset(req, 0, sizeof(struct ubus_request));
blob_buf_init(&audio_cm_b, 0);
blobmsg_add_u32(&audio_cm_b, "param0", device);
if ((rc = ubus_invoke_async(mbtk_audio_ubus_db->ctx,
mbtk_audio_ubus_db->audioif_request_id,
AUDIO_UBUS_LOOPBACK_EN,
audio_cm_b.head, req)) != UBUS_STATUS_OK)
{
free(req);
LOGI("%s, ubus_invoke_async volume get failed %s\n", __FUNCTION__, ubus_strerror(rc));
}
else
{
LOGI("%s: ubus_invoke_async success\n", __FUNCTION__);
req->complete_cb = mbtk_ubus_complete_cb;
ubus_complete_request_async(mbtk_audio_ubus_db->ctx, req);
}
}
static void mbtk_audio_loopback_stop(void)
{
int rc = 0;
if(NULL == mbtk_audio_ubus_db)
{
printf("mbtk_dtmf_ubus not init!\n");
return;
}
blob_buf_init(&audio_cm_b, 0);
if ((rc = ubus_invoke(mbtk_audio_ubus_db->ctx,
mbtk_audio_ubus_db->audioif_request_id,
AUDIO_UBUS_LOOPBACK_DIS,
audio_cm_b.head, NULL, 0, 0)) != UBUS_STATUS_OK)
{
LOGI("%s, ubus_invoke volume get failed %s\n", __FUNCTION__, ubus_strerror(rc));
}
else
{
LOGI("%s: ubus_invoke success\n", __FUNCTION__);
}
}
int mbtk_at_loopback(int type)
{
static mbtk_audio_client_handle_type audio_handle = 0;
int ret = 0;
LOGI("%s %d:%d", __FUNCTION__, __LINE__, type);
if(0 == type) // Stop
{
mbtk_audio_loopback_stop();
if(audio_handle)
{
mbtk_audio_ubus_client_deinit(audio_handle);
audio_handle = 0;
}
}
else // Start
{
if(NULL == mbtk_audio_ubus_db)
ret = mbtk_audio_ubus_client_init(&audio_handle, NULL);
if(ret)
{
return -1;
}
mbtk_audio_mode_set(0);
mbtk_audio_loopback_start(2);
}
return 0;
}
/***************************************************** \
* Retry mechanism to add subscriber for Audio_if
\*****************************************************/
static void mbtk_dtmf_add_subscriber_AudioIf(struct uloop_timeout *timeout)
{
/* add subscriber for Audio_If */
if (ubus_lookup_id(mbtk_audio_ubus_db->ctx, DTMFCODE_NOTIFICATION_NAME, &mbtk_audio_ubus_db->audioif_subscriber_id))
{
printf("%s, Failed to look up %s\n", __FUNCTION__, DTMFCODE_NOTIFICATION_NAME);
uloop_timeout_set(timeout, 2000);
return;
}
ubus_subscribe(mbtk_audio_ubus_db->ctx, &mbtk_audio_ubus_db->audioif_event, mbtk_audio_ubus_db->audioif_subscriber_id);
mbtk_audio_log("Audio_If subscribe %s object ok\n", DTMFCODE_NOTIFICATION_NAME);
return;
}
/*******************************************************************************\
* Function: mbtk_dtmf_uBus_pmConstraint
* Description: Lock/unlock system power management.
* 0: unlock
* 1: lock
* Returns:
\*******************************************************************************/
static void mbtk_dtmf_uBus_PMConstraint(int set)
{
FILE *flk;
if (mbtk_dtmf_PMConstraintWorks != 0)
return; //wake_lock unavailable or not exist. Do nothing
#ifdef PROSLIC_ENABLEFREERUN
mbtk_audio_log("%s(%d): %s\n", __FUNCTION__, set, set ? "no sleep" : "sleep after 7s");
#else
mbtk_audio_log("%s(%d): free-run is disabled, no sleep\n", __FUNCTION__, set);
#endif
/* Do Not check fopen success. It must be ok, if failed
** (for any reason) better to crash for logging and recovery
*/
flk = fopen("/sys/power/wake_lock", "w");
if(set)
{
fprintf(flk, mbtk_dtmf_UBUS_NAME);
}
else
{
#ifdef PROSLIC_ENABLEFREERUN
/* Clear constraint but with TimeOut enough
** Stay awake for (mbtk_dtmf_DIAL_TIMER + 1) seconds, wait for ringing timer expire
*/
fprintf(flk, mbtk_dtmf_UBUS_NAME " 7000000000"/*nsec*/);
#endif
}
fclose(flk);
}
/*******************************************************************************\
* Function: mbtk_dtmf_uBusInd_AudioIf_remove
* Description: Handle upon Audio_if remove indication.
* Returns:
\*******************************************************************************/
static void mbtk_dtmf_uBusInd_AudioIf_remove(struct ubus_context *ctx, struct ubus_subscriber *s,
uint32_t id)
{
UNUSEDPARAM(ctx);
UNUSEDPARAM(s);
UNUSEDPARAM(id);
mbtk_audio_log("%s\n", __FUNCTION__);
uloop_timeout_set(&mbtk_dtmf_add_subscribe_timeout_AudioIf, 2000);
}
/*******************************************************************************\
* Function: mbtk_dtmf_uBusInd_AudioIf
* Description: Handle upon Audio_If incoming indication.
* Returns: 0 on success
\*******************************************************************************/
static int mbtk_dtmf_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;
//Lock from mbtk_dtmf interrupt handler (mbtk_dtmf_MainLoop)
pthread_mutex_lock(&mbtk_dtmf_mutex);
mbtk_audio_log("==================================%s : Begin==================================\n", __FUNCTION__);
mbtk_dtmf_uBus_PMConstraint(1);
/*parsing blob to be accessed easily with tb array - parse "1" argument*/
rc = blobmsg_parse(dtmf_code_policy, 1, tb, blob_data(msg), blob_len(msg));
if (rc < 0) {
printf("%s: parsing fail, rc = 0x%x\n", __FUNCTION__, rc);
}
else {
DTMFCode = (char)blobmsg_get_u32(tb[0]);
if(mbtk_audio_ubus_db->dtmf_cb)
mbtk_audio_ubus_db->dtmf_cb(DTMFCode);
mbtk_audio_log("%s got DTMF Code: Char[%c]=ASCII[0x%x]\n", __FUNCTION__, DTMFCode, DTMFCode);
}
mbtk_dtmf_uBus_PMConstraint(0);
mbtk_audio_log("==================================%s : End==================================", __FUNCTION__);
pthread_mutex_unlock(&mbtk_dtmf_mutex);
return rc;
}
/*******************************************************************************\
* Function: mbtk_dtmf_uBusRegisterNotifications
* Description: Register UBUS notifications of RIL and Audio_If.
* Returns: 0 on success
\*******************************************************************************/
static int mbtk_dtmf_uBusRegisterNotifications(void)
{
int ret = 0;
/* register UBUS notifications of Audio_If */
ret = ubus_register_subscriber(mbtk_audio_ubus_db->ctx, &mbtk_audio_ubus_db->audioif_event);
if (ret)
{
printf("%s Failed to add audio_if watch handler: %s\n", __FUNCTION__, ubus_strerror(ret));
return -1;
}
/* specify callback to handle notifications */
mbtk_audio_ubus_db->audioif_event.remove_cb = mbtk_dtmf_uBusInd_AudioIf_remove;
mbtk_audio_ubus_db->audioif_event.cb = mbtk_dtmf_uBusInd_AudioIf;
/* add subscribe */
uloop_timeout_set(&mbtk_dtmf_add_subscribe_timeout_AudioIf, 0);
mbtk_audio_log("%s: Make use of DTMF detection in modem.\n", __FUNCTION__);
return 0;
}
void mbtk_switch_dtmf_detection_cb(struct ubus_request *req, int rc)
{
if (req)
{
free(req);
req = NULL;
}
mbtk_audio_log("%s do nothing, rc=%d\n", __FUNCTION__, rc);
}
/**
* @brief mbtk_switch_dtmf_detection
*
* @details detailed description
*
* @param param
* “param0": UINT32 onoff
* 0: disbale Tx DTMF detection
* 1: enable Tx DTMF detection
* 2: disbale Rx DTMF detection
* 3: enable Rx DTMF detection
* @return return type
*/
void mbtk_switch_dtmf_detection(unsigned short on_off, unsigned short param1,
unsigned short param2, unsigned short param3)
{
#if PCM_CTRL_OVER_VCM
vcm_DTMFDetection(on_off, param1, param2, param3);
#else
int rc = 0;
struct ubus_request *req = NULL;
if(NULL == mbtk_audio_ubus_db)
{
printf("mbtk_dtmf_ubus not init!\n");
return;
}
req = (struct ubus_request *)malloc(sizeof(struct ubus_request));
if (req == NULL)
{
printf("leave %s: lack of memory\n", __FUNCTION__);
return;
}
memset(req, 0, sizeof(struct ubus_request));
blob_buf_init(&audio_cm_b, 0);
blobmsg_add_u32(&audio_cm_b, "param0", on_off);
blobmsg_add_u32(&audio_cm_b, "param1", param1);
blobmsg_add_u32(&audio_cm_b, "param2", param2);
blobmsg_add_u32(&audio_cm_b, "param3", param3);
if ((rc = ubus_invoke_async(mbtk_audio_ubus_db->ctx, mbtk_audio_ubus_db->audioif_request_id, "dtmf_detection", audio_cm_b.head, req)) != UBUS_STATUS_OK)
{
free(req);
printf("%s, ubus_invoke dtmf_detection failed %s\n", __FUNCTION__, ubus_strerror(rc));
}
else
{
mbtk_audio_log("%s: ubus_invoke_async success\n", __FUNCTION__);
req->complete_cb = mbtk_switch_dtmf_detection_cb;
ubus_complete_request_async(mbtk_audio_ubus_db->ctx, req);
}
#endif
}
/*******************************************************************************\
* Function: mbtk_dtmf_uBusInit
* Description: Init UBUS context and register UBUS notifications of RIL.
* Returns: 0 on success
\*******************************************************************************/
int mbtk_dtmf_uBusInit(void)
{
int rc = 0;
uloop_init();
mbtk_audio_ubus_db->ctx = ubus_connect(NULL);
if (mbtk_audio_ubus_db->ctx == NULL)
{
printf(" %s Failed to connect to ubus\n", __FUNCTION__);
return -1;
}
ubus_add_uloop(mbtk_audio_ubus_db->ctx);
/* lookup fail if audio_if is not ready */
while(1)
{
rc = ubus_lookup_id(mbtk_audio_ubus_db->ctx, AUDIO_UBUS_REQUEST_NAME, &mbtk_audio_ubus_db->audioif_request_id);
if (0 != rc)
{
printf("%s, Failed to look up(%s), rc=%d\n", __FUNCTION__, AUDIO_UBUS_REQUEST_NAME, rc);
usleep(600000); //600ms
}
else
break;
}
mbtk_audio_log("%s, ubus_lookup_id(%s) OK\n", __FUNCTION__, AUDIO_UBUS_REQUEST_NAME);
/* subscribe for RIL & audio_if notifications */
if (mbtk_dtmf_uBusRegisterNotifications() != 0)
return -1;
mbtk_audio_log("%s success!\n", __FUNCTION__);
return 0;
}
/*******************************************************************************\
* Function: mbtk_dtmf_uBusRun
* Description: Start running of UBUS.
* Returns:
\*******************************************************************************/
static void mbtk_audio_ubus_thread(void* hdl)
{
pthread_detach(pthread_self());
uloop_run();
mbtk_audio_log("%s exit!\n", __FUNCTION__);
pthread_exit(NULL);
}
int mbtk_audio_ubus_client_init(mbtk_audio_client_handle_type *ph_audio, mbtk_dtmf_cb cb)
{
#ifndef MBTK_YX_SUPPORT
// Set call handle.
if(ph_audio == NULL || mbtk_audio_ubus_db != NULL)
{
printf("ARG error or has inited.");
return -1;
}
mbtk_audio_ubus_db = malloc(sizeof(struct mbtk_audio_ubus_db_t));
if(NULL == mbtk_audio_ubus_db)
{
printf("malloc memory error\n");
}
memset(mbtk_audio_ubus_db, 0, sizeof(struct mbtk_audio_ubus_db_t));
mbtk_dtmf_PMConstraintWorks = access("/sys/power/wake_lock", R_OK | W_OK);
mbtk_dtmf_uBusInit();
mbtk_audio_ubus_db->dtmf_cb = cb;
mbtk_switch_dtmf_detection(3, 50, 4, 3);
pthread_create(&mbtk_audio_ubus_db->dtmf_pthread, NULL, (void *)mbtk_audio_ubus_thread, (void *)mbtk_audio_ubus_db);
*ph_audio = mbtk_audio_ubus_db;
LOGI("%s %d:%x", __FUNCTION__, __LINE__, mbtk_audio_ubus_db);
#else
audio_ctx = ubus_connect(NULL);
if (!audio_ctx) {
printf("Failed to connect to ubus\n");
return -1;
}
int ret = ubus_lookup_id(audio_ctx, AUDIO_UBUS_REQUEST_NAME, &ubus_id_audio_if);
if (ret) {
printf("ubus_lookup_id() fail.\n");
return ret;
}
#endif
return 0;
}
int mbtk_audio_ubus_client_deinit(mbtk_audio_client_handle_type h_audio)
{
int ret;
#ifndef MBTK_YX_SUPPORT
struct mbtk_audio_ubus_db_t *audio_ubus = (struct mbtk_audio_ubus_db_t *)h_audio;
mbtk_audio_log("%s \n", __FUNCTION__);
if(h_audio == NULL || mbtk_audio_ubus_db == NULL)
{
printf("ARG error or not inited.");
return -1;
}
LOGI("%s %d:%x", __FUNCTION__, __LINE__, audio_ubus);
ret = pthread_cancel(audio_ubus->dtmf_pthread);
mbtk_audio_log("kill pthread : %d \n", ret);
pthread_join(audio_ubus->dtmf_pthread, NULL);
do{
ret = pthread_kill(audio_ubus->dtmf_pthread, 0);
mbtk_audio_log("kill pthread: %d \n", ret);
if(ret == ESRCH)
mbtk_audio_log("The specified thread does not exist or has terminated\n");
else if(ret == EINVAL)
mbtk_audio_log("Useless signal\n");
else
mbtk_audio_log("The thread exists\n");
usleep(100000);
}while(0 == ret);
LOGI("%s %d", __FUNCTION__, __LINE__);
mbtk_switch_dtmf_detection(2, 0, 0, 0);
/*unregister uloop*/
/*thread will get here only if uloop stopped*/
ubus_free(mbtk_audio_ubus_db->ctx);
uloop_done();
LOGI("%s %d", __FUNCTION__, __LINE__);
free(h_audio);
mbtk_audio_ubus_db = NULL;
#else
if(audio_ctx) {
ubus_free(audio_ctx);
audio_ctx = NULL;
}
#endif
return 0;
}
/**********************************************************************\
* Function: APP_Audio_VolumeSet
* Description: This function is called to send command into audio_if.
* unsigned int volume(0~100)
* Returns: 0 on success
\**********************************************************************/
void mbtk_audio_ubus_volume_set(unsigned int volume)
{
int rc = 0;
struct ubus_request *req = NULL;
if(NULL == mbtk_audio_ubus_db)
{
printf("mbtk_dtmf_ubus not init!\n");
return;
}
req = (struct ubus_request *)malloc(sizeof(struct ubus_request));
if (req == NULL)
{
printf("leave %s: lack of memory\n", __FUNCTION__);
return;
}
memset(req, 0, sizeof(struct ubus_request));
blob_buf_init(&audio_cm_b, 0);
blobmsg_add_u32(&audio_cm_b, "param0", volume);
if ((rc = ubus_invoke_async(mbtk_audio_ubus_db->ctx, mbtk_audio_ubus_db->audioif_request_id, AUDIO_UBUS_VOLUME_SET, audio_cm_b.head, req)) != UBUS_STATUS_OK)
{
free(req);
printf("%s, ubus_invoke_async volume set failed: %s\n", __FUNCTION__, ubus_strerror(rc));
}
else
{
mbtk_audio_log("%s: ubus_invoke_async success\n", __FUNCTION__);
req->complete_cb = mbtk_ubus_complete_cb;
ubus_complete_request_async(mbtk_audio_ubus_db->ctx, req);
}
}
#define MBTK_AUDIO_GAIN_NUM 11
void mbtk_audio_ubus_gain_set(mbtk_audio_gain_type_enum type, uint16 *gain, int gain_num)
{
int rc = 0;
struct ubus_request *req = NULL;
req = (struct ubus_request *)malloc(sizeof(struct ubus_request));
if (req == NULL)
{
printf("leave %s: lack of memory\n", __FUNCTION__);
return;
}
if((type == AUDIO_GAIN_TYPE_RX_CODECGAIN || type == AUDIO_GAIN_TYPE_RX_DSPGAIN)
&& gain_num != MBTK_AUDIO_GAIN_NUM) {
printf("gain_num error:type = %d, gain_name = %d.\n", type, gain_num);
return;
}
if((type == AUDIO_GAIN_TYPE_TX_CODECGAIN || type == AUDIO_GAIN_TYPE_TX_DSPGAIN)
&& gain_num != 1) {
printf("gain_num error:type = %d, gain_name = %d.\n", type, gain_num);
return;
}
memset(req, 0, sizeof(struct ubus_request));
blob_buf_init(&audio_cm_b, 0);
// Set RX
blobmsg_add_u16(&audio_cm_b, "volume_gain_type", type);
if(type == AUDIO_GAIN_TYPE_TX_CODECGAIN || type == AUDIO_GAIN_TYPE_TX_DSPGAIN) {
blobmsg_add_u16(&audio_cm_b, "volume_gain_0", gain[0]);
} else {
char name[20];
int i = 0;
// Set TX
for(; i < gain_num; i++) {
memset(name, 0x0, 20);
sprintf(name, "volume_gain_%d", i);
blobmsg_add_u16(&audio_cm_b, name, gain[i]);
}
}
#if 1
if ((rc = ubus_invoke_async(mbtk_audio_ubus_db->ctx, mbtk_audio_ubus_db->audioif_request_id, AUDIO_UBUS_AUDIO_GAIN_SET, audio_cm_b.head, req)) != UBUS_STATUS_OK)
{
free(req);
printf("%s, ubus_invoke_async volume set failed: %s\n", __FUNCTION__, ubus_strerror(rc));
}
else
{
printf("%s: ubus_invoke_async success\n", __FUNCTION__);
req->complete_cb = mbtk_ubus_complete_cb;
ubus_complete_request_async(mbtk_audio_ubus_db->ctx, req);
}
#else
if ((rc = ubus_invoke(APP_ctx, APP_audio_request_id, AUDIO_UBUS_AUDIO_GAIN_SET, audio_cm_b.head, NULL, 0, 0)) != UBUS_STATUS_OK)
{
printf("%s, ubus_invoke_async volume set failed: %s\n", __FUNCTION__, ubus_strerror(rc));
}
else
{
printf("%s: ubus_invoke_async success\n", __FUNCTION__);
}
free(req);
#endif
}
void mbtk_audio_ubus_reg_set(int reg_addr, int reg_value)
{
int rc = 0;
struct ubus_request *req = NULL;
req = (struct ubus_request *)malloc(sizeof(struct ubus_request));
if (req == NULL)
{
printf("leave %s: lack of memory\n", __FUNCTION__);
return;
}
memset(req, 0, sizeof(struct ubus_request));
blob_buf_init(&audio_cm_b, 0);
blobmsg_add_u32(&audio_cm_b, "reg_addr", reg_addr);
blobmsg_add_u32(&audio_cm_b, "reg_value", reg_value);
#if 1
if ((rc = ubus_invoke_async(mbtk_audio_ubus_db->ctx, mbtk_audio_ubus_db->audioif_request_id, AUDIO_UBUS_AUDIO_REG_SET, audio_cm_b.head, req)) != UBUS_STATUS_OK)
{
free(req);
printf("%s, ubus_invoke_async volume set failed: %s\n", __FUNCTION__, ubus_strerror(rc));
}
else
{
printf("%s: ubus_invoke_async success\n", __FUNCTION__);
req->complete_cb = mbtk_ubus_complete_cb;
ubus_complete_request_async(mbtk_audio_ubus_db->ctx, req);
}
#else
if ((rc = ubus_invoke(APP_ctx, APP_audio_request_id, AUDIO_UBUS_AUDIO_GAIN_SET, audio_cm_b.head, NULL, 0, 0)) != UBUS_STATUS_OK)
{
printf("%s, ubus_invoke_async volume set failed: %s\n", __FUNCTION__, ubus_strerror(rc));
}
else
{
printf("%s: ubus_invoke_async success\n", __FUNCTION__);
}
free(req);
#endif
}
static void audio_volume_get_data_cb (struct ubus_request *req, int type, struct blob_attr *msg)
{
UNUSEDPARAM(req);
UNUSEDPARAM(type);
struct blob_attr *tb[1];
unsigned int volume = 888;
int rc = 0;
rc = blobmsg_parse(int_policy, 1, tb, blob_data(msg), blob_len(msg));
if (rc < 0)
{
printf("[%s] parsing blobmsg failed\n", __FUNCTION__);
return;
}
if(tb[0])
volume = blobmsg_get_u32(tb[0]);
if (mbtk_audio_ubus_db->audio_volume_get_cb)
mbtk_audio_ubus_db->audio_volume_get_cb(volume);
mbtk_audio_log("%s; volume:%d\n", __FUNCTION__, volume);
}
void mbtk_audio_ubus_volume_get(mbtk_volume_cb cb)
{
int rc = 0;
struct ubus_request *req = NULL;
if(NULL == mbtk_audio_ubus_db || NULL == cb)
{
printf("mbtk_dtmf_ubus not init or callback invalid!\n");
return;
}
mbtk_audio_ubus_db->audio_volume_get_cb = cb;
req = (struct ubus_request *)malloc(sizeof(struct ubus_request));
if (req == NULL)
{
printf("leave %s: lack of memory\n", __FUNCTION__);
return;
}
memset(req, 0, sizeof(struct ubus_request));
blob_buf_init(&audio_cm_b, 0);
if ((rc = ubus_invoke_async(mbtk_audio_ubus_db->ctx,
mbtk_audio_ubus_db->audioif_request_id,
AUDIO_UBUS_VOLUME_GET,
audio_cm_b.head, req)) != UBUS_STATUS_OK)
{
free(req);
printf("%s, ubus_invoke_async volume get failed %s\n", __FUNCTION__, ubus_strerror(rc));
}
else
{
mbtk_audio_log("%s: ubus_invoke_async success\n", __FUNCTION__);
req->data_cb = audio_volume_get_data_cb;
req->complete_cb = mbtk_ubus_complete_cb;
ubus_complete_request_async(mbtk_audio_ubus_db->ctx, req);
}
}