blob: bd512b271f3825eedc11a3f50a67d5dee7f793cc [file] [log] [blame]
/******************************************************************************
*(C) Copyright 2014 Marvell International Ltd.
* All Rights Reserved
******************************************************************************/
/* -------------------------------------------------------------------------------------------------------------------
*
* Filename: audio_if_api.c
*
* Authors:
*
* Description: This file handle RIL indication and audio_if invokations
* RIL Indication are refer this file from audio_if/audio_if_ubus.c AudioIf_uBusInd_RIL()
*
* HISTORY:
*
*
*
* Notes:
*
******************************************************************************/
/******************************************************************************
* Include files
******************************************************************************/
#include "audio_if_types.h"
#include "audio_if_ubus.h"
#include "audio_if_parameter.h"
#include "audio_if.h"
#include "audio_if_api.h"
#include "audio_if_audio_hw_mrvl.h"
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include "telatparamdef_ubus.h" //Range check for input parameters
#include "voice_control.h"
/******************************************************************************
* Globals
******************************************************************************/
extern audio_hw_device_t *ahw_dev_ubus;
extern struct mrvl_audio_device *mrvl_ahw_dev_ubus;
extern const struct blobmsg_policy int_policy[];
extern const struct blobmsg_policy ecall_data_set_policy[];
extern const struct blobmsg_policy ecall_data_get_policy[];
extern const struct blobmsg_policy ecall_voice_set_policy[];
extern const struct blobmsg_policy ecall_voice_get_policy[];
extern const struct blobmsg_policy vcm_play_rec_policy[];
extern const struct blobmsg_policy cp_loopback_enable_policy[];
extern const struct blobmsg_policy vcm_config_policy[];
extern const struct blobmsg_policy config_pcm_policy[];
extern const struct blobmsg_policy config_dspgain_policy[];
extern const struct blobmsg_policy config_pcmexpert_policy[];
extern const struct blobmsg_policy vcm_dtmfcontrol_policy[];
extern const struct blobmsg_policy config_pa_policy[];
extern audioIfReqDb_t audioIfReqDb;
extern audioIfUbusDb_t audioIfUbusDb;
extern AUDIO_IF_DATABASE audioIfDb;
extern int aud_hal_set_hw_device(int dev);
extern void aud_hal_select_output_device(void);
extern int vcm_ecall(void *value);
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);
struct audio_stream_in *stream_in = NULL;
struct audio_stream_out *stream_out = NULL;
bool go_on_rec, go_on_play, go_on_pcmloopback;
unsigned int pcm_record_size = 0; //320:NB, 640:WB
unsigned int pcm_playback_size = 0; //320:NB, 640:WB
unsigned int voice_status = 0; /* bit1:record; bit0:playback; */
bool b_play_start = false;
bool b_rec_start = false;
extern pthread_mutex_t AudioIf_Ubus_mutex_play;
extern pthread_mutex_t AudioIf_Ubus_mutex_rec;
/* Hold path in a global string*/
char *gPath_playback = NULL;
char *gPath_record = NULL;
char *gPath_pcmloopback = NULL;
/******************************************************************************
** Code
******************************************************************************/
#define ECALL_STATUS_TIMEOUT 30000 //30 seconds: uBus default timeout is 30 seconds
#define audio_if_CheckRange(value, min, max, p_data2free) do{ \
if ((value) > (max)) \
{ \
AUDIO_IF_LOGD("%s: Wrong value=%d, Correct Range: %d-%d!!!", __FUNCTION__, (value), (min), (max)); \
if ((p_data2free) != NULL) \
free(p_data2free); \
return UBUS_STATUS_INVALID_ARGUMENT; \
} \
}while (0)
#ifdef TARGET_mmp_asr1901_KSTR901
typedef enum {
ADSP_PCM_NB = 0,
ADSP_PCM_WB,
ADSP_PCM_44,
ADSP_PCM_48,
ADSP_PCM_NB_ST,
ADSP_PCM_WB_ST,
ADSP_PCM_44_ST,
ADSP_PCM_48_ST,
ADSP_MP3_ID3V1,
ADSP_MP3_ID3V2
} ADSP_MUSIC_TYPE;
#endif
/****************************************************************/
/** Thread functions */
/****************************************************************/
/****************************************************************/
/** Thread functions */
/****************************************************************/
#ifdef TARGET_mmp_asr1901_KSTR901
/*******************************************************************************\
* Function: audio_if_music_playback_thread
* Description:This function will perform a playback into the HS.
* can also be played during VC.
* Due to modem limited, only support 8k/16k sample rate, mono wave file playback
* Must set vcm_configure before playback
* Returns: void
\*******************************************************************************/
static void audio_if_music_playback_thread(void *arg)
{
int rc, len, fd, frames = 0;
char buf[PCM_WB_BUF_SIZE];
char *path = (char *)arg;
struct stat st;
struct riff_wave_header riff_wave_header;
struct chunk_header chunk_header;
struct chunk_fmt chunk_fmt = { 0 };
unsigned int more_chunks = 1;
unsigned int data_sz = 0;
unsigned int type;
char cID3V2_head[10] = { 0 };
long iFrameStart = 0;
int ID3V2_size = 0;
unsigned int timeout_ms = 0;
#define ID3V1_size 128
char cID3V1[ID3V1_size] = { 0 };
/* Must set vcm_configure before playback*/
if ((pcm_playback_size != PCM_NB_BUF_SIZE) && (pcm_playback_size != PCM_WB_BUF_SIZE)) {
AUDIO_IF_LOGE("%s: Please use vcm_configure before playback!!\n", __FUNCTION__);
goto free_memory;
}
/* Check and open source file */
if (access(path, F_OK) || stat(path, &st)) {
AUDIO_IF_LOGE("%s: error reading from file %s\n", __FUNCTION__, path);
goto free_memory;
}
if (!st.st_size) {
AUDIO_IF_LOGE("%s: empty file %s\n", __FUNCTION__, path);
goto free_memory;
}
fd = open(path, O_RDONLY);
if (fd < 0) {
AUDIO_IF_LOGE("%s: error opening file %s\n", __FUNCTION__, path);
goto free_memory;
}
read(fd, &riff_wave_header, sizeof(riff_wave_header));
if ((riff_wave_header.riff_id == ID_RIFF) && (riff_wave_header.wave_id == ID_WAVE)) { //is WAV
AUDIO_IF_LOGE("It's wave.\n");
do {
read(fd, &chunk_header, sizeof(chunk_header));
switch (chunk_header.id) {
case ID_FMT:
read(fd, &chunk_fmt, sizeof(chunk_fmt));
/* If the format header is larger, skip the rest */
if (chunk_header.sz > sizeof(chunk_fmt)) {
lseek(fd, chunk_header.sz - sizeof(chunk_fmt), SEEK_CUR);
}
break;
case ID_DATA:
/* Stop looking for chunks */
more_chunks = 0;
data_sz = chunk_header.sz;
AUDIO_IF_LOGE("%s: file_size=%u, data_size=%u\n", __FUNCTION__, riff_wave_header.riff_sz, data_sz);
break;
default:
/* Unknown chunk, skip bytes */
lseek(fd, chunk_header.sz, SEEK_CUR);
}
} while (more_chunks);
if (chunk_fmt.num_channels == 0 || chunk_fmt.num_channels > 2) {
AUDIO_IF_LOGE("%s: error wave file: sample_rate=%d, num_channels=%d.\n", __FUNCTION__, chunk_fmt.sample_rate, chunk_fmt.num_channels);
close(fd);
goto free_memory;
}
switch (chunk_fmt.sample_rate) {
case 8000:
type = chunk_fmt.num_channels == 1 ? ADSP_PCM_NB : ADSP_PCM_NB_ST;
break;
case 16000:
type = chunk_fmt.num_channels == 1 ? ADSP_PCM_WB : ADSP_PCM_WB_ST;
break;
case 44100:
type = chunk_fmt.num_channels == 1 ? ADSP_PCM_44 : ADSP_PCM_44_ST;
break;
case 48000:
type = chunk_fmt.num_channels == 1 ? ADSP_PCM_48 : ADSP_PCM_48_ST;
break;
default:
AUDIO_IF_LOGE("%s: error wave file: sample_rate = %d, num_channels = %d.\n", __FUNCTION__, chunk_fmt.sample_rate, chunk_fmt.num_channels);
close(fd);
goto free_memory;
}
AUDIO_IF_LOGD("%s: success open wave file: sample_rate=%d, num_channels=%d, type=%d.\n", __FUNCTION__, chunk_fmt.sample_rate, chunk_fmt.num_channels, type);
}
else { //not WAV
lseek(fd, 0, SEEK_SET);
read(fd, cID3V2_head, 10);
if ((cID3V2_head[0] == 'I' || cID3V2_head[1] == 'i')
&& (cID3V2_head[1] == 'D' || cID3V2_head[2] == 'd')
&& cID3V2_head[2] == '3') { //is MP3 ID3v2
ID3V2_size = (cID3V2_head[6] & 0x7F) << 21
| (cID3V2_head[7] & 0x7F) << 14
| (cID3V2_head[8] & 0x7F) << 7
| ((cID3V2_head[9] & 0x7F) + 10);
AUDIO_IF_LOGE("It's mp3 id3v2, head size:0x%x.\n", ID3V2_size);
iFrameStart = ID3V2_size;
lseek(fd, iFrameStart, SEEK_SET);
type = ADSP_MP3_ID3V2;
}
else { //not MP3 ID3v2
lseek(fd, -ID3V1_size, SEEK_END);
read(fd, cID3V1, ID3V1_size);
if ((cID3V1[0] == 'T' || cID3V1[0] == 't')
&& (cID3V1[1] == 'A' || cID3V1[1] == 'a')
&& (cID3V1[2] == 'G' || cID3V1[2] == 'g')) { //is MP3 ID3v1
AUDIO_IF_LOGE("It's mp3 id3v1.\n");
lseek(fd, 0, SEEK_SET);
type = ADSP_MP3_ID3V1;
}
else { //not ALL
AUDIO_IF_LOGE("Error: '%s' is not a riff/wave/mp3 file\n", path);
close(fd);
goto free_memory;
}
}
}
vcm_config_pkttype(type);
#if 0
//yjg: adsp not ready for mp3
if (type >= ADSP_MP3_ID3V1) {
close(fd);
goto free_memory;
}
#endif
rc = ahw_dev_ubus->open_output_stream(ahw_dev_ubus, 0,
ahw_dev_ubus->get_supported_devices(ahw_dev_ubus),
AUDIO_OUTPUT_FLAG_DIRECT, NULL, &stream_out, 0);
if (rc < 0) {
AUDIO_IF_LOGE("%s: error opening output device. rc = %d\n", __FUNCTION__, rc);
goto bad_stream;
}
AUDIO_IF_LOGD("%s: starting playback %d bytes every 20ms.\n", __FUNCTION__, pcm_playback_size);
go_on_play = true;
voice_status |= 1 << 0;/* bit1:record; bit0:playback; */
AudioIf_report_voice_status();
while (go_on_play) {
/* Playback loop */
memset(buf, 0x00, sizeof(buf));
if ((riff_wave_header.riff_id == ID_RIFF) && (riff_wave_header.wave_id == ID_WAVE)) { //is WAV
len = read(fd, buf, data_sz>pcm_playback_size ? pcm_playback_size : data_sz);
}
else {
len = read(fd, buf, pcm_playback_size);
}
if (len == -1) {
AUDIO_IF_LOGE("%s: error reading from file\n", __FUNCTION__);
goto end_thread;
}
else if (len == 0) {
/* reached EOF */
AUDIO_IF_LOGD("%s: nothing to read\n", __FUNCTION__);
goto end_thread;
}
if ((riff_wave_header.riff_id == ID_RIFF) && (riff_wave_header.wave_id == ID_WAVE)) { //is WAV
if (len < (signed int)pcm_playback_size) {
printf("%s: left:%u read_len:%d is smaller than needed %d, so fill the buffer with 0.\n", __FUNCTION__, data_sz, len, pcm_playback_size);
}
data_sz-=len;
}
else {
if (len < (signed int)pcm_playback_size) {
printf("%s: len %d is smaller than needed %d, so fill the buffer with 0.\n", __FUNCTION__, len, pcm_playback_size);
}
}
rc = stream_out->write(stream_out, buf, pcm_playback_size);
if (rc < 0) {
AUDIO_IF_LOGE("%s: error writing (child)\n", __FUNCTION__);
goto end_thread;
}
else if (rc < (signed int)pcm_playback_size) {
AUDIO_IF_LOGD("%s: wrote less than buffer size, rc=%d.\n", __FUNCTION__, rc);
goto end_thread;
}
//Print here will overwrite the ddr reserved by ap/adsp, the reason is unknown
frames++;
}
end_thread:
switch (type) {
case ADSP_PCM_NB:
timeout_ms = pcm_playback_size / 16; /*256ms*/
break;
case ADSP_PCM_WB:
timeout_ms = pcm_playback_size / 32; /*128ms*/
break;
case ADSP_PCM_44:
timeout_ms = pcm_playback_size / 88; /*46ms*/
break;
case ADSP_PCM_48:
timeout_ms = pcm_playback_size / 96; /*42ms*/
break;
case ADSP_PCM_NB_ST:
timeout_ms = pcm_playback_size / 32; /*128ms*/
break;
case ADSP_PCM_WB_ST:
timeout_ms = pcm_playback_size / 64; /*64ms*/
break;
case ADSP_PCM_44_ST:
timeout_ms = pcm_playback_size / 176; /*23ms*/
break;
case ADSP_PCM_48_ST:
timeout_ms = pcm_playback_size / 192; /*21ms*/
break;
case ADSP_MP3_ID3V1:
case ADSP_MP3_ID3V2:
timeout_ms = pcm_playback_size / 16; /*256ms*/
break;
default:
AUDIO_IF_LOGD("%s: pcm_playback_size = %d, type = %d.\n", __FUNCTION__, pcm_playback_size, type);
timeout_ms = pcm_playback_size / 16; /*256ms*/
break;
}
timeout_ms += 20; //in order to cope with rounding operations
vcm_playback_drain(timeout_ms); //wait timeout_ms for drain the AP audiostub queue.
usleep(timeout_ms*4000); //delay timeout_ms until DSP play out its buffered data. Multiplying by 1000 does not guarantee.
stream_out->common.standby(&stream_out->common);
ahw_dev_ubus->close_output_stream(ahw_dev_ubus, stream_out);
go_on_play = false;
bad_stream:
if (close(fd)) {
AUDIO_IF_LOGE("%s: error closing file\n", __FUNCTION__);
}
AUDIO_IF_LOGD("%s: finished pcm playback.\n", __FUNCTION__);
b_play_start = false;
voice_status &= ~(1 << 0);/* bit1:record; bit0:playback; */
AudioIf_report_voice_status();
free_memory:
/* free path name memory */
if(gPath_playback != NULL) {
free(gPath_playback);
gPath_playback = NULL;
}
return;
}
/*******************************************************************************\
* Function: audio_if_pcm_record_thread
* Description:This fuction will record a VC or a playback from user
* and save on flash
* Due to modem limited, only support 8k/16k sample rate, mono wave file record
* Must set vcm_configure before record
* Returns: void
\*******************************************************************************/
static void audio_if_music_record_thread(void *arg)
{
int rc, len, fd;
char buffer[PCM_WB_BUF_SIZE];
char *path = (char *)arg;
unsigned int frames = 0;
struct wav_header header;
unsigned int status;
header.riff_id = ID_RIFF;
header.riff_sz = 0;
header.riff_fmt = ID_WAVE;
header.fmt_id = ID_FMT;
header.fmt_sz = 16;
header.audio_format = 1; //FORMAT_PCM;
header.num_channels = 1; //Modem ONLY support mono recording
header.sample_rate = 16000;
header.bits_per_sample = 16; //PCM_SAMPLEBITS_S16_LE;
header.byte_rate = (header.bits_per_sample / 8) * header.num_channels * header.sample_rate;
header.block_align = header.num_channels * (header.bits_per_sample / 8);
header.data_id = ID_DATA;
/* Must set vcm_configure before record*/
if ((pcm_record_size != PCM_NB_BUF_SIZE) && (pcm_record_size != PCM_WB_BUF_SIZE)) {
AUDIO_IF_LOGE("%s: Please use vcm_configure before record!!\n", __FUNCTION__);
goto free_memory;
}
fd = open(path, O_WRONLY | O_CREAT);
if (fd < 0) {
AUDIO_IF_LOGE("%s: error opening file %s\n", __FUNCTION__, path);
goto free_memory;
}
if (mrvl_ahw_dev_ubus->in_call) {
status = 1;
}
else {
status = 0;
}
vcm_config_callstatus(status);
/* leave enough room for header */
lseek(fd, sizeof(struct wav_header), SEEK_SET);
rc = ahw_dev_ubus->open_input_stream(ahw_dev_ubus, 0,
ahw_dev_ubus->get_supported_devices(ahw_dev_ubus),
NULL, &stream_in, 0, 0, AUDIO_SOURCE_VOICE_CALL);
if (rc < 0) {
AUDIO_IF_LOGE("%s: error opening input device. rc = %d\n", __FUNCTION__, rc);
goto bad_stream;
}
AUDIO_IF_LOGD("%s: starting record %d bytes every 20ms.\n", __FUNCTION__, pcm_record_size);
go_on_rec = true;
voice_status |= 1 << 1;/* bit1:record; bit0:playback; */
AudioIf_report_voice_status();
while (go_on_rec) {
/* Record loop */
len = stream_in->read(stream_in, buffer, pcm_record_size);
if (len < 0) {
AUDIO_IF_LOGE("%s: error reading\n", __FUNCTION__);
goto end_rec;
}
rc = write(fd, buffer, len);
if (rc < 0) {
AUDIO_IF_LOGE("%s: error writing to file\n", __FUNCTION__);
goto end_rec;
}
else if (rc < len) {
AUDIO_IF_LOGE("%s: wrote less the buffer size\n", __FUNCTION__);
}
AUDIO_IF_LOGD("%s: No.%d frame record\n", __FUNCTION__, frames);
frames++;
}
end_rec:
/* write header now all information is known */
header.data_sz = pcm_record_size * frames;
header.riff_sz = header.data_sz + sizeof(header) - 8;
lseek(fd, 0, SEEK_SET);
write(fd, &header, sizeof(struct wav_header));
AUDIO_IF_LOGD("%s: save wave file:%s. sample_rate = %d, num_channels = %d.\n", __FUNCTION__, path, header.sample_rate, header.num_channels);
stream_in->common.standby(&stream_in->common);
ahw_dev_ubus->close_input_stream(ahw_dev_ubus, stream_in);
go_on_rec = false;
bad_stream:
if (close(fd)) {
AUDIO_IF_LOGE("%s: error closing file\n", __FUNCTION__);
}
AUDIO_IF_LOGD("%s: finished pcm record.\n", __FUNCTION__);
b_rec_start = false;
voice_status &= ~(1 << 1);/* bit1:record; bit0:playback; */
AudioIf_report_voice_status();
free_memory:
/* free path name memory */
if(gPath_record != NULL) {
free(gPath_record);
gPath_record = NULL;
}
return;
}
#else //TARGET_mmp_asr1901_KSTR901
/*******************************************************************************\
* Function: audio_if_pcm_playback_thread
* Description:This function will perform a playback into the HS.
* can also be played during VC.
* Due to modem limited, only support 8k/16k sample rate, mono wave file playback
* Must set vcm_configure before playback
* Returns: void
\*******************************************************************************/
static void audio_if_pcm_playback_thread(void *arg)
{
int rc, len, fd, frames = 0;
char buf[PCM_WB_BUF_SIZE];
char *path = (char *)arg;
struct stat st;
struct riff_wave_header riff_wave_header;
struct chunk_header chunk_header;
struct chunk_fmt chunk_fmt = { 0 };
unsigned int more_chunks = 1;
unsigned int playback_rate = (pcm_playback_size == PCM_NB_BUF_SIZE) ? 8000 : 16000;
unsigned int data_sz = 0;
/* Must set vcm_configure before playback*/
if ((pcm_playback_size != PCM_NB_BUF_SIZE) && (pcm_playback_size != PCM_WB_BUF_SIZE)) {
AUDIO_IF_LOGE("%s: Please use vcm_configure before playback!!\n", __FUNCTION__);
goto free_memory;
}
/* Check and open source file */
if (access(path, F_OK) || stat(path, &st)) {
AUDIO_IF_LOGE("%s: error reading from file %s\n", __FUNCTION__, path);
goto free_memory;
}
if (!st.st_size) {
AUDIO_IF_LOGE("%s: empty file %s\n", __FUNCTION__, path);
goto free_memory;
}
fd = open(path, O_RDONLY);
if (fd < 0) {
AUDIO_IF_LOGE("%s: error opening file %s\n", __FUNCTION__, path);
goto free_memory;
}
read(fd, &riff_wave_header, sizeof(riff_wave_header));
if ((riff_wave_header.riff_id != ID_RIFF) || (riff_wave_header.wave_id != ID_WAVE)) {
AUDIO_IF_LOGE("Error: '%s' is not a riff/wave file\n", path);
close(fd);
goto free_memory;
}
do {
read(fd, &chunk_header, sizeof(chunk_header));
switch (chunk_header.id) {
case ID_FMT:
read(fd, &chunk_fmt, sizeof(chunk_fmt));
/* If the format header is larger, skip the rest */
if (chunk_header.sz > sizeof(chunk_fmt)) {
lseek(fd, chunk_header.sz - sizeof(chunk_fmt), SEEK_CUR);
}
break;
case ID_DATA:
/* Stop looking for chunks */
more_chunks = 0;
data_sz = chunk_header.sz;
AUDIO_IF_LOGE("%s: file_size=%u, data_size=%u\n", __FUNCTION__, riff_wave_header.riff_sz, data_sz);
break;
default:
/* Unknown chunk, skip bytes */
lseek(fd, chunk_header.sz, SEEK_CUR);
}
} while (more_chunks);
//Support 8k/16k & mono wave file
if (((chunk_fmt.sample_rate != 8000) && (chunk_fmt.sample_rate != 16000)) || (chunk_fmt.num_channels != 1) || (chunk_fmt.sample_rate != playback_rate)) {
AUDIO_IF_LOGE("%s: error wave file:sample_rate = %d, num_channels = %d; Configured playback_rate = %d!! \n", __FUNCTION__, chunk_fmt.sample_rate, chunk_fmt.num_channels, playback_rate);
close(fd);
goto free_memory;
}
else {
AUDIO_IF_LOGD("%s: success open wave file:%s, sample_rate = %d, num_channels = %d.\n", __FUNCTION__, path, chunk_fmt.sample_rate, chunk_fmt.num_channels);
}
rc = ahw_dev_ubus->open_output_stream(ahw_dev_ubus, 0,
ahw_dev_ubus->get_supported_devices(ahw_dev_ubus),
AUDIO_OUTPUT_FLAG_DIRECT, NULL, &stream_out, 0);
if (rc < 0) {
AUDIO_IF_LOGE("%s: error opening output device. rc = %d\n", __FUNCTION__, rc);
goto bad_stream;
}
AUDIO_IF_LOGD("%s: starting playback file %s, %d bytes every 20ms.\n", __FUNCTION__, path, pcm_playback_size);
go_on_play = true;
voice_status |= 1 << 0;/* bit1:record; bit0:playback; */
AudioIf_report_voice_status();
while (go_on_play) {
/* Playback loop */
memset(buf, 0x00, sizeof(buf));
len = read(fd, buf, data_sz>pcm_playback_size ? pcm_playback_size : data_sz);
if (len == -1) {
AUDIO_IF_LOGE("%s: error reading from file\n", __FUNCTION__);
goto end_thread;
}
else if (len == 0) {
/* reached EOF */
AUDIO_IF_LOGD("%s: nothing to read\n", __FUNCTION__);
goto end_thread;
}
if (len < (signed int)pcm_playback_size) {
printf("%s: left:%u read_len:%d is smaller than needed %d, so fill the buffer with 0.\n", __FUNCTION__, data_sz, len, pcm_playback_size);
}
data_sz-=len;
rc = stream_out->write(stream_out, buf, pcm_playback_size);
if (rc < 0) {
AUDIO_IF_LOGE("%s: error writing (child)\n", __FUNCTION__);
goto end_thread;
}
else if (rc < (signed int)pcm_playback_size) {
AUDIO_IF_LOGD("%s: wrote less than buffer size, rc=%d.\n", __FUNCTION__, rc);
goto end_thread;
}
AUDIO_IF_LOGD("%s: No.%d frame playback\n", __FUNCTION__, frames);
frames++;
}
end_thread:
vcm_playback_drain(80); //wait 80ms for drain the AP audiostub queue.
usleep(80000); //delay 80ms until DSP play out its buffered data.
stream_out->common.standby(&stream_out->common);
ahw_dev_ubus->close_output_stream(ahw_dev_ubus, stream_out);
go_on_play = false;
bad_stream:
if (close(fd)) {
AUDIO_IF_LOGE("%s: error closing file\n", __FUNCTION__);
}
AUDIO_IF_LOGD("%s: finished pcm playback.\n", __FUNCTION__);
b_play_start = false;
voice_status &= ~(1 << 0);/* bit1:record; bit0:playback; */
AudioIf_report_voice_status();
free_memory:
/* free path name memory */
if(gPath_playback != NULL) {
free(gPath_playback);
gPath_playback = NULL;
}
return;
}
/*******************************************************************************\
* Function: audio_if_pcm_record_thread
* Description:This fuction will record a VC or a playback from user
* and save on flash
* Due to modem limited, only support 8k/16k sample rate, mono wave file record
* Must set vcm_configure before record
* Returns: void
\*******************************************************************************/
static void audio_if_pcm_record_thread(void *arg)
{
int rc, len, fd;
char buffer[PCM_WB_BUF_SIZE];
char *path = (char *)arg;
unsigned int frames = 0;
struct wav_header header;
header.riff_id = ID_RIFF;
header.riff_sz = 0;
header.riff_fmt = ID_WAVE;
header.fmt_id = ID_FMT;
header.fmt_sz = 16;
header.audio_format = 1; //FORMAT_PCM;
header.num_channels = 1; //Modem ONLY support mono recording
header.sample_rate = (pcm_record_size == PCM_NB_BUF_SIZE ? 8000 : 16000);
header.bits_per_sample = 16; //PCM_SAMPLEBITS_S16_LE;
header.byte_rate = (header.bits_per_sample / 8) * header.num_channels * header.sample_rate;
header.block_align = header.num_channels * (header.bits_per_sample / 8);
header.data_id = ID_DATA;
/* Must set vcm_configure before record*/
if ((pcm_record_size != PCM_NB_BUF_SIZE) && (pcm_record_size != PCM_WB_BUF_SIZE)) {
AUDIO_IF_LOGE("%s: Please use vcm_configure before record!!\n", __FUNCTION__);
goto free_memory;
}
fd = open(path, O_WRONLY | O_CREAT, 0777);
if (fd < 0) {
AUDIO_IF_LOGE("%s: error opening file %s\n", __FUNCTION__, path);
goto free_memory;
}
/* leave enough room for header */
lseek(fd, sizeof(struct wav_header), SEEK_SET);
rc = ahw_dev_ubus->open_input_stream(ahw_dev_ubus, 0,
ahw_dev_ubus->get_supported_devices(ahw_dev_ubus),
NULL, &stream_in, 0, 0, AUDIO_SOURCE_VOICE_CALL);
if (rc < 0) {
AUDIO_IF_LOGE("%s: error opening input device. rc = %d\n", __FUNCTION__, rc);
goto bad_stream;
}
AUDIO_IF_LOGD("%s: starting record file %s, %d bytes every 20ms.\n", __FUNCTION__, path, pcm_record_size);
go_on_rec = true;
voice_status |= 1 << 1;/* bit1:record; bit0:playback; */
AudioIf_report_voice_status();
while (go_on_rec) {
/* Record loop */
len = stream_in->read(stream_in, buffer, pcm_record_size);
if (len < 0) {
AUDIO_IF_LOGE("%s: error reading\n", __FUNCTION__);
goto end_rec;
}
rc = write(fd, buffer, len);
if (rc < 0) {
AUDIO_IF_LOGE("%s: error writing to file\n", __FUNCTION__);
goto end_rec;
}
else if (rc < len) {
AUDIO_IF_LOGE("%s: wrote less the buffer size\n", __FUNCTION__);
}
AUDIO_IF_LOGD("%s: No.%d frame record\n", __FUNCTION__, frames);
frames++;
}
end_rec:
/* write header now all information is known */
header.data_sz = pcm_record_size * frames;
header.riff_sz = header.data_sz + sizeof(header) - 8;
lseek(fd, 0, SEEK_SET);
write(fd, &header, sizeof(struct wav_header));
AUDIO_IF_LOGD("%s: save file. sample_rate = %d, num_channels = %d.\n", __FUNCTION__, header.sample_rate, header.num_channels);
stream_in->common.standby(&stream_in->common);
ahw_dev_ubus->close_input_stream(ahw_dev_ubus, stream_in);
go_on_rec = false;
bad_stream:
if (close(fd)) {
AUDIO_IF_LOGE("%s: error closing file\n", __FUNCTION__);
}
AUDIO_IF_LOGD("%s: finished pcm record.\n", __FUNCTION__);
b_rec_start = false;
voice_status &= ~(1 << 1);/* bit1:record; bit0:playback; */
AudioIf_report_voice_status();
free_memory:
/* free path name memory */
if(gPath_record != NULL) {
free(gPath_record);
gPath_record = NULL;
}
return;
}
#endif //TARGET_mmp_asr1901_KSTR901
/*******************************************************************************\
* Function: audio_if_pcmloopback_thread
* Description:This function will playback recorded PCM into DSP
* Due to modem limited, only support 8k/16k sample rate, mono
* Must set vcm_configure before pcmloopback
* Returns: void
\*******************************************************************************/
static void audio_if_pcmloopback_thread(void *arg)
{
int rc, len, fd;
char buffer[PCM_WB_BUF_SIZE];
char *path = (char *)arg;
unsigned int frames = 0;
struct wav_header header;
header.riff_id = ID_RIFF;
header.riff_sz = 0;
header.riff_fmt = ID_WAVE;
header.fmt_id = ID_FMT;
header.fmt_sz = 16;
header.audio_format = 1; //FORMAT_PCM;
header.num_channels = 1; //Modem ONLY support mono recording
header.sample_rate = (pcm_record_size == PCM_NB_BUF_SIZE ? 8000 : 16000);
header.bits_per_sample = 16; //PCM_SAMPLEBITS_S16_LE;
header.byte_rate = (header.bits_per_sample / 8) * header.num_channels * header.sample_rate;
header.block_align = header.num_channels * (header.bits_per_sample / 8);
header.data_id = ID_DATA;
/* Must set vcm_configure before pcmloopback*/
if ((pcm_record_size != PCM_NB_BUF_SIZE) && (pcm_record_size != PCM_WB_BUF_SIZE)) {
AUDIO_IF_LOGE("%s: Please use vcm_configure to set pcm_record_size!!\n", __FUNCTION__);
goto free_memory;
}
/* Must set vcm_configure before playback*/
if ((pcm_playback_size != PCM_NB_BUF_SIZE) && (pcm_playback_size != PCM_WB_BUF_SIZE)) {
AUDIO_IF_LOGE("%s: Please use vcm_configure to set pcm_playback_size!!\n", __FUNCTION__);
goto free_memory;
}
/* Must set vcm_configure before playback*/
if (pcm_record_size != pcm_playback_size) {
AUDIO_IF_LOGE("%s: Please configure pcm_record_size = pcm_playback_size!!\n", __FUNCTION__);
goto free_memory;
}
fd = open(path, O_WRONLY | O_CREAT, 0777);
if (fd < 0) {
AUDIO_IF_LOGE("%s: error opening file %s\n", __FUNCTION__, path);
goto free_memory;
}
/* leave enough room for header */
lseek(fd, sizeof(struct wav_header), SEEK_SET);
/* open record stream */
rc = ahw_dev_ubus->open_input_stream(ahw_dev_ubus, 0,
ahw_dev_ubus->get_supported_devices(ahw_dev_ubus),
NULL, &stream_in, 0, 0, AUDIO_SOURCE_VOICE_CALL);
if (rc < 0) {
AUDIO_IF_LOGE("%s: error opening input device. rc = %d\n", __FUNCTION__, rc);
goto bad_stream;
}
/* open playback stream */
rc = ahw_dev_ubus->open_output_stream(ahw_dev_ubus, 0,
ahw_dev_ubus->get_supported_devices(ahw_dev_ubus),
AUDIO_OUTPUT_FLAG_DIRECT, NULL, &stream_out, 0);
if (rc < 0) {
AUDIO_IF_LOGE("%s: error opening output device. rc = %d\n", __FUNCTION__, rc);
goto bad_stream;
}
AUDIO_IF_LOGD("%s: starting pcmloopback file %s, %d bytes every 20ms.\n", __FUNCTION__, path, pcm_record_size);
go_on_pcmloopback = true;
while (go_on_pcmloopback) {
/* get PCM from DSP */
len = stream_in->read(stream_in, buffer, pcm_record_size);
if (len < 0) {
AUDIO_IF_LOGE("%s: error reading\n", __FUNCTION__);
goto end_pcmloopback;
}
/* save into file */
rc = write(fd, buffer, len);
if (rc < 0) {
AUDIO_IF_LOGE("%s: error writing to file\n", __FUNCTION__);
goto end_pcmloopback;
}
else if (rc < len) {
AUDIO_IF_LOGE("%s: wrote less the buffer size\n", __FUNCTION__);
}
/* send PCM into DSP */
rc = stream_out->write(stream_out, buffer, len);
if (rc < 0) {
AUDIO_IF_LOGE("%s: error writing (child)\n", __FUNCTION__);
goto end_pcmloopback;
}
else if (rc < len) {
AUDIO_IF_LOGD("%s: wrote less than buffer size\n", __FUNCTION__);
goto end_pcmloopback;
}
AUDIO_IF_LOGD("%s: No.%d frame loopback\n", __FUNCTION__, frames);
frames++;
}
end_pcmloopback:
/* write header now all information is known */
header.data_sz = pcm_record_size * frames;
header.riff_sz = header.data_sz + sizeof(header) - 8;
lseek(fd, 0, SEEK_SET);
write(fd, &header, sizeof(struct wav_header));
AUDIO_IF_LOGD("%s: save file. sample_rate = %d, num_channels = %d.\n", __FUNCTION__, header.sample_rate, header.num_channels);
stream_in->common.standby(&stream_in->common);
ahw_dev_ubus->close_input_stream(ahw_dev_ubus, stream_in);
stream_out->common.standby(&stream_out->common);
ahw_dev_ubus->close_output_stream(ahw_dev_ubus, stream_out);
go_on_pcmloopback = false;
bad_stream:
if (close(fd)) {
AUDIO_IF_LOGE("%s: error closing file\n", __FUNCTION__);
}
AUDIO_IF_LOGD("%s: finished pcm loopback.\n", __FUNCTION__);
free_memory:
/* free path name memory */
if(gPath_pcmloopback != NULL) {
free(gPath_pcmloopback);
gPath_pcmloopback = NULL;
}
return;
}
static int audio_if_StringToInt(const char *pString, int *pVal, int strLen, int strMinLen, int strMaxLen, int valMin, int valMax)
{
int count;
int val;
/* Check string length */
if ((strLen < strMinLen) || (strLen > strMaxLen)) {
return (-1);
}
/* Check string characters, first character may be plus/minus sign */
if ((!isdigit(pString[0])) && (pString[0] != '+') && (pString[0] != '-')) {
return (-2);
}
for (count = 1 ; count < strLen ; count++) {
if (!isdigit(pString[count])) {
return (-2);
}
}
/* Convert to integer */
val = atoi(pString);
/* Check integer value range */
if ((val < valMin) || (val > valMax)) {
return (-3);
}
*pVal = val;
return 0;
}
static int audio_if_HexStringToInt(const char *pString, void *pVal, int strLen, int strMinLen, int strMaxLen, int sizeBytes)
{
int count;
unsigned long val;
/* Check string length */
if ((strLen < strMinLen) || (strLen > strMaxLen)) {
return (-1);
}
/* Check string characters */
for (count = 0 ; count < strLen ; count++) {
if (!isxdigit(pString[count])) {
return (-2);
}
}
/* Convert to integer */
if (sizeBytes == 1) {
unsigned char *pChar = (unsigned char *)pVal;
for (count = 0 ; count < ((strLen + 1) >> 1) ; count++) {
if (sscanf(&pString[count << 1], "%2lx", (unsigned long *)&val) == 1) {
pChar[count] = (unsigned char)val;
}
else {
return (-3);
}
}
}
else if (sizeBytes == 2) {
unsigned short *pShort = (unsigned short *)pVal;
for (count = 0 ; count < ((strLen + 3) >> 2) ; count++) {
if (sscanf(&pString[count << 2], "%4lx", (unsigned long *)&val) == 1) {
pShort[count] = (unsigned short)val;
}
else {
return (-3);
}
}
}
else if (sizeBytes == 4) {
unsigned long *pLong = (unsigned long *)pVal;
for (count = 0 ; count < ((strLen + 7) >> 3) ; count++) {
if (sscanf(&pString[count << 3], "%8lx", (unsigned long *)&val) == 1) {
pLong[count] = (unsigned long)val;
}
else {
return (-3);
}
}
}
else {
return (-4);
}
return 0;
}
/****************************************************************
** request functions
****************************************************************/
/*******************************************************************************
* Function: audio_if_audio_mode_set
* Description: This function is called when an audio_if client invoke audio_mode method
* This method changes the audio mode: Normal/VC/VOIP/VOLTE/RING
* Returns: 0 on success
*******************************************************************************/
int audio_if_audio_mode_set(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);
struct blob_attr *tb[PARAM_1_INT];
struct blob_attr *cur;
int mode;
int rc;
/*parsing blob to be accessed easily with tb array - parse "1" argument*/
rc = blobmsg_parse(int_policy, PARAM_1_INT, tb, blob_data(msg), blob_len(msg));
if (rc < 0) {
AUDIO_IF_LOGD("%s: parsing fail\n", __FUNCTION__);
return UBUS_STATUS_INVALID_ARGUMENT;
}
cur = tb[0];
if (!cur) {
AUDIO_IF_LOGD("%s: missing parameter\n", __FUNCTION__);
return UBUS_STATUS_INVALID_ARGUMENT;
}
mode = blobmsg_get_u32(cur);
AUDIO_IF_LOGD("%s: mode=%d!", __FUNCTION__, mode);
audio_if_CheckRange(mode, TEL_AT_AUDIO_MODE_VAL_MIN, TEL_AT_AUDIO_MODE_VAL_MAX, NULL);
if (ahw_dev_ubus->set_mode(ahw_dev_ubus, mode) == 0) {
/*Set Volume after starting call just like doing in APSE (android)*/
if (mode == AUDIO_MODE_IN_CALL) {
if (ahw_dev_ubus->set_voice_volume(ahw_dev_ubus, mrvl_ahw_dev_ubus->voice_volume) != 0) {
return UBUS_STATUS_UNKNOWN_ERROR;
}
}
return UBUS_STATUS_OK;
}
else {
return UBUS_STATUS_UNKNOWN_ERROR;
}
}
/*******************************************************************************\
* Function: audio_if_audio_mode_status
* Description: This function is called when an audio_if client invoke audio_mode_status method
* This function return the current audio mode: Normal/VC/VOIP/VOLTE/RING
* Returns: 0 on success
\*******************************************************************************/
int audio_if_audio_mode_status(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(method);
UNUSEDPARAM(msg);
struct blob_buf b;
if (mrvl_ahw_dev_ubus->mode >= 0) {
unsigned int mode = mrvl_ahw_dev_ubus->mode;
memset(&b, 0, sizeof(b));
blob_buf_init(&b, 0);
blobmsg_add_u32(&b, "param0", mode);
ubus_send_reply(audioIfUbusDb.ctx, req, b.head);
blob_buf_free(&b);
return UBUS_STATUS_OK;
}
return UBUS_STATUS_UNKNOWN_ERROR;
}
/*******************************************************************************\
* Function: audio_if_audio_device_set
* Description: This function is called when an audio_if client invoke audio_device_set method
* This method changes the audio mode: earpiece/speaker/headset
* Returns: 0 on success
\*******************************************************************************/
int audio_if_audio_device_set(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);
struct blob_attr *tb[PARAM_1_INT];
struct blob_attr *cur;
unsigned int device;
int rc;
#if 0
if (mrvl_ahw_dev_ubus->mode != AUDIO_MODE_NORMAL) {
AUDIO_IF_LOGD("%s: can't switch device during call\n", __FUNCTION__);
return UBUS_STATUS_UNKNOWN_ERROR;
}
#endif
/*parsing blob to be accessed easily with tb array - parse "1" argument*/
rc = blobmsg_parse(int_policy, PARAM_1_INT, tb, blob_data(msg), blob_len(msg));
if (rc < 0) {
AUDIO_IF_LOGD("%s: parsing fail\n", __FUNCTION__);
return UBUS_STATUS_INVALID_ARGUMENT;
}
cur = tb[0];
if (!cur) {
AUDIO_IF_LOGD("%s: missing parameter\n", __FUNCTION__);
return UBUS_STATUS_INVALID_ARGUMENT;
}
device = blobmsg_get_u32(cur);
AUDIO_IF_LOGD("%s: device=%d!", __FUNCTION__, device);
audio_if_CheckRange(device, TEL_AT_AUDIO_DEVICE_VAL_MIN, TEL_AT_AUDIO_DEVICE_VAL_MAX, NULL);
switch (device) {
case 0:
aud_hal_set_hw_device((int)AUDIO_DEVICE_OUT_EARPIECE);
break;
case 1:
aud_hal_set_hw_device((int)AUDIO_DEVICE_OUT_SPEAKER);
break;
case 2:
aud_hal_set_hw_device((int)AUDIO_DEVICE_OUT_WIRED_HEADSET);
break;
default:
ALOGE("%s: Unknow device", __FUNCTION__);
return UBUS_STATUS_INVALID_ARGUMENT;
break;
}
//Make new audio device take effect, no matter it is in call or not
aud_hal_select_output_device();
return UBUS_STATUS_OK;
}
/*******************************************************************************\
* Function: audio_if_audio_device_status
* Description: This function is called when an audio_if client invoke audio_device_status method
* This function return the current audio device: earpiece/speaker/headset(0/1/2)
* Returns: 0 on success
\*******************************************************************************/
int audio_if_audio_device_status(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(method);
UNUSEDPARAM(msg);
struct blob_buf b;
if (mrvl_ahw_dev_ubus->out_device >= 1) {
unsigned int out_device = mrvl_ahw_dev_ubus->out_device >> 1;
memset(&b, 0, sizeof(b));
blob_buf_init(&b, 0);
blobmsg_add_u32(&b, "param0", out_device);
ubus_send_reply(audioIfUbusDb.ctx, req, b.head);
blob_buf_free(&b);
return UBUS_STATUS_OK;
}
return UBUS_STATUS_UNKNOWN_ERROR;
}
/*******************************************************************************\
* Function: audio_if_tty_set
* Description: This function is called when a audio_if client invoke tty_set method
* This method changes the tty mode: off/full/hco/vco
* Returns: 0 on success
\*******************************************************************************/
int audio_if_tty_set(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);
struct blob_attr *tb[PARAM_1_INT];
struct blob_attr *cur;
unsigned int tty_mode;
char kvpair[128];
int rc;
if (mrvl_ahw_dev_ubus->mode != AUDIO_MODE_NORMAL) {
AUDIO_IF_LOGD("%s: can't change tty during call\n", __FUNCTION__);
return UBUS_STATUS_UNKNOWN_ERROR;
}
/*parsing blob to be accessed easily with tb array - parse "1" argument*/
rc = blobmsg_parse(int_policy, PARAM_1_INT, tb, blob_data(msg), blob_len(msg));
if (rc < 0) {
AUDIO_IF_LOGD("%s: parsing fail\n", __FUNCTION__);
return UBUS_STATUS_INVALID_ARGUMENT;
}
cur = tb[0];
if (!cur) {
AUDIO_IF_LOGD("%s: missing parameter\n", __FUNCTION__);
return UBUS_STATUS_INVALID_ARGUMENT;
}
tty_mode = blobmsg_get_u32(cur);
memset(kvpair, 0, sizeof(kvpair));
audio_if_CheckRange(tty_mode, 0, 3, NULL);
switch (tty_mode) {
case 0: //tty off
sprintf(kvpair, "%s=%s", AUDIO_PARAMETER_KEY_TTY_MODE, AUDIO_PARAMETER_VALUE_TTY_OFF);
break;
case 1://tty full
sprintf(kvpair, "%s=%s", AUDIO_PARAMETER_KEY_TTY_MODE, AUDIO_PARAMETER_VALUE_TTY_FULL);
break;
case 2://tty HCO
sprintf(kvpair, "%s=%s", AUDIO_PARAMETER_KEY_TTY_MODE, AUDIO_PARAMETER_VALUE_TTY_HCO);
break;
case 3://tty VCO
sprintf(kvpair, "%s=%s", AUDIO_PARAMETER_KEY_TTY_MODE, AUDIO_PARAMETER_VALUE_TTY_VCO);
break;
default:
AUDIO_IF_LOGE("%s: Unknow tty_mode", __FUNCTION__);
return UBUS_STATUS_INVALID_ARGUMENT;
break;
}
ahw_dev_ubus->set_parameters(ahw_dev_ubus, kvpair);
return UBUS_STATUS_OK;
}
/*******************************************************************************\
* Function: audio_if_volume_set
* Description: This function is called when an audio_if client invoke volume_set method
* This method changes the volume: input is 0<param0<100
* Returns: 0 on success
\*******************************************************************************/
int audio_if_volume_set(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);
struct blob_attr *tb[PARAM_1_INT];
struct blob_attr *cur;
unsigned int volume = TEL_AT_AUDIO_VOL_VAL_DEFAULT;
float volume_float;
int rc;
/*parsing blob to be accessed easily with tb array - parse "1" argument*/
rc = blobmsg_parse(int_policy, PARAM_1_INT, tb, blob_data(msg), blob_len(msg));
if (rc < 0) {
AUDIO_IF_LOGD("%s: parsing fail\n", __FUNCTION__);
return UBUS_STATUS_INVALID_ARGUMENT;
}
cur = tb[0];
if (!cur) {
AUDIO_IF_LOGD("%s: missing parameter\n", __FUNCTION__);
return UBUS_STATUS_INVALID_ARGUMENT;
}
volume = blobmsg_get_u32(cur);
AUDIO_IF_LOGD("%s: volume = %d\n", __FUNCTION__, volume);
audio_if_CheckRange(volume, TEL_AT_AUDIO_VOL_VAL_MIN, TEL_AT_AUDIO_VOL_VAL_MAX, NULL);
/*set_voice_volume() is using float */
volume_float = ((float)volume / 100.0f);
if (ahw_dev_ubus->set_voice_volume(ahw_dev_ubus, volume_float) == 0) {
return UBUS_STATUS_OK;
}
else {
return UBUS_STATUS_UNKNOWN_ERROR;
}
}
/*******************************************************************************\
* Function: audio_if_volume_status
* Description: This function is called when an audio_if client invoke volume_status method
* This function return the current volume (between 0-100)
* Returns: 0 on success
\*******************************************************************************/
int audio_if_volume_status(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(method);
UNUSEDPARAM(msg);
struct blob_buf b;
unsigned int volume;
volume = (unsigned int)((mrvl_ahw_dev_ubus->voice_volume) * 100.0f);
AUDIO_IF_LOGD("%s: volume (%d)(%f)\n", __FUNCTION__, volume, mrvl_ahw_dev_ubus->voice_volume);
memset(&b, 0, sizeof(b));
blob_buf_init(&b, 0);
blobmsg_add_u32(&b, "param0", volume);
ubus_send_reply(audioIfUbusDb.ctx, req, b.head);
blob_buf_free(&b);
return UBUS_STATUS_OK;
}
/*******************************************************************************\
* Function: audio_if_mute_set
* Description: This function is called when an audio_if client invoke mute_set method
* This method set mute off/on: input is param0: 0/1
* Returns: 0 on success
\*******************************************************************************/
int audio_if_mute_set(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);
struct blob_attr *tb[PARAM_1_INT];
struct blob_attr *cur;
unsigned int mute;
bool mute_bool;
int rc;
/*parsing blob to be accessed easily with tb array - parse "1" argument*/
rc = blobmsg_parse(int_policy, PARAM_1_INT, tb, blob_data(msg), blob_len(msg));
if (rc < 0) {
AUDIO_IF_LOGD("%s: parsing fail\n", __FUNCTION__);
return UBUS_STATUS_INVALID_ARGUMENT;
}
cur = tb[0];
if (!cur) {
AUDIO_IF_LOGD("%s: missing parameter\n", __FUNCTION__);
return UBUS_STATUS_INVALID_ARGUMENT;
}
mute = blobmsg_get_u32(cur);
audio_if_CheckRange(mute, TEL_AT_AUDIO_MUTE_VAL_MIN, TEL_AT_AUDIO_MUTE_VAL_MAX, NULL);
/*set_mic_mute() is using bool */
mute_bool = ((mute == 1) ? true : false);
if (ahw_dev_ubus->set_mic_mute(ahw_dev_ubus, mute_bool) == 0) {
return UBUS_STATUS_OK;
}
else {
return UBUS_STATUS_UNKNOWN_ERROR;
}
}
/*******************************************************************************\
* Function: audio_if_mute_status
* Description: This function is called when an audio_if client invoke mute_status method
* This function return the current mute status (0- off; 1- on)
* Returns: 0 on success
\*******************************************************************************/
int audio_if_mute_status(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(method);
UNUSEDPARAM(msg);
struct blob_buf b;
bool mute_bool;
unsigned int mute;
if (ahw_dev_ubus->get_mic_mute(ahw_dev_ubus, &mute_bool) == 0) {
mute = (mute_bool == true) ? 1 : 0;
AUDIO_IF_LOGD("%s: mute (%d)\n", __FUNCTION__, mute);
memset(&b, 0, sizeof(b));
blob_buf_init(&b, 0);
blobmsg_add_u32(&b, "param0", mute);
ubus_send_reply(audioIfUbusDb.ctx, req, b.head);
blob_buf_free(&b);
return UBUS_STATUS_OK;
}
return UBUS_STATUS_INVALID_ARGUMENT;
}
/*******************************************************************************\
* Function: audio_if_ecall_data_set
* Description: This function is called when an audio_if client invoke ecall_data_set method
* Returns: 0 on success
\*******************************************************************************/
int audio_if_ecall_data_set(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);
struct blob_attr *tb[PARAM_ECALL_DATA_SET_POLICY_MAX];
struct blob_attr *cur;
unsigned int op = 0, param1;
unsigned long dataLength;
char *data;
atc_ecall_msg *p_atc_ecall_msg;
int rc;
P_ACIPC_AUDIO_VCM_ECALL_DATA_SET pEcallDataSet;
p_atc_ecall_msg = (atc_ecall_msg *)malloc(sizeof(atc_ecall_msg));
if (p_atc_ecall_msg == NULL) {
AUDIO_IF_LOGD("%s: Memory error\n", __FUNCTION__);
return UBUS_STATUS_UNKNOWN_ERROR;
}
pEcallDataSet = (P_ACIPC_AUDIO_VCM_ECALL_DATA_SET)p_atc_ecall_msg->ecall_data;
memset(p_atc_ecall_msg, 0, sizeof(atc_ecall_msg));
/*parsing blob to be accessed easily with tb array*/
rc = blobmsg_parse(ecall_data_set_policy, PARAM_ECALL_DATA_SET_POLICY_MAX, tb, blob_data(msg), blob_len(msg));
if (rc < 0) {
AUDIO_IF_LOGD("%s: parsing fail\n", __FUNCTION__);
rc = UBUS_STATUS_INVALID_ARGUMENT;
goto ECALL_END;
}
pEcallDataSet->command = (unsigned long)ACIPC_CODE_AUDIO_VCM_ECALL_DATA_SET;
/*parse 1st param*/
cur = tb[0];
if (!cur) {
AUDIO_IF_LOGD("%s: missing parameter\n", __FUNCTION__);
rc = UBUS_STATUS_INVALID_ARGUMENT;
goto ECALL_END;
}
dataLength = blobmsg_get_u32(cur);
AUDIO_IF_LOGD("%s: *****dataLength= %d\n", __FUNCTION__, (int)dataLength);// TODO remove
/* Check dataLength */
if ((dataLength != 4) && (dataLength != 8) && (dataLength != 12) && (dataLength != 148)) {
AUDIO_IF_LOGD("%s: Wrong length=%d, Correct length: 4,8,12,148!!!", __FUNCTION__, dataLength);
rc = UBUS_STATUS_INVALID_ARGUMENT;
goto ECALL_END;
}
if (dataLength >= sizeof(pEcallDataSet->op)) {
/*parse 2nd param*/
cur = tb[1];
if (!cur) {
AUDIO_IF_LOGD("%s: missing parameter\n", __FUNCTION__);
rc = UBUS_STATUS_INVALID_ARGUMENT;
goto ECALL_END;
}
op = blobmsg_get_u32(cur);
AUDIO_IF_LOGD("%s: *****op= %d\n", __FUNCTION__, (int)op); //debug
pEcallDataSet->op = (unsigned long)op;
}
else {
goto ECALL_SEND;
}
if (dataLength >= sizeof(pEcallDataSet->op) + sizeof(pEcallDataSet->param1)) {
/*parse 3rd param*/
cur = tb[2];
if (!cur) {
AUDIO_IF_LOGD("%s: missing parameter\n", __FUNCTION__);
rc = UBUS_STATUS_INVALID_ARGUMENT;
goto ECALL_END;
}
param1 = blobmsg_get_u32(cur);
AUDIO_IF_LOGD("%s: *****param1= %d\n", __FUNCTION__, (int)param1);//debug
pEcallDataSet->param1 = (unsigned long)param1;
}
else {
goto ECALL_SEND;
}
/*parse 4th param*/
if (dataLength > sizeof(pEcallDataSet->op) + sizeof(pEcallDataSet->param1)) {
cur = tb[3];
if (!cur) {
AUDIO_IF_LOGD("%s: missing parameter\n", __FUNCTION__);
rc = UBUS_STATUS_INVALID_ARGUMENT;
goto ECALL_END;
}
data = blobmsg_get_string(cur);
if (op == 5) {
/*Special for Timer op(i.e. 5): AT*ECALLDATA=5,1,#### ; here, #### use decimal format*/
audio_if_StringToInt(data, (int *)pEcallDataSet->data, strlen(data), 1, 5, 1, 65535); //range:decimal, 1 ~ 65535
//audio_if_HexStringToInt(data, pEcallDataSet->data, strlen(data), 1, 4, 2); //one short data
AUDIO_IF_LOGD("%s: *****data= %s, strlen=%d, value=%ld\n", __FUNCTION__, data, strlen(data), *(int *)(pEcallDataSet->data)); //debug
}
else {
audio_if_HexStringToInt(data, pEcallDataSet->data, strlen(data), 1, 280, 1);
AUDIO_IF_LOGD("%s: *****data= %s, strlen=%d\n", __FUNCTION__, data, strlen(data));//debug
}
}
ECALL_SEND:
audio_if_CheckRange(op, TEL_AT_ECALLDATA_OP_VAL_MIN, TEL_AT_ECALLDATA_OP_VAL_MAX, p_atc_ecall_msg);
p_atc_ecall_msg->ecall_data_len = dataLength + sizeof(pEcallDataSet->command);
if (vcm_ecall((void *)p_atc_ecall_msg)) {
rc = UBUS_STATUS_PERMISSION_DENIED;
goto ECALL_END;
}
rc = UBUS_STATUS_OK;
ECALL_END:
free(p_atc_ecall_msg);
return rc;
}
/*******************************************************************************\
* Function: audio_if_ecall_data_status_timeout
* Description: This function is called when timeout happen in ecall_data_status method
* Returns: N/A
\*******************************************************************************/
static void audio_if_ecall_data_status_timeout(struct uloop_timeout *t)
{
UNUSEDPARAM(t);
AUDIO_IF_LOGD("%s called", __FUNCTION__);
if (audioIfReqDb.occupy == 1) {
AUDIO_IF_LOGD("%s: reset occupy as 0", __FUNCTION__);
ubus_complete_deferred_request(audioIfUbusDb.ctx, &audioIfReqDb.reqdata, UBUS_STATUS_TIMEOUT);
pthread_mutex_lock(audioIfReqDb.pMutexLock);
audioIfReqDb.occupy = 0;
pthread_mutex_unlock(audioIfReqDb.pMutexLock);
}
}
/*******************************************************************************\
* Function: audio_if_ecall_data_status
* Description: This function is called when an audio_if client invoke ecall_data_status method
* Returns: 0 on success
\*******************************************************************************/
int audio_if_ecall_data_status(struct ubus_context *ctx, struct ubus_object *obj,
struct ubus_request_data *req, const char *method,
struct blob_attr *msg)
{
UNUSEDPARAM(obj);
UNUSEDPARAM(method);
struct blob_attr *tb[PARAM_ECALL_DATA_GET_POLICY_MAX];
struct blob_attr *cur;
unsigned int op, param1;
unsigned long dataLength;
P_ACIPC_AUDIO_VCM_ECALL_DATA_GET pEcallDataGet;
atc_ecall_msg *p_atc_ecall_msg;
int rc;
/* check if a defer req is currently handled*/
if (!pthread_mutex_trylock(audioIfReqDb.pMutexLock) && audioIfReqDb.occupy != 1) {
audioIfReqDb.occupy = 1;
pthread_mutex_unlock(audioIfReqDb.pMutexLock);
}
else {
AUDIO_IF_LOGD("%s: fail: audio_if is occupied\n", __FUNCTION__);
return UBUS_STATUS_PERMISSION_DENIED;
}
p_atc_ecall_msg = (atc_ecall_msg *)malloc(sizeof(atc_ecall_msg));
if (p_atc_ecall_msg == NULL) {
AUDIO_IF_LOGD("%s: Memory error\n", __FUNCTION__);
return UBUS_STATUS_UNKNOWN_ERROR;
}
memset(p_atc_ecall_msg, 0, sizeof(atc_ecall_msg));
pEcallDataGet = (P_ACIPC_AUDIO_VCM_ECALL_DATA_GET)p_atc_ecall_msg->ecall_data;
/*parsing blob to be accessed easily with tb array*/
rc = blobmsg_parse(ecall_data_get_policy, PARAM_ECALL_DATA_GET_POLICY_MAX, tb, blob_data(msg), blob_len(msg));
if (rc < 0) {
AUDIO_IF_LOGD("%s: parsing fail\n", __FUNCTION__);
pthread_mutex_lock(audioIfReqDb.pMutexLock);
audioIfReqDb.occupy = 0;
pthread_mutex_unlock(audioIfReqDb.pMutexLock);
rc = UBUS_STATUS_INVALID_ARGUMENT;
goto ECALL_END;
}
pEcallDataGet->command = (unsigned long)ACIPC_CODE_AUDIO_VCM_ECALL_DATA_GET;
/*parse 1st param*/
cur = tb[0];
if (!cur) {
AUDIO_IF_LOGD("%s: missing parameter\n", __FUNCTION__);
pthread_mutex_lock(audioIfReqDb.pMutexLock);
audioIfReqDb.occupy = 0;
pthread_mutex_unlock(audioIfReqDb.pMutexLock);
rc = UBUS_STATUS_INVALID_ARGUMENT;
goto ECALL_END;
}
dataLength = blobmsg_get_u32(cur);
AUDIO_IF_LOGD("%s: *****dataLength= %d\n", __FUNCTION__, (int)dataLength);// TODO remove
/* Check dataLength */
if ((dataLength != 4) && (dataLength != 8)) {
AUDIO_IF_LOGD("%s: Wrong length=%d, Correct length: 4 or 8!!!", __FUNCTION__, dataLength);
pthread_mutex_lock(audioIfReqDb.pMutexLock);
audioIfReqDb.occupy = 0;
pthread_mutex_unlock(audioIfReqDb.pMutexLock);
rc = UBUS_STATUS_INVALID_ARGUMENT;
goto ECALL_END;
}
/*parse 2nd param*/
cur = tb[1];
if (!cur) {
AUDIO_IF_LOGD("%s: missing parameter\n", __FUNCTION__);
pthread_mutex_lock(audioIfReqDb.pMutexLock);
audioIfReqDb.occupy = 0;
pthread_mutex_unlock(audioIfReqDb.pMutexLock);
rc = UBUS_STATUS_INVALID_ARGUMENT;
goto ECALL_END;
}
op = blobmsg_get_u32(cur);
AUDIO_IF_LOGD("%s: *****op= %d\n", __FUNCTION__, (int)op);// TODO debug
pEcallDataGet->op = (unsigned long)op;
if (dataLength > sizeof(pEcallDataGet->op)) {
/*parse 3rd param*/
cur = tb[2];
if (!cur) {
AUDIO_IF_LOGD("%s: missing parameter\n", __FUNCTION__);
pthread_mutex_lock(audioIfReqDb.pMutexLock);
audioIfReqDb.occupy = 0;
pthread_mutex_unlock(audioIfReqDb.pMutexLock);
rc = UBUS_STATUS_INVALID_ARGUMENT;
goto ECALL_END;
}
param1 = blobmsg_get_u32(cur);
AUDIO_IF_LOGD("%s: *****param1= %d\n", __FUNCTION__, (int)param1);// TODO debug
pEcallDataGet->param1 = (unsigned long)param1;
}
else {
goto ECALL_SEND;
}
/*defer request*/
ECALL_SEND:
/* Check op */
if (op > TEL_AT_ECALLDATA_OP_VAL_MAX) {
AUDIO_IF_LOGD("%s: Wrong op=%d, Correct Range: %d-%d!!!", __FUNCTION__, op, TEL_AT_ECALLDATA_OP_VAL_MIN, TEL_AT_ECALLDATA_OP_VAL_MAX);
pthread_mutex_lock(audioIfReqDb.pMutexLock);
audioIfReqDb.occupy = 0;
pthread_mutex_unlock(audioIfReqDb.pMutexLock);
rc = UBUS_STATUS_INVALID_ARGUMENT;
goto ECALL_END;
}
ubus_defer_request(ctx, req, &audioIfReqDb.reqdata);
audioIfReqDb.timeout.cb = audio_if_ecall_data_status_timeout;
uloop_timeout_set(&audioIfReqDb.timeout, ECALL_STATUS_TIMEOUT);
p_atc_ecall_msg->ecall_data_len = (unsigned long)sizeof(ACIPC_AUDIO_VCM_ECALL_DATA_GET);
if (vcm_ecall((void *)p_atc_ecall_msg)) {
AUDIO_IF_LOGD("%s: ioctl failed\n", __FUNCTION__); // TODO debug
ubus_complete_deferred_request(audioIfUbusDb.ctx, &audioIfReqDb.reqdata, UBUS_STATUS_PERMISSION_DENIED);
pthread_mutex_lock(audioIfReqDb.pMutexLock);
audioIfReqDb.occupy = 0;
pthread_mutex_unlock(audioIfReqDb.pMutexLock);
rc = UBUS_STATUS_PERMISSION_DENIED;
goto ECALL_END;
}
rc = UBUS_STATUS_OK;
ECALL_END:
free(p_atc_ecall_msg);
return rc;
}
/*******************************************************************************\
* Function: audio_if_ecall_voice_set
* Description: This function is called when an audio_if client invoke ecall_voice_set method
* Returns: 0 on success
\*******************************************************************************/
int audio_if_ecall_voice_set(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);
struct blob_attr *tb[PARAM_ECALL_VOICE_SET_POLICY_MAX];
struct blob_attr *cur;
unsigned long cmd_id, res_id, param2;
atc_ecall_msg *p_atc_ecall_msg;
int rc;
P_ACIPC_AUDIO_VCM_ECALL_VOICE_SET pEcallVoiceSet;
p_atc_ecall_msg = (atc_ecall_msg *)malloc(sizeof(atc_ecall_msg));
if (p_atc_ecall_msg == NULL) {
AUDIO_IF_LOGD("%s: Memory error\n", __FUNCTION__);
return UBUS_STATUS_UNKNOWN_ERROR;
}
pEcallVoiceSet = (P_ACIPC_AUDIO_VCM_ECALL_VOICE_SET)p_atc_ecall_msg->ecall_data;
memset(p_atc_ecall_msg, 0, sizeof(atc_ecall_msg));
/*parsing blob to be accessed easily with tb array*/
rc = blobmsg_parse(ecall_voice_set_policy, PARAM_ECALL_VOICE_SET_POLICY_MAX, tb, blob_data(msg), blob_len(msg));
if (rc < 0) {
AUDIO_IF_LOGD("%s: parsing fail\n", __FUNCTION__);
rc = UBUS_STATUS_INVALID_ARGUMENT;
goto ECALL_END;
}
/*parse 1st param*/
cur = tb[0];
if (!cur) {
AUDIO_IF_LOGD("%s: missing parameter\n", __FUNCTION__);
rc = UBUS_STATUS_INVALID_ARGUMENT;
goto ECALL_END;
}
cmd_id = blobmsg_get_u32(cur);
/*parse 2nd param*/
cur = tb[1];
if (!cur) {
AUDIO_IF_LOGD("%s: missing parameter\n", __FUNCTION__);
rc = UBUS_STATUS_INVALID_ARGUMENT;
goto ECALL_END;
}
res_id = blobmsg_get_u32(cur);
/*parse 3rd param*/
cur = tb[2];
if (!cur) {
AUDIO_IF_LOGD("%s: missing parameter\n", __FUNCTION__);
rc = UBUS_STATUS_INVALID_ARGUMENT;
goto ECALL_END;
}
param2 = blobmsg_get_u32(cur);
audio_if_CheckRange(cmd_id, TEL_AT_ECALLVOICE_CMDID_VAL_MIN, TEL_AT_ECALLVOICE_CMDID_VAL_MAX, p_atc_ecall_msg);
audio_if_CheckRange(res_id, TEL_AT_ECALLVOICE_RESID_VAL_MIN, TEL_AT_ECALLVOICE_RESID_VAL_MAX, p_atc_ecall_msg);
audio_if_CheckRange(param2, TEL_AT_ECALLVOICE_PARAM2_VAL_MIN, TEL_AT_ECALLVOICE_PARAM2_VAL_MAX, p_atc_ecall_msg);
/*build msg*/
pEcallVoiceSet->command = (unsigned long)ACIPC_CODE_AUDIO_VCM_ECALL_VOICE_SET;
pEcallVoiceSet->cmd_id = (unsigned long)cmd_id;
pEcallVoiceSet->res_id = (unsigned long)res_id;
pEcallVoiceSet->param2 = (unsigned long)param2;
p_atc_ecall_msg->ecall_data_len = (unsigned long)sizeof(ACIPC_AUDIO_VCM_ECALL_VOICE_SET);
if (vcm_ecall((void *)p_atc_ecall_msg)) {
rc = UBUS_STATUS_PERMISSION_DENIED;
goto ECALL_END;
}
rc = UBUS_STATUS_OK;
ECALL_END:
free(p_atc_ecall_msg);
return rc;
}
/*******************************************************************************\
* Function: audio_if_ecall_voice_status_timeout
* Description: This function is called when timeout happen in ecall_voice_status method
* Returns: N/A
\*******************************************************************************/
static void audio_if_ecall_voice_status_timeout(struct uloop_timeout *t)
{
UNUSEDPARAM(t);
AUDIO_IF_LOGD("%s called", __FUNCTION__);
if (audioIfReqDb.occupy == 1) {
AUDIO_IF_LOGD("%s: reset occupy as 0", __FUNCTION__);
ubus_complete_deferred_request(audioIfUbusDb.ctx, &audioIfReqDb.reqdata, UBUS_STATUS_TIMEOUT);
pthread_mutex_lock(audioIfReqDb.pMutexLock);
audioIfReqDb.occupy = 0;
pthread_mutex_unlock(audioIfReqDb.pMutexLock);
}
}
/*******************************************************************************\
* Function: audio_if_ecall_voice_status
* Description: This function is called when an audio_if client invoke ecall_voice_status method
* Returns: 0 on success
\*******************************************************************************/
int audio_if_ecall_voice_status(struct ubus_context *ctx, struct ubus_object *obj,
struct ubus_request_data *req, const char *method,
struct blob_attr *msg)
{
UNUSEDPARAM(obj);
UNUSEDPARAM(method);
struct blob_attr *tb[PARAM_ECALL_VOICE_GET_POLICY_MAX];
struct blob_attr *cur;
unsigned long cmd_id, res_id;
P_ACIPC_AUDIO_VCM_ECALL_VOICE_GET pEcallVoiceGet;
atc_ecall_msg *p_atc_ecall_msg;
int rc;
/* check if a defer req is currently handled*/
if (!pthread_mutex_trylock(audioIfReqDb.pMutexLock) && audioIfReqDb.occupy != 1) {
audioIfReqDb.occupy = 1;
pthread_mutex_unlock(audioIfReqDb.pMutexLock);
}
else {
AUDIO_IF_LOGD("%s: fail: audio_if is occupied\n", __FUNCTION__);
return UBUS_STATUS_PERMISSION_DENIED;
}
p_atc_ecall_msg = (atc_ecall_msg *)malloc(sizeof(atc_ecall_msg));
if (p_atc_ecall_msg == NULL) {
AUDIO_IF_LOGD("%s: Memory error\n", __FUNCTION__);
return UBUS_STATUS_UNKNOWN_ERROR;
}
memset(p_atc_ecall_msg, 0, sizeof(atc_ecall_msg));
pEcallVoiceGet = (P_ACIPC_AUDIO_VCM_ECALL_VOICE_GET)p_atc_ecall_msg->ecall_data;
/*parsing blob to be accessed easily with tb array*/
rc = blobmsg_parse(ecall_voice_get_policy, PARAM_ECALL_VOICE_GET_POLICY_MAX, tb, blob_data(msg), blob_len(msg));
if (rc < 0) {
AUDIO_IF_LOGD("%s: parsing fail\n", __FUNCTION__);
pthread_mutex_lock(audioIfReqDb.pMutexLock);
audioIfReqDb.occupy = 0;
pthread_mutex_unlock(audioIfReqDb.pMutexLock);
rc = UBUS_STATUS_INVALID_ARGUMENT;
goto ECALL_END;
}
/*parse 1st param*/
cur = tb[0];
if (!cur) {
AUDIO_IF_LOGD("%s: missing parameter\n", __FUNCTION__);
pthread_mutex_lock(audioIfReqDb.pMutexLock);
audioIfReqDb.occupy = 0;
pthread_mutex_unlock(audioIfReqDb.pMutexLock);
rc = UBUS_STATUS_INVALID_ARGUMENT;
goto ECALL_END;
}
cmd_id = blobmsg_get_u32(cur);
AUDIO_IF_LOGD("%s: *****cmd_id= %d\n", __FUNCTION__, (int)cmd_id);//debug
/*parse 2nd param*/
cur = tb[1];
if (!cur) {
AUDIO_IF_LOGD("%s: missing parameter\n", __FUNCTION__);
pthread_mutex_lock(audioIfReqDb.pMutexLock);
audioIfReqDb.occupy = 0;
pthread_mutex_unlock(audioIfReqDb.pMutexLock);
rc = UBUS_STATUS_INVALID_ARGUMENT;
goto ECALL_END;
}
res_id = blobmsg_get_u32(cur);
AUDIO_IF_LOGD("%s: *****res_id= %d\n", __FUNCTION__, (int)res_id);//debug
/* Check cmd_id */
if (cmd_id > TEL_AT_ECALLVOICE_CMDID_VAL_MAX) {
AUDIO_IF_LOGD("%s: Wrong cmd_id=%d, Correct Range: %d-%d!!!", __FUNCTION__, cmd_id, TEL_AT_ECALLVOICE_CMDID_VAL_MIN, TEL_AT_ECALLVOICE_CMDID_VAL_MAX);
pthread_mutex_lock(audioIfReqDb.pMutexLock);
audioIfReqDb.occupy = 0;
pthread_mutex_unlock(audioIfReqDb.pMutexLock);
rc = UBUS_STATUS_INVALID_ARGUMENT;
goto ECALL_END;
}
/* Check res_id */
if (res_id > TEL_AT_ECALLVOICE_RESID_VAL_MAX) {
AUDIO_IF_LOGD("%s: Wrong res_id=%d, Correct Range: %d-%d!!!", __FUNCTION__, res_id, TEL_AT_ECALLVOICE_RESID_VAL_MIN, TEL_AT_ECALLVOICE_RESID_VAL_MAX);
pthread_mutex_lock(audioIfReqDb.pMutexLock);
audioIfReqDb.occupy = 0;
pthread_mutex_unlock(audioIfReqDb.pMutexLock);
rc = UBUS_STATUS_INVALID_ARGUMENT;
goto ECALL_END;
}
/*defer request*/
ubus_defer_request(ctx, req, &audioIfReqDb.reqdata);
audioIfReqDb.timeout.cb = audio_if_ecall_voice_status_timeout;
uloop_timeout_set(&audioIfReqDb.timeout, ECALL_STATUS_TIMEOUT);
/*build msg*/
pEcallVoiceGet->command = (unsigned long)ACIPC_CODE_AUDIO_VCM_ECALL_VOICE_GET;
pEcallVoiceGet->cmd_id = (unsigned long)cmd_id;
pEcallVoiceGet->res_id = (unsigned long)res_id;
p_atc_ecall_msg->ecall_data_len = (unsigned long)sizeof(ACIPC_AUDIO_VCM_ECALL_VOICE_GET);
if (vcm_ecall((void *)p_atc_ecall_msg)) {
AUDIO_IF_LOGD("%s: ioctl failed\n", __FUNCTION__); // TODO debug
ubus_complete_deferred_request(audioIfUbusDb.ctx, &audioIfReqDb.reqdata, UBUS_STATUS_PERMISSION_DENIED);
pthread_mutex_lock(audioIfReqDb.pMutexLock);
audioIfReqDb.occupy = 0;
pthread_mutex_unlock(audioIfReqDb.pMutexLock);
rc = UBUS_STATUS_PERMISSION_DENIED;
goto ECALL_END;
}
rc = UBUS_STATUS_OK;
ECALL_END:
free(p_atc_ecall_msg);
return rc;
}
/*******************************************************************************\
* Function: audio_if_pcm_read_test
* Description: This function will launch a thread to record from an
* on-going VC to flash
* Returns: 0 on success
\*******************************************************************************/
int audio_if_vcm_rec_start(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);
struct blob_attr *tb[PARAM_VCM_CONFIG_POLICY_MAX];
struct blob_attr *cur;
int rc = UBUS_STATUS_OK;
pthread_t thread;
char *path;
pthread_mutex_lock(&AudioIf_Ubus_mutex_rec);
if (b_rec_start) {
AUDIO_IF_LOGD("%s: playback or record is ongoing.\n", __FUNCTION__);
rc = UBUS_STATUS_PERMISSION_DENIED;
pthread_mutex_unlock(&AudioIf_Ubus_mutex_rec);
return rc;
}
b_rec_start = true;
/*parsing blob to be accessed easily with tb array*/
rc = blobmsg_parse(vcm_play_rec_policy, PARAM_VCM_PLAY_REC_POLICY_MAX, tb, blob_data(msg), blob_len(msg));
if (rc < 0) {
AUDIO_IF_LOGD("%s: parsing fail\n", __FUNCTION__);
rc = UBUS_STATUS_INVALID_ARGUMENT;
pthread_mutex_unlock(&AudioIf_Ubus_mutex_rec);
return rc;
}
/*parse param*/
cur = tb[0];
if (!cur) {
AUDIO_IF_LOGD("%s: missing parameter\n", __FUNCTION__);
rc = UBUS_STATUS_INVALID_ARGUMENT;
pthread_mutex_unlock(&AudioIf_Ubus_mutex_rec);
return rc;
}
path = blobmsg_get_string(cur);
AUDIO_IF_LOGD("%s: got %s\n", __FUNCTION__, path);
/* malloc new memory */
gPath_record = malloc(strlen(path) + 1); /* ending with /0 */
memset(gPath_record, 0x00, strlen(path) + 1);
if(gPath_record == NULL) {
AUDIO_IF_LOGE("%s: error malloc\n", __FUNCTION__);
rc = UBUS_STATUS_UNKNOWN_ERROR;
pthread_mutex_unlock(&AudioIf_Ubus_mutex_rec);
return rc;
}
else {
memcpy(gPath_record, path, strlen(path));
}
#ifdef TARGET_mmp_asr1901_KSTR901
rc = pthread_create(&thread, NULL, (void *)&audio_if_music_record_thread, (void *)gPath_record);
#else
rc = pthread_create(&thread, NULL, (void *)&audio_if_pcm_record_thread, (void *)gPath_record);
#endif
if (rc < 0) {
AUDIO_IF_LOGE("%s: error creating read thread\n", __FUNCTION__);
rc = UBUS_STATUS_PERMISSION_DENIED;
}
pthread_detach(thread);
pthread_mutex_unlock(&AudioIf_Ubus_mutex_rec);
AUDIO_IF_LOGD("%s: launched record thread\n", __FUNCTION__);
return rc;
}
/*******************************************************************************\
* Function: audio_if_pcm_stop_read_test
* Description: This function will stop the thread recording started
* by audio_if_pcm_stop_read_test()
* Returns: always 0 for success
\*******************************************************************************/
int audio_if_vcm_rec_stop(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);
UNUSEDPARAM(msg);
int i = 0;
go_on_rec = false;
/* free path name memory */
if(gPath_record != NULL) {
free(gPath_record);
gPath_record = NULL;
}
while (0 != voice_status) {
AUDIO_IF_LOGD("%s: playback or record is ongoing.\n", __FUNCTION__);
if (i > 10) {
AUDIO_IF_LOGD("%s: i=%d. Please check voice_status.\n", __FUNCTION__, i);
break;
} else {
AUDIO_IF_LOGD("%s: i=%d.\n", __FUNCTION__, i);
}
i++;
usleep(80000); //delay 80ms
}
b_rec_start = false;
AUDIO_IF_LOGD("%s: stop signal sent\n", __FUNCTION__);
return UBUS_STATUS_OK;
}
/*******************************************************************************\
* Function: audio_if_pcm_write_test
* Description: This function will launch a thread to play from an
* a file to HP. can be used with audio_if_pcm_read_test()
* to perform loopback.
* Returns: 0 on success
\*******************************************************************************/
int audio_if_vcm_play_start(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);
struct blob_attr *tb[PARAM_VCM_CONFIG_POLICY_MAX];
struct blob_attr *cur;
int rc = UBUS_STATUS_OK;
pthread_t thread;
char *path;
pthread_mutex_lock(&AudioIf_Ubus_mutex_play);
if (b_play_start) {
AUDIO_IF_LOGD("%s: playback or record is ongoing.\n", __FUNCTION__);
rc = UBUS_STATUS_PERMISSION_DENIED;
pthread_mutex_unlock(&AudioIf_Ubus_mutex_play);
return rc;
}
b_play_start = true;
/*parsing blob to be accessed easily with tb array*/
rc = blobmsg_parse(vcm_play_rec_policy, PARAM_VCM_PLAY_REC_POLICY_MAX, tb, blob_data(msg), blob_len(msg));
if (rc < 0) {
AUDIO_IF_LOGD("%s: parsing fail\n", __FUNCTION__);
rc = UBUS_STATUS_INVALID_ARGUMENT;
pthread_mutex_unlock(&AudioIf_Ubus_mutex_play);
return rc;
}
/*parse param*/
cur = tb[0];
if (!cur) {
AUDIO_IF_LOGD("%s: missing parameter\n", __FUNCTION__);
rc = UBUS_STATUS_INVALID_ARGUMENT;
pthread_mutex_unlock(&AudioIf_Ubus_mutex_play);
return rc;
}
path = blobmsg_get_string(cur);
AUDIO_IF_LOGD("%s: got %s\n", __FUNCTION__, path);
/* malloc new memory */
gPath_playback = malloc(strlen(path) + 1); /* ending with /0 */
memset(gPath_playback, 0x00, strlen(path) + 1);
if(gPath_playback == NULL) {
AUDIO_IF_LOGE("%s: error malloc\n", __FUNCTION__);
rc = UBUS_STATUS_UNKNOWN_ERROR;
pthread_mutex_unlock(&AudioIf_Ubus_mutex_play);
return rc;
}
else {
memcpy(gPath_playback, path, strlen(path));
}
#ifdef TARGET_mmp_asr1901_KSTR901
rc = pthread_create(&thread, NULL, (void *)&audio_if_music_playback_thread, (void *)gPath_playback);
#else
rc = pthread_create(&thread, NULL, (void *)&audio_if_pcm_playback_thread, (void *)gPath_playback);
#endif
if (rc < 0) {
AUDIO_IF_LOGE("%s: error creating write thread\n", __FUNCTION__);
rc = UBUS_STATUS_PERMISSION_DENIED;
}
pthread_detach(thread);
pthread_mutex_unlock(&AudioIf_Ubus_mutex_play);
AUDIO_IF_LOGD("%s: launched playback thread\n", __FUNCTION__);
return rc;
}
/*******************************************************************************\
* Function: audio_if_pcm_stop_write_test
* Description: This function will stop the thread playback started
* by audio_if_pcm_write_test()
* Returns: always 0 for success
\*******************************************************************************/
int audio_if_vcm_play_stop(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);
UNUSEDPARAM(msg);
int i = 0;
go_on_play = false;
/* free path name memory */
if(gPath_playback != NULL) {
free(gPath_playback);
gPath_playback = NULL;
}
while (0 != voice_status) {
AUDIO_IF_LOGD("%s: playback or record is ongoing.\n", __FUNCTION__);
if (i > 10) {
AUDIO_IF_LOGD("%s: i=%d. Please check voice_status.\n", __FUNCTION__, i);
break;
} else {
AUDIO_IF_LOGD("%s: i=%d.\n", __FUNCTION__, i);
}
i++;
usleep(80000); //delay 80ms
}
b_play_start = false;
AUDIO_IF_LOGD("%s: stop signal sent\n", __FUNCTION__);
return UBUS_STATUS_OK;
}
/*******************************************************************************\
* Function: audio_if_pcmloopback_start
* Description:This function will launch a thread for pcm loopback
*
* Returns: 0 on success
\*******************************************************************************/
int audio_if_pcmloopback_start(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);
struct blob_attr *tb[PARAM_VCM_PLAY_REC_POLICY_MAX];
struct blob_attr *cur;
int rc = UBUS_STATUS_OK;
pthread_t thread;
char *path;
/*parsing blob to be accessed easily with tb array*/
rc = blobmsg_parse(vcm_play_rec_policy, PARAM_VCM_PLAY_REC_POLICY_MAX, tb, blob_data(msg), blob_len(msg));
if (rc < 0) {
AUDIO_IF_LOGD("%s: parsing fail\n", __FUNCTION__);
rc = UBUS_STATUS_INVALID_ARGUMENT;
return rc;
}
/*parse param*/
cur = tb[0];
if (!cur) {
AUDIO_IF_LOGD("%s: missing parameter\n", __FUNCTION__);
rc = UBUS_STATUS_INVALID_ARGUMENT;
return rc;
}
path = blobmsg_get_string(cur);
AUDIO_IF_LOGD("%s: got %s\n", __FUNCTION__, path);
/* malloc new memory */
gPath_pcmloopback = malloc(strlen(path) + 1); /* ending with /0 */
memset(gPath_pcmloopback, 0x00, strlen(path) + 1);
if(gPath_pcmloopback == NULL) {
AUDIO_IF_LOGE("%s: error malloc\n", __FUNCTION__);
rc = UBUS_STATUS_UNKNOWN_ERROR;
return rc;
}
else {
memcpy(gPath_pcmloopback, path, strlen(path));
}
mrvl_ahw_dev_ubus->device.set_mode(ahw_dev_ubus, AUDIO_MODE_IN_CALL);
rc = pthread_create(&thread, NULL, (void *)&audio_if_pcmloopback_thread, (void *)gPath_pcmloopback);
if (rc < 0) {
AUDIO_IF_LOGE("%s: error creating write thread\n", __FUNCTION__);
rc = UBUS_STATUS_PERMISSION_DENIED;
}
pthread_detach(thread);
AUDIO_IF_LOGD("%s: launched pcmloopback thread\n", __FUNCTION__);
return rc;
}
/*******************************************************************************\
* Function: audio_if_pcmloopback_stop
* Description:This function will stop the pcmloopback thread
*
* Returns: always 0 for success
\*******************************************************************************/
int audio_if_pcmloopback_stop(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);
UNUSEDPARAM(msg);
mrvl_ahw_dev_ubus->device.set_mode(ahw_dev_ubus, AUDIO_MODE_NORMAL);
go_on_pcmloopback = false;
/* free path name memory */
if(gPath_pcmloopback != NULL) {
free(gPath_pcmloopback);
gPath_pcmloopback = NULL;
}
AUDIO_IF_LOGD("%s: stop signal sent\n", __FUNCTION__);
return UBUS_STATUS_OK;
}
/*******************************************************************************\
* Function: audio_if_cp_loopback_enable
* Description: This function will enable CP loopback
* Returns: always 0 for success
\*******************************************************************************/
int audio_if_cp_loopback_enable(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 kvpair[128];
struct blob_attr *tb[PARAM_2_INT];
struct blob_attr *cur;
unsigned int device;
/* ubus call audio_if loopback_enable has two parameter formats:
loopback_enable "{'param0':x}" and loopback_enable "{'param0':x, 'mode':y}".
To be compatible with the first format, mode is initialized to 0,
in the end, mode will participate in the calculation of test_mode of structure LoopCtlMsg.
The minimum value of test_mode will be set to 1 in vcm_set_loopback.*/
unsigned int mode = 0;
int rc;
/*parsing blob to be accessed easily with tb array - parse "1" argument*/
rc = blobmsg_parse(cp_loopback_enable_policy, PARAM_2_INT, tb, blob_data(msg), blob_len(msg));
if (rc < 0) {
AUDIO_IF_LOGD("%s: parsing fail\n", __FUNCTION__);
return UBUS_STATUS_INVALID_ARGUMENT;
}
cur = tb[0];
if (!cur) {
AUDIO_IF_LOGD("%s: missing parameter for device\n", __FUNCTION__);
return UBUS_STATUS_INVALID_ARGUMENT;
}
device = blobmsg_get_u32(cur);
AUDIO_IF_LOGD("%s: device=%d!", __FUNCTION__, device);
//0: EARPIECE; 1: SPEAKER; 2: HEADSET
audio_if_CheckRange(device, TEL_AT_AUDIO_DEVICE_VAL_MIN, TEL_AT_AUDIO_DEVICE_VAL_MAX, NULL);
/* parse 2nd param */
cur = tb[1];
if (cur) {
mode = blobmsg_get_u32(cur);
AUDIO_IF_LOGD("%s: mode=%d!", __FUNCTION__, mode);
audio_if_CheckRange(mode, TEL_AT_AUDIO_MODE_VAL_MIN, TEL_AT_AUDIO_MODE_VAL_MAX, NULL);
}
memset(kvpair, 0, sizeof(kvpair));
switch (device) {
case 0:
sprintf(kvpair, "%s=%d;%s=%d", LOOPBACK, AUDIO_DEVICE_OUT_EARPIECE, LOOPBACK_MODE, mode);
break;
case 1:
sprintf(kvpair, "%s=%d;%s=%d", LOOPBACK, AUDIO_DEVICE_OUT_SPEAKER, LOOPBACK_MODE, mode);
break;
case 2:
sprintf(kvpair, "%s=%d;%s=%d", LOOPBACK, AUDIO_DEVICE_OUT_WIRED_HEADSET, LOOPBACK_MODE, mode);
break;
default:
ALOGE("%s: Unknow device", __FUNCTION__);
return UBUS_STATUS_INVALID_ARGUMENT;
break;
}
mrvl_ahw_dev_ubus->device.set_parameters(ahw_dev_ubus, kvpair);
AUDIO_IF_LOGD("%s: CP loopback enabled\n", __FUNCTION__);
return UBUS_STATUS_OK;
}
/*******************************************************************************\
* Function: audio_if_pcm_loopback_disable
* Description: This function will disable CP loopback
* Returns: always 0 for success
\*******************************************************************************/
int audio_if_cp_loopback_disable(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);
UNUSEDPARAM(msg);
char kvpair[128];
memset(kvpair, 0, sizeof(kvpair));
sprintf(kvpair, "%s=%d;%s=%d", LOOPBACK, AUDIO_DEVICE_NONE, LOOPBACK_MODE, 0);
mrvl_ahw_dev_ubus->device.set_parameters(ahw_dev_ubus, kvpair);
AUDIO_IF_LOGD("%s: CP loopback disabled\n", __FUNCTION__);
return UBUS_STATUS_OK;
}
/*******************************************************************************\
* Function: audio_if_pcm_loopback_disable
* Description: This function will disable CP loopback
* Returns: always 0 for success
\*******************************************************************************/
int audio_if_vcm_configure(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);
struct blob_attr *tb[PARAM_VCM_CONFIG_POLICY_MAX];
struct blob_attr *cur;
unsigned int direction = 0xFF, type, srcdst, priority, dest;
int rc;
char kvpair[128];
if (go_on_play || go_on_rec) {
AUDIO_IF_LOGE("%s: vcm playback and\\or record in process. aborting.\n", __FUNCTION__);
return UBUS_STATUS_PERMISSION_DENIED;
}
/*parsing blob to be accessed easily with tb array*/
rc = blobmsg_parse(vcm_config_policy, PARAM_VCM_CONFIG_POLICY_MAX, tb, blob_data(msg), blob_len(msg));
if (rc < 0) {
AUDIO_IF_LOGD("%s: parsing fail\n", __FUNCTION__);
rc = UBUS_STATUS_INVALID_ARGUMENT;
return rc;
}
/*parse 1st param*/
cur = tb[0];
if (!cur) {
AUDIO_IF_LOGD("%s: missing parameter\n", __FUNCTION__);
rc = UBUS_STATUS_INVALID_ARGUMENT;
return rc;
}
direction = blobmsg_get_u32(cur);
/*parse 2nd param*/
cur = tb[1];
if (!cur) {
AUDIO_IF_LOGD("%s: missing parameter\n", __FUNCTION__);
rc = UBUS_STATUS_INVALID_ARGUMENT;
return rc;
}
type = blobmsg_get_u32(cur);
/*parse 3rd param*/
cur = tb[2];
if (!cur) {
AUDIO_IF_LOGD("%s: missing parameter\n", __FUNCTION__);
rc = UBUS_STATUS_INVALID_ARGUMENT;
return rc;
}
srcdst = blobmsg_get_u32(cur);
/*parse 4th param*/
cur = tb[3];
if (!cur) {
AUDIO_IF_LOGD("%s: missing parameter\n", __FUNCTION__);
rc = UBUS_STATUS_INVALID_ARGUMENT;
return rc;
}
priority = blobmsg_get_u32(cur);
/*parse 5th param*/
cur = tb[4];
if (!cur) {
AUDIO_IF_LOGD("%s: missing parameter\n", __FUNCTION__);
rc = UBUS_STATUS_INVALID_ARGUMENT;
return rc;
}
dest = blobmsg_get_u32(cur);
if (direction == 0) {//output
if (type == 0) {
pcm_playback_size = PCM_NB_BUF_SIZE;
}
else {
pcm_playback_size = PCM_WB_BUF_SIZE;
}
}
else if (direction == 1) { //input
#if 0 //def TARGET_mmp_asr1901_KSTR901
unsigned int pkttype;
if (2 == srcdst) { //3-Both ends
pkttype = 1; //RECORD_TXRX
}
else { //0-None, 1-Near end, 2-Far end
pkttype = 0; //RECORD_RX
}
vcm_config_pkttype(pkttype | 1 << 16);
#endif
if (type == 0) {
pcm_record_size = PCM_NB_BUF_SIZE;
}
else {
pcm_record_size = PCM_WB_BUF_SIZE;
}
}
memset(kvpair, 0, sizeof(kvpair));
sprintf(kvpair, "%s=%d;%s=%d;%s=%d;%s=%d;%s=%d", VCM_CONFIG_DIRECTION, direction,
VCM_CONFIG_TYPE, type, VCM_CONFIG_SRC_DST, srcdst,
VCM_CONFIG_PRIORITY, priority, VCM_CONFIG_DEST, dest);
mrvl_ahw_dev_ubus->device.set_parameters(ahw_dev_ubus, kvpair);
return UBUS_STATUS_OK;
}
/****************************************************************
** response functions
****************************************************************/
/*******************************************************************************\
* Function: audio_if_ecall_data_status_response
* Description: This function is called when a VCM return the response for
* audio_if_ecall_data_status
* Returns: void
\*******************************************************************************/
void audio_if_ecall_data_status_response(void *p_atc_ecall_msg)
{
struct blob_buf b;
P_ACIPC_AUDIO_VCM_ECALL_DATA_GET_CNF pAcipcMsg;
unsigned long command, op, param1, value1, value2;
pAcipcMsg = (P_ACIPC_AUDIO_VCM_ECALL_DATA_GET_CNF)p_atc_ecall_msg;
command = pAcipcMsg->command;
op = pAcipcMsg->op;
param1 = pAcipcMsg->param1;
value1 = pAcipcMsg->value1;
value2 = pAcipcMsg->value2;
AUDIO_IF_LOGD("[%s] command=0x%x, op=0x%x, param1=0x%x, value1=0x%x, value2=0x%",
__FUNCTION__, (int)command, (int)op, (int)param1, (int)value1, (int)value2);
memset(&b, 0, sizeof(b));
blob_buf_init(&b, 0);
blobmsg_add_u32(&b, "op", op);
blobmsg_add_u32(&b, "param1", param1);
blobmsg_add_u32(&b, "value1", value1);
blobmsg_add_u32(&b, "value2", value2);
ubus_send_reply(audioIfUbusDb.ctx, &audioIfReqDb.reqdata, b.head);
ubus_complete_deferred_request(audioIfUbusDb.ctx, &audioIfReqDb.reqdata, UBUS_STATUS_OK);
pthread_mutex_lock(audioIfReqDb.pMutexLock);
audioIfReqDb.occupy = 0;
pthread_mutex_unlock(audioIfReqDb.pMutexLock);
blob_buf_free(&b);
return;
}
/*******************************************************************************\
* Function: audio_if_ecall_voice_status_response
* Description: This function is called when a VCM return the response for
* audio_if_ecall_voice_status
* Returns: void
\*******************************************************************************/
void audio_if_ecall_voice_status_response(void *p_atc_ecall_msg)
{
struct blob_buf b;
P_ACIPC_AUDIO_VCM_ECALL_VOICE_GET_CNF pAcipcMsg;
unsigned long command, cmd_id, res_id, param2;
pAcipcMsg = (P_ACIPC_AUDIO_VCM_ECALL_VOICE_GET_CNF)p_atc_ecall_msg;
command = pAcipcMsg->command;
cmd_id = pAcipcMsg->cmd_id;
res_id = pAcipcMsg->res_id;
param2 = pAcipcMsg->param2;
AUDIO_IF_LOGD("[%s] command=0x%x, cmd_id=0x%x, res_id=0x%x, param2=0x%x",
__FUNCTION__, (int)command, (int)cmd_id, (int)res_id, (int)param2);
memset(&b, 0, sizeof(b));
blob_buf_init(&b, 0);
blobmsg_add_u32(&b, "cmd_id", cmd_id);
blobmsg_add_u32(&b, "res_id", res_id);
blobmsg_add_u32(&b, "param2", param2);
ubus_send_reply(audioIfUbusDb.ctx, &audioIfReqDb.reqdata, b.head);
ubus_complete_deferred_request(audioIfUbusDb.ctx, &audioIfReqDb.reqdata, UBUS_STATUS_OK);
pthread_mutex_lock(audioIfReqDb.pMutexLock);
audioIfReqDb.occupy = 0;
pthread_mutex_unlock(audioIfReqDb.pMutexLock);
blob_buf_free(&b);
return;
}
/*******************************************************************************\
* Function: audio_if_switch_pcm
* Description: This function is called when audio_if client invoke switch_pcm method
* 0: turn off PCM clock
* 1: turn on PCM clock
* Returns: 0 on success
\*******************************************************************************/
int audio_if_switch_pcm(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);
struct blob_attr *tb[PARAM_1_INT];
struct blob_attr *cur;
unsigned int pcm;
int rc;
/*parsing blob to be accessed easily with tb array - parse "1" argument*/
rc = blobmsg_parse(int_policy, PARAM_1_INT, tb, blob_data(msg), blob_len(msg));
if (rc < 0) {
AUDIO_IF_LOGD("%s: parsing fail\n", __FUNCTION__);
return UBUS_STATUS_INVALID_ARGUMENT;
}
cur = tb[0];
if (!cur) {
AUDIO_IF_LOGD("%s: missing parameter\n", __FUNCTION__);
return UBUS_STATUS_INVALID_ARGUMENT;
}
pcm = blobmsg_get_u32(cur);
audio_if_CheckRange(pcm, 0, MAX_PCM_SWITCH_TYPE, NULL);
if (ahw_dev_ubus->switch_pcm(ahw_dev_ubus, pcm) == 0) {
return UBUS_STATUS_OK;
}
return UBUS_STATUS_INVALID_ARGUMENT;
}
/*******************************************************************************\
* Function: audio_if_DTMFDetection
* Description: This function is called when audio_if client invoke DTMFDetection method
* DTMFType_OnOff: bit1: 0:Tx, 1:Rx; bit0: 0:Off, 1:On;
* dialToneToOthersTones; //Detection ration b/w a dial tone and preset tones
* dialTonesToOthersDialTones; //Detection ration b/w a dial tone and other dial tones
* dialVadDuration; //Duration time b/w two successive dial tones (unit: 20ms)
* Returns: 0 on success
\*******************************************************************************/
int audio_if_DTMFDetection(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);
struct blob_attr *tb[PARAM_INT_POLICY_MAX];
struct blob_attr *cur;
unsigned int DTMFType_OnOff = 0;
unsigned int DTMFType = 0;/* 0=TX, 1=RX */
unsigned int OnOff = 0;
unsigned int dialToneToOthersTones = 0;
unsigned int dialTonesToOthersDialTones = 0;
unsigned int dialVadDuration = 0;
int rc = 0;
/*parsing blob to be accessed easily with tb array - parse "1" argument*/
rc = blobmsg_parse(int_policy, PARAM_INT_POLICY_MAX, tb, blob_data(msg), blob_len(msg));
if (rc < 0) {
AUDIO_IF_LOGD("%s: parsing fail\n", __FUNCTION__);
return UBUS_STATUS_INVALID_ARGUMENT;
}
/*parse 1st param*/
cur = tb[0];
if (!cur) {
AUDIO_IF_LOGD("%s: missing parameter\n", __FUNCTION__);
rc = UBUS_STATUS_INVALID_ARGUMENT;
return rc;
}
DTMFType_OnOff = blobmsg_get_u32(cur);
audio_if_CheckRange(DTMFType_OnOff, 0, 3, NULL);
/*DTMFType_OnOff
* DTMFType: bit1: 0:TX, 1:RX
* OnOff: bit0: 0:OFF, 1:ON
*
* NOTES:
* The extended is compatible between ASR1826 and ASR1802SL.
* ASR1826: Only support TX DTMF Detection becauseof DSP. DTMFType is always TX.
* when ASR1826, the attribute of DTMFType is ignored.
* ASR1802SL: Could support TX and RX DTMF Detection.
*
*/
DTMFType = (DTMFType_OnOff & 0x02) >> 1;
OnOff = DTMFType_OnOff & 0x01;
if (1 == OnOff) {
/*parse 2nd param*/
cur = tb[1];
if (!cur) {
AUDIO_IF_LOGD("%s: missing parameter\n", __FUNCTION__);
rc = UBUS_STATUS_INVALID_ARGUMENT;
return rc;
}
dialToneToOthersTones = blobmsg_get_u32(cur);
/*parse 3rd param*/
cur = tb[2];
if (!cur) {
AUDIO_IF_LOGD("%s: missing parameter\n", __FUNCTION__);
rc = UBUS_STATUS_INVALID_ARGUMENT;
return rc;
}
dialTonesToOthersDialTones = blobmsg_get_u32(cur);
/*parse 4th param*/
cur = tb[3];
if (!cur) {
AUDIO_IF_LOGD("%s: missing parameter\n", __FUNCTION__);
rc = UBUS_STATUS_INVALID_ARGUMENT;
return rc;
}
dialVadDuration = blobmsg_get_u32(cur);
}
AUDIO_IF_LOGD("%s, DTMFType:%s, OnOff:%s, DTMFType_OnOff:%u, dialToneToOthersTones:%u, dialTonesToOthersDialTones:%u, dialVadDuration:%u", __FUNCTION__, DTMFType?"RX":"TX", OnOff?"ON":"OFF", DTMFType_OnOff, dialToneToOthersTones, dialTonesToOthersDialTones, dialVadDuration);
rc = vcm_DTMFDetection(DTMFType_OnOff, dialToneToOthersTones, dialTonesToOthersDialTones, dialVadDuration);
if (rc) {
return UBUS_STATUS_PERMISSION_DENIED;
}
else {
return UBUS_STATUS_OK;
}
}
/*******************************************************************************\
* Function: audio_if_config_pcm
* Description: This function is called when audio_if client invoke config_pcm method
* role: 1:master, 0:slave for modem
* rate: 1:WB, 0:NB for modem
* bitclk: 0:decided by CP; 1:BCLK_32_FS; 2:BCLK_64_FS; 3:BCLK_128_FS; 4:BCLK_256_FS;
* 2slots: 1:enable 2 time slots; 0:disable 2 time slots; NOTES:this config use BCLK_32_FS
* controller: 0:GSSP; 1:SSPA; 2:internal codec;
* Returns: 0 on success
\*******************************************************************************/
int audio_if_config_pcm(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);
struct blob_attr *tb[PARAM_5_INT];
struct blob_attr *cur = NULL;
unsigned int pcm_role = 0;
unsigned int pcm_rate = 0;
unsigned int pcm_bitclk = 0;
unsigned int pcm_2slots = 0;
unsigned int pcm_controller = 0;
unsigned int pcm = 0;
int rc;
/* parsing blob to be accessed easily with tb array - parse "1" argument */
rc = blobmsg_parse(config_pcm_policy, PARAM_5_INT, tb, blob_data(msg), blob_len(msg));
if (rc < 0) {
AUDIO_IF_LOGD("%s: parsing fail\n", __FUNCTION__);
return UBUS_STATUS_INVALID_ARGUMENT;
}
/* parse 1st param */
cur = tb[0];
if (!cur) {
AUDIO_IF_LOGD("%s: missing parameter for role.\n", __FUNCTION__);
return UBUS_STATUS_INVALID_ARGUMENT;
}
/* role: 1:master, 0:slave for modem */
pcm_role = blobmsg_get_u32(cur);
if ((0 != pcm_role) && (1 != pcm_role)) {
AUDIO_IF_LOGD("%s: incorrect parameter for role, 1:master, 0:slave.\n", __FUNCTION__);
return UBUS_STATUS_INVALID_ARGUMENT;
}
/* parse 2nd param */
cur = tb[1];
if (!cur) {
AUDIO_IF_LOGD("%s: missing parameter for rate.\n", __FUNCTION__);
return UBUS_STATUS_INVALID_ARGUMENT;
}
/* rate: 1:WB, 0:NB for modem */
pcm_rate = blobmsg_get_u32(cur);
if (pcm_rate > 3) {
AUDIO_IF_LOGD("%s: incorrect parameter for rate, 3:48KHz, 2:32KHz, 1:WB, 0:NB.\n", __FUNCTION__);
return UBUS_STATUS_INVALID_ARGUMENT;
}
/* parse 3rd param */
cur = tb[2];
if (!cur) {
AUDIO_IF_LOGD("%s: missing parameter for bitclk.\n", __FUNCTION__);
return UBUS_STATUS_INVALID_ARGUMENT;
}
/* bitclk: 0:decided by CP; 1:BCLK_32_FS; 2:BCLK_64_FS; 3:BCLK_128_FS; 4:BCLK_256_FS; */
pcm_bitclk = blobmsg_get_u32(cur);
if (pcm_bitclk > 4) {
AUDIO_IF_LOGD("%s: incorrect parameter for bitclk, 0:decided by CP; 1:BCLK_32_FS; 2:BCLK_64_FS; 3:BCLK_128_FS; 4:BCLK_256_FS.\n", __FUNCTION__);
return UBUS_STATUS_INVALID_ARGUMENT;
}
/* parse 4th param */
cur = tb[3];
if (!cur) {
AUDIO_IF_LOGD("%s: missing parameter for 2slots.\n", __FUNCTION__);
return UBUS_STATUS_INVALID_ARGUMENT;
}
/* 2slots: 1:enable 2 time slots; 0:disable 2 time slots; */
pcm_2slots = blobmsg_get_u32(cur);
if ((0 != pcm_2slots) && (1 != pcm_2slots)) {
AUDIO_IF_LOGD("%s: incorrect parameter for 2slots, 1:enable 2 time slots; 0:disable 2 time slots.\n", __FUNCTION__);
return UBUS_STATUS_INVALID_ARGUMENT;
}
/* parse 5th param */
cur = tb[4];
if (!cur) {
AUDIO_IF_LOGD("%s: missing parameter for controller.\n", __FUNCTION__);
return UBUS_STATUS_INVALID_ARGUMENT;
}
/* controller: 0:GSSP; 1:SSPA; 2:internal codec; */
pcm_controller = blobmsg_get_u32(cur);
if (pcm_controller > 2) {
AUDIO_IF_LOGD("%s: incorrect parameter for controller: 0:GSSP; 1:SSPA; 2:internal codec.\n", __FUNCTION__);
return UBUS_STATUS_INVALID_ARGUMENT;
}
#ifdef TARGET_mmp_asr1901_KSTR901
/*
* bit0: 1:master, 0:slave
* bit1~bit3: (3:48KHz, 2:32KHz, 1:WB, 0:NB)
* bit4~bit6: (0:decided by CP; 1:BCLK_32_FS; 2:BCLK_64_FS; 3:BCLK_128_FS; 4:BCLK_256_FS;)
* bit7: 1:enable 2 time slots; 0:disable 2 time slots;
* bit8~bit9: 0:GSSP; 1:SSPA; 2:internal codec;
*/
pcm = ((pcm_controller << 8) | (pcm_2slots << 7) | (pcm_bitclk << 4) | (pcm_rate << 1) | (pcm_role & 0x01));
#else
/*
* bit0: 1:master, 0:slave
* bit1: 1:WB, 0:NB
* bit2~bit4: (0:decided by CP; 1:BCLK_32_FS; 2:BCLK_64_FS; 3:BCLK_128_FS; 4:BCLK_256_FS;)
* bit5: 1:enable 2 time slots; 0:disable 2 time slots;
* bit6~bit7: 0:GSSP; 1:SSPA; 2:internal codec;
*/
pcm = ((pcm_controller << 6) | (pcm_2slots << 5) | (pcm_bitclk << 2) | (pcm_rate << 1) | (pcm_role & 0x01));
#endif
AUDIO_IF_LOGD("%s: pcm=%d, pcm_controller=%d, 2slots=%d, bitclk=%d, rate=%d, role=%d.\n", __FUNCTION__, pcm, pcm_controller, pcm_2slots, pcm_bitclk, pcm_rate, pcm_role);
if (ahw_dev_ubus->config_pcm(ahw_dev_ubus, pcm) == 0) {
return UBUS_STATUS_OK;
}
return UBUS_STATUS_INVALID_ARGUMENT;
}
/*******************************************************************************\
* Function: audio_if_config_dspgain
* Description: This function is called when audio_if client invoke config_dspgain method
* type: 0:TX_VOLUME, 1:RX_VOLUME, 2:SIDETONE_VOLUME
* gain: [-36dB, 12dB],
* -128 means disable SIDETONE. NOTE: keep identical with CP index
* -100: MUTE ON, 100: MUTE OFF
* Returns: 0 on success
\*******************************************************************************/
int audio_if_config_dspgain(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);
struct blob_attr *tb[PARAM_2_INT];
struct blob_attr *cur = NULL;
unsigned int type_vol = 0;
unsigned int dsp_gain = 0;
int rc;
/* parsing blob to be accessed easily with tb array - parse "1" argument */
rc = blobmsg_parse(config_dspgain_policy, PARAM_2_INT, tb, blob_data(msg), blob_len(msg));
if (rc < 0) {
AUDIO_IF_LOGD("%s: parsing fail\n", __FUNCTION__);
return UBUS_STATUS_INVALID_ARGUMENT;
}
/* parse 1st param */
cur = tb[0];
if (!cur) {
AUDIO_IF_LOGD("%s: missing parameter for type.\n", __FUNCTION__);
return UBUS_STATUS_INVALID_ARGUMENT;
}
type_vol = blobmsg_get_u32(cur);
/* type: 0:CONFIG_DSPGAIN_TX, 1:CONFIG_DSPGAIN_RX, 2:CONFIG_DSPGAIN_SIDETONE */
if (type_vol > CONFIG_DSPGAIN_NUMBER) {
AUDIO_IF_LOGD("%s: The type is out of the range 0~2.\n", __FUNCTION__);
return UBUS_STATUS_INVALID_ARGUMENT;
}
/* parse 2nd param */
cur = tb[1];
if (!cur) {
AUDIO_IF_LOGD("%s: missing parameter for dsp gain.\n", __FUNCTION__);
return UBUS_STATUS_INVALID_ARGUMENT;
}
dsp_gain = blobmsg_get_u32(cur);
/* gain: [-36dB, 12dB] , -128 means disable SIDETONE. NOTE: keep identical with CP index */
if (((signed int)dsp_gain < CONFIG_DSPGAIN_DOMAIN_MIN) || ((signed int)dsp_gain > CONFIG_DSPGAIN_DOMAIN_MAX)) {
if (((signed int)dsp_gain == CONFIG_DSPGAIN_SIDETONE_DISABLE) && (type_vol == CONFIG_DSPGAIN_SIDETONE)) {
AUDIO_IF_LOGD("%s: Disable SideTone module. SideTone gain is -128. dsp_gain=%d. \n", __FUNCTION__, dsp_gain);
}
else if ((((signed int)dsp_gain == CONFIG_DSPGAIN_MUTE_ON) && (type_vol != CONFIG_DSPGAIN_SIDETONE))
|| (((signed int)dsp_gain == CONFIG_DSPGAIN_MUTE_OFF) && (type_vol != CONFIG_DSPGAIN_SIDETONE))) {
AUDIO_IF_LOGD("%s: Direction is %s, MUTE is %s. \n",
__FUNCTION__, (type_vol == CONFIG_DSPGAIN_TX)?"TX":"RX", (dsp_gain == CONFIG_DSPGAIN_MUTE_OFF)?"OFF":"ON");
}
else {
AUDIO_IF_LOGD("%s: The Gain is out of the range [-36dB, 12dB], dsp_gain=%d. \n", __FUNCTION__, dsp_gain);
return UBUS_STATUS_INVALID_ARGUMENT;
}
}
AUDIO_IF_LOGD("%s: type_vol=%d, dsp_gain=%d.\n", __FUNCTION__, type_vol, dsp_gain);
if (ahw_dev_ubus->config_dspgain(ahw_dev_ubus, type_vol, dsp_gain) == 0) {
return UBUS_STATUS_OK;
}
return UBUS_STATUS_INVALID_ARGUMENT;
}
/*******************************************************************************\
* Function: audio_if_config_pcmexpert
* Description: This function is called when audio_if client invoke config_pcm method
* frame_format: 1:psp, 0:ssp
* invert_frame: 1:invert frame polarity, 0:normal frame polarity
* frame_polarity: 1:active high, 0:active low
* bitclk_polarity: 0: FAILING_RISING_LOW; 1: RISING_FAILING_LOW; 2: RISING_FAILING_HIGH; 3: FAILING_RISING_HIGH;
* fsyc_shift: 1: shift 1 bitclk; 0:shift 0 bitclk
* Returns: 0 on success
\*******************************************************************************/
int audio_if_config_pcmexpert(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);
struct blob_attr *tb[PARAM_5_INT];
struct blob_attr *cur = NULL;
unsigned int frame_format = 0;
unsigned int invert_frame = 0;
unsigned int frame_polarity = 0;
unsigned int bitclk_polarity = 0;
unsigned int fsyc_shift = 0;
unsigned int pcmexpert = 0;
int rc;
/* parsing blob to be accessed easily with tb array - parse "1" argument */
rc = blobmsg_parse(config_pcmexpert_policy, PARAM_5_INT, tb, blob_data(msg), blob_len(msg));
if (rc < 0) {
AUDIO_IF_LOGD("%s: parsing fail\n", __FUNCTION__);
return UBUS_STATUS_INVALID_ARGUMENT;
}
/* parse 1st param */
cur = tb[0];
if (!cur) {
AUDIO_IF_LOGD("%s: missing parameter for frame_format.\n", __FUNCTION__);
return UBUS_STATUS_INVALID_ARGUMENT;
}
/* frame_format: 1:psp, 0:ssp */
frame_format = blobmsg_get_u32(cur);
if ((0 != frame_format) && (1 != frame_format)) {
AUDIO_IF_LOGD("%s: incorrect parameter for frame_format, 1:psp, 0:ssp.\n", __FUNCTION__);
return UBUS_STATUS_INVALID_ARGUMENT;
}
/* NOTES: the other segments are based on frame_format of "PSP" */
if (1 == frame_format) {
/* parse 2nd param */
cur = tb[1];
if (!cur) {
AUDIO_IF_LOGD("%s: missing parameter for invert_frame.\n", __FUNCTION__);
return UBUS_STATUS_INVALID_ARGUMENT;
}
/* invert_frame: 1:invert frame polarity, 0:normal frame polarity */
invert_frame = blobmsg_get_u32(cur);
if ((0 != invert_frame) && (1 != invert_frame)) {
AUDIO_IF_LOGD("%s: incorrect parameter for invert_frame, 1:invert frame polarity, 0:normal frame polarity.\n", __FUNCTION__);
return UBUS_STATUS_INVALID_ARGUMENT;
}
/* parse 3rd param */
cur = tb[2];
if (!cur) {
AUDIO_IF_LOGD("%s: missing parameter for frame_polarity.\n", __FUNCTION__);
return UBUS_STATUS_INVALID_ARGUMENT;
}
/* frame_polarity: 1:active high, 0:active low */
frame_polarity = blobmsg_get_u32(cur);
if ((0 != frame_polarity) && (1 != frame_polarity)) {
AUDIO_IF_LOGD("%s: incorrect parameter for frame_polarity, 1:active high, 0:active low.\n", __FUNCTION__);
return UBUS_STATUS_INVALID_ARGUMENT;
}
/* parse 4th param */
cur = tb[3];
if (!cur) {
AUDIO_IF_LOGD("%s: missing parameter for bitclk_polarity.\n", __FUNCTION__);
return UBUS_STATUS_INVALID_ARGUMENT;
}
/* bitclk_polarity: 0: FAILING_RISING_LOW; 1: RISING_FAILING_LOW; 2: RISING_FAILING_HIGH; 3: FAILING_RISING_HIGH; */
bitclk_polarity = blobmsg_get_u32(cur);
if (bitclk_polarity > 3) {
AUDIO_IF_LOGD("%s: incorrect parameter for bitclk_polarity: 0: FAILING_RISING_LOW; 1: RISING_FAILING_LOW; 2: RISING_FAILING_HIGH; 3: FAILING_RISING_HIGH;.\n", __FUNCTION__);
return UBUS_STATUS_INVALID_ARGUMENT;
}
/* parse 5th param */
cur = tb[4];
if (!cur) {
AUDIO_IF_LOGD("%s: missing parameter for fsyc_shift.\n", __FUNCTION__);
return UBUS_STATUS_INVALID_ARGUMENT;
}
/* fsyc_shift: 1: shift 1 bitclk; 0:shift 0 bitclk */
fsyc_shift = blobmsg_get_u32(cur);
if ((0 != fsyc_shift) && (1 != fsyc_shift)) {
AUDIO_IF_LOGD("%s: incorrect parameter for fsyc_shift: 1: shift 1 bitclk; 0:shift 0 bitclk.\n", __FUNCTION__);
return UBUS_STATUS_INVALID_ARGUMENT;
}
}
/*
* bit0: 1:psp, 0:ssp
* bit1: 1:invert frame polarity, 0:normal frame polarity
* bit2: 1:active high, 0:active low
* bit3~bit4: (0: FAILING_RISING_LOW; 1: RISING_FAILING_LOW; 2: RISING_FAILING_HIGH; 3: FAILING_RISING_HIGH;)
* bit5: 1: shift 1 bitclk; 0:shift 0 bitclk
*/
pcmexpert = ((fsyc_shift << 5) | (bitclk_polarity << 3) | (frame_polarity << 2) | (invert_frame << 1) | (frame_format & 0x01));
AUDIO_IF_LOGD("%s: pcmexpert=%d, fsyc_shift=%d, bitclk_polarity=%d, frame_polarity=%d, invert_frame=%d, frame_format=%d.\n",
__FUNCTION__, pcmexpert, fsyc_shift, bitclk_polarity, frame_polarity, invert_frame, frame_format);
if (ahw_dev_ubus->config_pcmexpert(ahw_dev_ubus, pcmexpert) == 0) {
return UBUS_STATUS_OK;
}
return UBUS_STATUS_INVALID_ARGUMENT;
}
/*******************************************************************************\
* Function: audio_if_DTMFControl
* Description: This function is called when audio_if client invoke DTMFControl method
* on: 0:Off, 1:On;
* tone1_index: within the domain of CONFIG_DTMFCONTROL_INDEX
* tone2_index: within the domain of CONFIG_DTMFCONTROL_INDEX
* Returns: 0 on success
\*******************************************************************************/
int audio_if_DTMFControl(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);
struct blob_attr *tb[PARAM_3_INT];
struct blob_attr *cur;
unsigned int OnOff = 0;
unsigned int Tone1_Index = 0;
unsigned int Tone2_Index = 0;
int rc = 0;
/*parsing blob to be accessed easily with tb array - parse "1" argument*/
rc = blobmsg_parse(vcm_dtmfcontrol_policy, PARAM_3_INT, tb, blob_data(msg), blob_len(msg));
if (rc < 0) {
AUDIO_IF_LOGD("%s: parsing fail\n", __FUNCTION__);
return UBUS_STATUS_INVALID_ARGUMENT;
}
/*parse 1st param*/
cur = tb[0];
if (!cur) {
AUDIO_IF_LOGD("%s: missing parameter\n", __FUNCTION__);
rc = UBUS_STATUS_INVALID_ARGUMENT;
return rc;
}
OnOff = blobmsg_get_u32(cur);
//bit0 for on/off, bit1 for combine(1)/override(0), bit8~15 for gain in db
audio_if_CheckRange(OnOff, 0, 0xffff, NULL);
/*parse 2nd param*/
cur = tb[1];
if (!cur) {
AUDIO_IF_LOGD("%s: missing parameter\n", __FUNCTION__);
rc = UBUS_STATUS_INVALID_ARGUMENT;
return rc;
}
Tone1_Index = blobmsg_get_u32(cur);
audio_if_CheckRange(Tone1_Index, F697, F480, NULL);
/*parse 3rd param*/
cur = tb[2];
if (!cur) {
AUDIO_IF_LOGD("%s: missing parameter\n", __FUNCTION__);
rc = UBUS_STATUS_INVALID_ARGUMENT;
return rc;
}
Tone2_Index = blobmsg_get_u32(cur);
audio_if_CheckRange(Tone2_Index, F697, F480, NULL);
AUDIO_IF_LOGD("%s, OnOff:0x%u, Tone1_Index:%u, Tone2_Index:%u", __FUNCTION__, OnOff, Tone1_Index, Tone2_Index);
rc = vcm_DTMFControl(OnOff, Tone1_Index, Tone2_Index);
if (rc) {
return UBUS_STATUS_PERMISSION_DENIED;
}
else {
return UBUS_STATUS_OK;
}
return UBUS_STATUS_INVALID_ARGUMENT;
}
/*******************************************************************************\
* Function: audio_if_report_voice_status
* Description: This function is called when need to check the status of record or playback.
*
* Returns: 0 on success
\*******************************************************************************/
int audio_if_report_voice_status(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(method);
UNUSEDPARAM(msg);
struct blob_buf buf_blob;
AUDIO_IF_LOGD("%s: voice_status is %d.\n", __FUNCTION__, voice_status);
memset(&buf_blob, 0, sizeof(buf_blob));
blob_buf_init(&buf_blob, 0);
blobmsg_add_u32(&buf_blob, "param0", voice_status);
ubus_send_reply(audioIfUbusDb.ctx, req, buf_blob.head);
blob_buf_free(&buf_blob);
return UBUS_STATUS_OK;
}
/*******************************************************************************\
* Function: audio_if_reload_nvm
* Description: This function is called when need to reload NVM of both AP and CP.
*
* Returns: 0 on success
\*******************************************************************************/
int audio_if_reload_nvm(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(method);
UNUSEDPARAM(msg);
struct blob_buf buf_blob;
int ret;
ret = ahw_dev_ubus->reload_nvm(ahw_dev_ubus);
AUDIO_IF_LOGD("%s: reload_nvm retrun %d.\n", __FUNCTION__, ret);
memset(&buf_blob, 0, sizeof(buf_blob));
blob_buf_init(&buf_blob, 0);
blobmsg_add_u32(&buf_blob, "return", ret);
ubus_send_reply(audioIfUbusDb.ctx, req, buf_blob.head);
blob_buf_free(&buf_blob);
return UBUS_STATUS_OK;
}
/*******************************************************************************\
* Function: audio_if_config_pa
* Description: This function is called when need to configure PA.
*
* Returns: 0 on success
\*******************************************************************************/
int audio_if_config_pa(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(method);
struct blob_attr *tb[PARAM_4_INT];
struct blob_attr *cur;
unsigned int on_off = 0;
unsigned int gpio_pin = 0;
unsigned int delay_start = 0;
unsigned int delay_stop = 0;
int rc = 0;
struct blob_buf buf_blob;
/*parsing blob to be accessed easily with tb array - parse "1" argument*/
rc = blobmsg_parse(config_pa_policy, PARAM_4_INT, tb, blob_data(msg), blob_len(msg));
if (rc < 0) {
AUDIO_IF_LOGD("%s: parsing fail\n", __FUNCTION__);
return UBUS_STATUS_INVALID_ARGUMENT;
}
/*parse 1st param*/
cur = tb[0];
if (!cur) {
AUDIO_IF_LOGD("%s: missing parameter\n", __FUNCTION__);
rc = UBUS_STATUS_INVALID_ARGUMENT;
return rc;
}
on_off = blobmsg_get_u32(cur);
audio_if_CheckRange(on_off, 0, 3, NULL);
/*parse 2nd param*/
cur = tb[1];
if (!cur) {
AUDIO_IF_LOGD("%s: missing parameter\n", __FUNCTION__);
rc = UBUS_STATUS_INVALID_ARGUMENT;
return rc;
}
gpio_pin = blobmsg_get_u32(cur);
audio_if_CheckRange(gpio_pin, 0, 0xffff, NULL);
/*parse 3rd param*/
cur = tb[2];
if (!cur) {
AUDIO_IF_LOGD("%s: missing parameter\n", __FUNCTION__);
rc = UBUS_STATUS_INVALID_ARGUMENT;
return rc;
}
delay_start = blobmsg_get_u32(cur);
audio_if_CheckRange(delay_start, 0, 0xffff, NULL);
/*parse 4th param*/
cur = tb[3];
if (!cur) {
AUDIO_IF_LOGD("%s: missing parameter\n", __FUNCTION__);
rc = UBUS_STATUS_INVALID_ARGUMENT;
return rc;
}
delay_stop = blobmsg_get_u32(cur);
audio_if_CheckRange(delay_stop, 0, 0xffff, NULL);
AUDIO_IF_LOGD("%s, on_off:0x%u, gpio_pin:0x%u, delay_start:%u, delay_stop:%u", __FUNCTION__, on_off, gpio_pin, delay_start, delay_stop);
rc = vcm_config_pa(on_off, gpio_pin, delay_start, delay_stop);
AUDIO_IF_LOGD("%s: configpa retrun %d.\n", __FUNCTION__, rc);
memset(&buf_blob, 0, sizeof(buf_blob));
blob_buf_init(&buf_blob, 0);
blobmsg_add_u32(&buf_blob, "return", rc);
ubus_send_reply(audioIfUbusDb.ctx, req, buf_blob.head);
blob_buf_free(&buf_blob);
return UBUS_STATUS_OK;
}
#ifdef TARGET_mmp_asr1901_KSTR901
extern const struct blobmsg_policy adsp_set_policy[];
extern int audio_dsp_set(char *cmd);
/*******************************************************************************\
* Function: audio_if_adsp_set
* Description: This function will launch a thread to send msg to adsp.
* Returns: 0 on success
\*******************************************************************************/
int audio_if_adsp_set(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);
struct blob_attr *tb[PARAM_VCM_CONFIG_POLICY_MAX];
struct blob_attr *cur;
int rc = UBUS_STATUS_OK;
char *cmd;
/*parsing blob to be accessed easily with tb array*/
rc = blobmsg_parse(adsp_set_policy, PARAM_ADSP_SET_POLICY_MAX, tb, blob_data(msg), blob_len(msg));
if (rc < 0) {
AUDIO_IF_LOGD("%s: parsing fail\n", __FUNCTION__);
rc = UBUS_STATUS_INVALID_ARGUMENT;
return rc;
}
/*parse param*/
cur = tb[0];
if (!cur) {
AUDIO_IF_LOGD("%s: missing parameter\n", __FUNCTION__);
rc = UBUS_STATUS_INVALID_ARGUMENT;
return rc;
}
cmd = blobmsg_get_string(cur);
AUDIO_IF_LOGE("%s: %s\n", __FUNCTION__, cmd);
audio_dsp_set(cmd);
AUDIO_IF_LOGD("%s: done.\n", __FUNCTION__);
return rc;
}
extern void ACM_SendVEtoADSP(void);
/*******************************************************************************\
* Function: audio_if_adsp_send_ve
* Description: This function will launch a thread to send msg to adsp.
* Returns: 0 on success
\*******************************************************************************/
int audio_if_adsp_send_ve(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);
UNUSEDPARAM(msg);
AUDIO_IF_LOGD("%s: audio_if_adsp_send_ve\n", __FUNCTION__);
ACM_SendVEtoADSP();
AUDIO_IF_LOGD("%s: done.\n", __FUNCTION__);
return UBUS_STATUS_OK;
}
extern int audio_dsp_dump_full_ddr(unsigned int val);
/*******************************************************************************\
* Function: audio_if_adsp_dump_full_ddr
* Description: This function is called when an audio_if client invoke mute_set method
* This method set mute off/on: input is param0: 0/1
* Returns: 0 on success
\*******************************************************************************/
int audio_if_adsp_dump_full_ddr(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);
struct blob_attr *tb[PARAM_1_INT];
struct blob_attr *cur;
unsigned int val;
int rc;
/*parsing blob to be accessed easily with tb array - parse "1" argument*/
rc = blobmsg_parse(int_policy, PARAM_1_INT, tb, blob_data(msg), blob_len(msg));
if (rc < 0) {
AUDIO_IF_LOGD("%s: parsing fail\n", __FUNCTION__);
return UBUS_STATUS_INVALID_ARGUMENT;
}
cur = tb[0];
if (!cur) {
AUDIO_IF_LOGD("%s: missing parameter\n", __FUNCTION__);
return UBUS_STATUS_INVALID_ARGUMENT;
}
val = blobmsg_get_u32(cur);
audio_if_CheckRange(val, 0, 1, NULL);
if (audio_dsp_dump_full_ddr(val) == 0) {
return UBUS_STATUS_OK;
}
else {
return UBUS_STATUS_UNKNOWN_ERROR;
}
}
#endif