| /****************************************************************************** |
| *(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 |
| |