| /** | 
 |  *   \file mbtk_audio_alsa.c | 
 |  *   \brief A Documented file. | 
 |  * | 
 |  *  Detailed description | 
 |  *   \Author:  js.wang <js.wang@mobiletek.cn> | 
 |  *   \Version: 1.0.0 | 
 |  *   \Date: 2020-09-21 | 
 |  */ | 
 | #include <stdio.h> | 
 | #include <stdlib.h> | 
 | #include <string.h> | 
 | #include <unistd.h> | 
 | #include <sys/types.h> | 
 | #include <errno.h> | 
 | #include <fcntl.h> | 
 | #include <pthread.h> | 
 |  | 
 | #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 <unistd.h> | 
 | #include <sys/stat.h> | 
 | #include "audio_if_audio_hw_mrvl.h" | 
 | #include "audio_hw_mrvl.h" | 
 | #include <cutils/str_parms.h> | 
 | #include "vcm.h" | 
 | #include "voice_control.h" | 
 | #include "mbtk_audio.h" | 
 |  | 
 |  | 
 | // #define DEBUG 1 | 
 |  | 
 | #ifdef DEBUG | 
 | 	#define mbtk_audio_log(...)                    printf(__VA_ARGS__) | 
 | #else | 
 | 	#define mbtk_audio_log(...) | 
 | #endif | 
 |  | 
 | typedef int (*_play_callback)(int hdl, int result); | 
 |  | 
 | #define FAILURE -1 | 
 | #define ID_RIFF 0x46464952 | 
 | #define ID_WAVE 0x45564157 | 
 | #define ID_FMT  0x20746d66 | 
 | #define ID_DATA 0x61746164 | 
 | #define FORMAT_PCM 1 | 
 |  | 
 | typedef enum { | 
 | 	AUD_PLAYER_ERROR = -1, | 
 | 	AUD_PLAYER_START = 0, | 
 | 	AUD_PLAYER_PAUSE, | 
 | 	AUD_PLAYER_RESUME, | 
 | 	AUD_PLAYER_NODATA,  //Buff no data and play tread will sleep | 
 |     AUD_PLAYER_LESSDATA, //Buff has less data | 
 | 	AUD_PLAYER_FINISHED, | 
 | } Enum_AudPlayer_State; | 
 |  | 
 | struct mopen_audio_t | 
 | { | 
 |     int device; | 
 |     audio_hw_device_t *audio_ahw_dev_ubus; | 
 |     struct audio_stream_in *stream_in; | 
 |     struct audio_stream_out *stream_out; | 
 |     int pcm_packet_size;     //320:NB, 640:WB | 
 |     int pipe_data; | 
 |     int fd[2]; | 
 |     pthread_t pid; | 
 |     mbtk_audio_state_enum state; | 
 |     pthread_mutex_t _cond_mutex; | 
 |     pthread_mutex_t _stream_mutex; | 
 |     void *usrData; | 
 | }; | 
 | struct record_cb_s | 
 | { | 
 |     mbtk_audio_record_cb_func _cb; | 
 |     void *cb_data; | 
 | }; | 
 |  | 
 | static struct mopen_audio_t *internal_hdl = NULL; | 
 |  | 
 | static int dsp_rx_gain = 0xFF; | 
 | static int dsp_tx_gain = 0xFF; | 
 |  | 
 | int mbtk_wav_pcm16Le_check(int fd) | 
 | { | 
 |     printf("MBTK_wav_pcm16Le_check()----------strart5, fd:%d\n", fd); | 
 |     struct wav_header hdr; | 
 |  | 
 |     if (fd <= 0) | 
 |         return -1; | 
 |  | 
 |     if (read(fd, &hdr, sizeof(hdr)) != sizeof(hdr)) | 
 |     { | 
 |         printf("\n%s: cannot read header\n", __FUNCTION__); | 
 |         return -1; | 
 |     } | 
 |  | 
 |         printf("hdr.riff_id:%X, hdr.riff_fmt:%X, hdr.fmt_id:%X", hdr.riff_id, hdr.riff_fmt, hdr.fmt_id); | 
 |  | 
 |     if ((hdr.riff_id != ID_RIFF) | 
 |             || (hdr.riff_fmt != ID_WAVE) | 
 |             || (hdr.fmt_id != ID_FMT)) | 
 |     { | 
 |         printf("\n%s: is not a riff/wave file\n", __FUNCTION__); | 
 |         return -1; | 
 |     } | 
 |  | 
 |     if ((hdr.audio_format != FORMAT_PCM) || (hdr.fmt_sz != 16)) { | 
 |         printf("\n%s: is not pcm format\n", __FUNCTION__); | 
 |         return -1; | 
 |     } | 
 |  | 
 |     if (hdr.bits_per_sample != 16) { | 
 |         printf("\n%s: is not 16bit per sample\n", __FUNCTION__); | 
 |         return -1; | 
 |     } | 
 |  | 
 |     printf("audio_format: %d,num_channels: %d,sample_rate: %d,byte_rate: %d,bits_per_sample:  %d data_sz: %d\n", | 
 |            hdr.audio_format, hdr.num_channels, hdr.sample_rate, hdr.byte_rate, hdr.bits_per_sample, hdr.data_sz); | 
 |  | 
 |     return hdr.data_sz; | 
 | } | 
 |  | 
 |  | 
 | static void simulateOffhook(struct mopen_audio_t *aud_hdl, unsigned int onoff) | 
 | { | 
 |     unsigned int pcm_on; | 
 |     unsigned int DTMFDetectiononoff; | 
 |     unsigned int dialToneToOthersTones; | 
 |     unsigned int dialTonesToOthersDialTones; | 
 |     unsigned int dialVadDuration; | 
 |  | 
 |     pcm_on = onoff; | 
 |     //send the command of "AUDIOSTUB_PCMCTL" | 
 |     aud_hdl->audio_ahw_dev_ubus->switch_pcm(aud_hdl->audio_ahw_dev_ubus, pcm_on); | 
 |  | 
 |     DTMFDetectiononoff = onoff; | 
 |     dialToneToOthersTones = 50; | 
 |     dialTonesToOthersDialTones = 4; | 
 |     dialVadDuration = 3; | 
 |     //send the command of "AUDIOSTUB_DTMFDETECTIONCTL" | 
 |     //vcm_DTMFDetection(1, 50, 4, 3); | 
 |     vcm_DTMFDetection(DTMFDetectiononoff, dialToneToOthersTones, dialTonesToOthersDialTones, dialVadDuration); | 
 |  | 
 |     return; | 
 | } | 
 | static int config_parameters(int in_out, int NBWB) | 
 | { | 
 |     unsigned int direction = 0xFF, type, srcdst, priority, dest; | 
 |     char kvpair[128]; | 
 |     struct str_parms *param = NULL; | 
 |     int data[5]; | 
 |     const char *key = NULL; | 
 |     bool update_vcm = false; | 
 |  | 
 |     direction = in_out;/* 0-play, 1-record */ | 
 |     type = NBWB; /* 0:PCM_NB_BUF_SIZE, 1:PCM_WB_BUF_SIZE */ | 
 |     srcdst = 1;/* 0-None, 1-Near end, 2-Far end, 3-Both ends */ | 
 |     priority = 1;/* 0-Do not combine(override), 1-Combine */ | 
 |     dest = 1;/* 0-Near codec, 1-Near Vocoder */ | 
 |  | 
 |     memset(kvpair, 0x00, 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); | 
 |  | 
 |     mbtk_audio_log("%s: config information kvpair is %s.\n", __FUNCTION__, kvpair); | 
 |  | 
 |     //extract the parameter and config from string | 
 |     param = str_parms_create_str(kvpair); | 
 |     if (!param) { | 
 |         printf("%s: param create str is null!", __FUNCTION__); | 
 |         return -1; | 
 |     } | 
 |  | 
 |     //set vcm configurations | 
 |     key = VCM_CONFIG_DIRECTION; | 
 |     if (str_parms_get_int(param, key, &data[0]) == 0) { | 
 |         update_vcm = true; | 
 |         str_parms_del(param, key); | 
 |     } | 
 |     key = VCM_CONFIG_TYPE; | 
 |     if (str_parms_get_int(param, key, &data[1]) == 0) { | 
 |         update_vcm = true; | 
 |         str_parms_del(param, key); | 
 |     } | 
 |     key = VCM_CONFIG_SRC_DST; | 
 |     if (str_parms_get_int(param, key, &data[2]) == 0) { | 
 |         update_vcm = true; | 
 |         str_parms_del(param, key); | 
 |     } | 
 |     key = VCM_CONFIG_PRIORITY; | 
 |     if (str_parms_get_int(param, key, &data[3]) == 0) { | 
 |         update_vcm = true; | 
 |         str_parms_del(param, key); | 
 |     } | 
 |     key = VCM_CONFIG_DEST; | 
 |     if (str_parms_get_int(param, key, &data[4]) == 0) { | 
 |         update_vcm = true; | 
 |         str_parms_del(param, key); | 
 |     } | 
 |  | 
 |     //printf("Direction is %d, Type is %d, Src_Dst is %d, Priority is %d, Dest is %d. \n",data[0], data[1], data[2], data[3], data[4]); | 
 |  | 
 |     if (update_vcm) { | 
 |         configure_vcm(data);   /*TODO check if all inputs got all values successfully*/ | 
 |     } | 
 |  | 
 |     return 0; | 
 | } | 
 |  | 
 | void mbtk_audio_set_status(void* hdl, mbtk_audio_state_enum _status) | 
 | { | 
 |     struct mopen_audio_t *pcxt = (struct mopen_audio_t *)hdl; | 
 |     if (NULL == hdl || NULL == internal_hdl) | 
 |         return 0; | 
 |     pthread_mutex_lock(&pcxt->_cond_mutex); | 
 |     pcxt->state = _status; | 
 |     pthread_mutex_unlock(&pcxt->_cond_mutex); | 
 | } | 
 |  | 
 |  | 
 | int mbtk_audio_get_status(void* hdl) | 
 | { | 
 |     struct mopen_audio_t *pcxt = (struct mopen_audio_t *)hdl; | 
 |     if (NULL == hdl || NULL == internal_hdl) | 
 |         return 0; | 
 |  | 
 |     return pcxt->state; | 
 | } | 
 |  | 
 | static void* mbtk_record_pthread(void* hdl) | 
 | { | 
 |     struct mopen_audio_t *pcxt = (struct mopen_audio_t *)hdl; | 
 |     struct record_cb_s *_usrData = (struct record_cb_s *)pcxt->usrData; | 
 |     unsigned bufsize = 0; | 
 |     char *data = NULL; | 
 |     int len; | 
 |  | 
 |     if (NULL == hdl) | 
 |         return NULL; | 
 |  | 
 |     bufsize = pcxt->pcm_packet_size; | 
 |     data = calloc(1, bufsize); | 
 |     if (!data) { | 
 |         fprintf(stderr, "\n%s:could not allocate %d bytes\n", __FUNCTION__, bufsize); | 
 |         return NULL; | 
 |     } | 
 |  | 
 |     mbtk_audio_set_status(hdl, AUDIO_RUNNING); | 
 |  | 
 |     while (pcxt->state != AUDIO_STOP) | 
 |     { | 
 |         len = pcxt->stream_in->read(pcxt->stream_in, data, bufsize); | 
 |         if (len < 0) { | 
 |             printf("%s: error reading!\n", __FUNCTION__); | 
 |             break; | 
 |         } | 
 |  | 
 |         if(dsp_tx_gain == 0xFF) { | 
 |             if(!mbtk_dsp_gain_get(&dsp_rx_gain, &dsp_tx_gain)) { | 
 |                 vcm_config_dspgain(CONFIG_DSPGAIN_TX, dsp_tx_gain); | 
 |                 dsp_rx_gain = 0xFF; | 
 |             } | 
 |         } | 
 |  | 
 |         if ((bufsize > 0) && (NULL != _usrData->_cb)) | 
 |         { | 
 |             _usrData->_cb(2, data, bufsize); | 
 |         } | 
 |     } | 
 |     pcxt->pid = 0; | 
 |     if(pcxt->usrData) | 
 |     { | 
 |         free(pcxt->usrData); | 
 |         pcxt->usrData = NULL; | 
 |     } | 
 |     free(data); | 
 |     mbtk_audio_log("pcm pthread end-\n"); | 
 |     return NULL; | 
 | } | 
 |  | 
 | static void* mbtk_play_pthread(void* hdl) | 
 | { | 
 |     struct mopen_audio_t *pcxt = (struct mopen_audio_t *)hdl; | 
 |     _play_callback audio_play_cb = (_play_callback)pcxt->usrData; | 
 |     unsigned bufsize = 0; | 
 |     char *data = NULL; | 
 |     int first_set = 0; | 
 |     int ret = 0; | 
 |     int rc; | 
 |  | 
 |     pthread_detach(pthread_self()); | 
 |     if (NULL == hdl) | 
 |         return NULL; | 
 |  | 
 |     bufsize = pcxt->pcm_packet_size; | 
 |     data = calloc(1, bufsize); | 
 |     if (!data) { | 
 |         fprintf(stderr, "\n%s:could not allocate %d bytes\n",__FUNCTION__,bufsize); | 
 |         pthread_exit(NULL); | 
 |     } | 
 |  | 
 |     while (pcxt->state != AUDIO_STOP && 0 != pcxt->pipe_data) | 
 |     { | 
 |         ret = read(pcxt->fd[0], data, bufsize); | 
 |         // printf("%s:read : %d bytes\n", __FUNCTION__, ret); | 
 |         if(ret == 0) { | 
 |             mbtk_audio_log("%s %d [%d]", __FUNCTION__, __LINE__, ret); | 
 |             continue; | 
 |         } | 
 |         if(ret < 0) { | 
 |             mbtk_audio_log("%s %d [%d]", __FUNCTION__, __LINE__, ret); | 
 |             break; | 
 |         } | 
 |         if ((0 == first_set || AUDIO_RESUME == pcxt->state)) | 
 |         { | 
 |             first_set = 1; | 
 |             mbtk_audio_set_status(hdl, AUDIO_RUNNING); | 
 |             audio_play_cb(pcxt, AUD_PLAYER_RESUME); | 
 |         } | 
 |  | 
 |         pthread_mutex_lock(&pcxt->_stream_mutex); | 
 |         pcxt->pipe_data -= ret; | 
 |         pthread_mutex_unlock(&pcxt->_stream_mutex); | 
 |         if(pcxt->pipe_data < 0) | 
 |             pcxt->pipe_data = 0; | 
 |         if(ret < pcxt->pcm_packet_size) | 
 |             printf("pcm %d - %d\n", pcxt->pipe_data, ret); | 
 |  | 
 |         rc = pcxt->stream_out->write(pcxt->stream_out, data, bufsize); | 
 |         if (rc < 0) { | 
 |             printf("%s: error writing (child).\n", __FUNCTION__); | 
 |             break; | 
 |         } else if (rc < (signed int)pcxt->pcm_packet_size) { | 
 |             printf("%s: wrote less than buffer size, rc=%d.\n", __FUNCTION__, rc); | 
 |             break; | 
 |         } | 
 |     } | 
 |  | 
 |     if (pcxt->fd[0] != 0 && pcxt->fd[1] != 0) | 
 |     { | 
 |         close(pcxt->fd[0]); | 
 |         close(pcxt->fd[1]); | 
 |         pcxt->fd[0] = 0; | 
 |         pcxt->fd[1] = 0; | 
 |         /* printf("close pcxt->fd!\n"); */ | 
 |     } | 
 |     if (audio_play_cb) | 
 |         audio_play_cb(pcxt, AUD_PLAYER_FINISHED); | 
 |     pcxt->pid = 0; | 
 | //    mbtk_audio_set_status(hdl, AUDIO_STOP); | 
 |     mbtk_audio_set_status(hdl, AUDIO_OPEN); | 
 |     free(data); | 
 |     mbtk_audio_log("\n%s:exit!\n", __FUNCTION__); | 
 |     pthread_exit(NULL); | 
 |  | 
 |     return NULL; | 
 | } | 
 |  | 
 | static int audio_init_play_pthread(void* hdl) | 
 | { | 
 |     struct mopen_audio_t *pcxt = (struct mopen_audio_t *)hdl; | 
 |     _play_callback audio_play_cb = (_play_callback)pcxt->usrData; | 
 |     int ret; | 
 |  | 
 |     if (pcxt->fd[0] == 0 && pcxt->fd[1] == 0) { | 
 |         if(pipe(pcxt->fd) == 0) { | 
 |  | 
 |             pcxt->pipe_data = 0; | 
 |             fcntl(pcxt->fd[0], F_SETFL, O_NONBLOCK); | 
 |             fcntl(pcxt->fd[1], F_SETFL, O_NONBLOCK); | 
 |         } else { | 
 |             fprintf(stderr, "\n%d: create pipe error\n", __LINE__); | 
 |             return -1; | 
 |         } | 
 |     } | 
 |     if (pcxt->pid == 0) { | 
 |         if (audio_play_cb) | 
 |             audio_play_cb(pcxt, AUD_PLAYER_START); | 
 |         mbtk_audio_set_status(pcxt, AUDIO_RUNNING); | 
 |         ret = pthread_create(&pcxt->pid, NULL, mbtk_play_pthread, hdl); | 
 |         if (ret != 0) | 
 |         { | 
 |             fprintf(stderr, "\n%s: Failed create pthread\n",__FUNCTION__); | 
 |             return ret; | 
 |         } | 
 |     } | 
 |  | 
 |     return 0; | 
 | } | 
 |  | 
 | int  mbtk_audio_play_wait_end(void* hdl) | 
 | { | 
 |     struct mopen_audio_t *pcxt = (struct mopen_audio_t *)hdl; | 
 |  | 
 |     if (NULL == hdl) | 
 |     { | 
 |         fprintf(stderr, "\n%s: intput invalid params\n",__FUNCTION__); | 
 |         return -1; | 
 |     } | 
 |  | 
 |     if(pcxt->pid != 0) | 
 |     { | 
 |         do{ | 
 |             usleep(10000); | 
 |         } | 
 |         while(pcxt->state != AUDIO_STOP); | 
 |         pcxt->pid = 0; | 
 |     } | 
 |  | 
 |     return 0; | 
 | } | 
 |  | 
 | static int audio_open_pcm(void *dev_hdl, int num_channels, int rate, int in_out) | 
 | { | 
 |     struct mopen_audio_t *pcxt = (struct mopen_audio_t *)dev_hdl; | 
 |     int nb_wb; | 
 |  | 
 |     //Support 8k/16k & mono wave file | 
 |     if (((rate != 8000) && (rate != 16000)) | 
 |             || (num_channels != 1) ) { | 
 |         printf("%s: error wave file:rate = %d, num_channels = %d!! \n", | 
 |                 __FUNCTION__,rate, num_channels); | 
 |         return -1; | 
 |     } | 
 |  | 
 |     printf("%s: success open, rate = %d, num_channels = %d.\n", | 
 |             __FUNCTION__, rate, num_channels); | 
 |  | 
 |     if ((8000 == rate) && (1 == num_channels)) { | 
 |         nb_wb = 0;//NB | 
 |         pcxt->pcm_packet_size = PCM_NB_BUF_SIZE; | 
 |     } else if ((16000 == rate) && (1 == num_channels)) { | 
 |         nb_wb = 1;//WB | 
 |         pcxt->pcm_packet_size = PCM_WB_BUF_SIZE; | 
 |     } | 
 |  | 
 |     //config playback parameters. | 
 |     config_parameters(in_out, nb_wb); | 
 |     pcxt->device = in_out; | 
 |     return 0; | 
 | } | 
 |  | 
 | mbtk_audio_handle mbtk_audio_open(mbtk_audio_dev_enum dev, int flag, int rate, void *usrData) | 
 | { | 
 |     int value = 1; | 
 |     struct mopen_audio_t *aud_hdl = NULL; | 
 |     int ret; | 
 |  | 
 |     // if (dev <= AUDIO_NULL || dev >= AUDIO_MAX) | 
 |     // { | 
 |     //     printf("invaild PCM dev\n"); | 
 |     //     return NULL; | 
 |     // } | 
 |     if(internal_hdl) | 
 |     { | 
 |         printf("Audio device inited\n"); | 
 |         return internal_hdl; | 
 |     } | 
 |     aud_hdl = (struct mopen_audio_t *) calloc(1, sizeof(struct mopen_audio_t)); | 
 |     if (!aud_hdl) | 
 |     { | 
 |         fprintf(stderr, "\n%s:Failed to allocate audio hdl!, errno=%d\n", __FUNCTION__, errno); | 
 |         return NULL; | 
 |     } | 
 |     memset(aud_hdl, 0, sizeof(struct mopen_audio_t)); | 
 |  | 
 |     //init global variables | 
 |     aud_hdl->audio_ahw_dev_ubus = audio_hal_install(); | 
 |     if (aud_hdl->audio_ahw_dev_ubus == NULL) { | 
 |         printf("%s: audio_hal_install failed!\n", __FUNCTION__); | 
 |         goto error; | 
 |     } | 
 |  | 
 |     if(1 == dev) | 
 |     { | 
 |         //send the command of "AUDIOSTUB_PCMCTL" and "AUDIOSTUB_DTMFDETECTIONCTL" to simulate telephone offhook. | 
 |             // ASR Question #80497  Using it causes the recording to crash | 
 |     //    simulateOffhook(aud_hdl, 1); | 
 |         //config playback parameters. | 
 |         config_parameters(0, 0); | 
 |     } | 
 |     ret = audio_open_pcm(aud_hdl, flag, rate, dev); | 
 |     if (ret) | 
 |     { | 
 |         printf("\n%s: pcm open error, errno=%d\n", __FUNCTION__, errno); | 
 |         goto error; | 
 |     } | 
 |     if(1 == dev) | 
 |     { | 
 |         //open the audiostub_ctl, prepare for record and playback | 
 |         VCMInit(); | 
 |         //open record stream | 
 |         ret = aud_hdl->audio_ahw_dev_ubus->open_input_stream(aud_hdl->audio_ahw_dev_ubus, 0, | 
 |                 aud_hdl->audio_ahw_dev_ubus->get_supported_devices(aud_hdl->audio_ahw_dev_ubus), | 
 |                 NULL, &aud_hdl->stream_in, 0, 0, AUDIO_SOURCE_VOICE_CALL); | 
 |     } | 
 |     else | 
 |     { | 
 |         ret = aud_hdl->audio_ahw_dev_ubus->open_output_stream(aud_hdl->audio_ahw_dev_ubus, 0, | 
 |                 aud_hdl->audio_ahw_dev_ubus->get_supported_devices(aud_hdl->audio_ahw_dev_ubus), | 
 |                 AUDIO_OUTPUT_FLAG_DIRECT, NULL, &aud_hdl->stream_out, 0); | 
 |     } | 
 |  | 
 |     if (ret < 0) { | 
 |         printf("%s: error opening output device. rc = %d\n", __FUNCTION__, ret); | 
 |         goto error; | 
 |     } | 
 |     pthread_mutex_init(&aud_hdl->_cond_mutex, NULL); | 
 |     pthread_mutex_init(&aud_hdl->_stream_mutex, NULL); | 
 |     aud_hdl->usrData = usrData; | 
 |     aud_hdl->state = AUDIO_OPEN; | 
 |     /* printf("Mbtk_Audio_Open aud_hdl[%x][%x][%x]\n", aud_hdl, aud_hdl->_mixer_ctl, aud_hdl->_pcm); */ | 
 |     internal_hdl = aud_hdl; | 
 |  | 
 |     return (void *)aud_hdl; | 
 |  | 
 | error: | 
 |     value = 0; | 
 |     free(aud_hdl); | 
 |     return NULL; | 
 | } | 
 |  | 
 |  | 
 | int mbtk_audio_play_stream_old(void *dev_hdl, const void *pData, int len) | 
 | { | 
 |     struct mopen_audio_t *pcxt = (struct mopen_audio_t *)dev_hdl; | 
 |  | 
 |     if (NULL == pcxt || NULL == internal_hdl) | 
 |         return -1; | 
 |  | 
 |     if (len > 1024) { | 
 |         printf("audio play stream max size ( < 1024): %d\n", len); | 
 |         return -2; | 
 |     } | 
 |  | 
 |     if (pcxt->state == AUDIO_STOP) { | 
 |         return 0; | 
 | 	} | 
 |     audio_init_play_pthread(pcxt); | 
 |  | 
 |     pthread_mutex_lock(&pcxt->_stream_mutex); | 
 |     pcxt->pipe_data += len; | 
 |     pthread_mutex_unlock(&pcxt->_stream_mutex); | 
 |     while(pcxt->state != AUDIO_STOP && (pcxt->pipe_data > 40960 || pcxt->fd[1] < 0 || pcxt->fd[1] == 0)) { | 
 |         // printf("%s:wait %d %d\n", __FUNCTION__, pcxt->pipe_data, pcxt->fd[1]); | 
 |         usleep(50000); | 
 |     } | 
 |  | 
 |     if(pcxt->fd[1] > 0) { | 
 |         if (len != write(pcxt->fd[1], pData, len)) { | 
 |             fprintf(stderr, "\n%s: pcm_write failed [%d %d]\n", __FUNCTION__, pcxt->fd[1], errno); | 
 |             return -errno; | 
 |         } | 
 |     } | 
 |  | 
 |     return 0; | 
 | } | 
 |  | 
 | int mbtk_audio_play_stream(void *dev_hdl, const void *pData, int len) | 
 | { | 
 | //    printf("%s,--len:%d\n", __func__, len); | 
 |     unsigned bufsize = 0; | 
 |     char *data = NULL; | 
 |     int first_set = 0; | 
 |     int res = 0; | 
 |     int ret = 0; | 
 |     int read_size = 0; | 
 |     char *p = (char *)pData; | 
 |  | 
 |     struct mopen_audio_t *pcxt = (struct mopen_audio_t *)dev_hdl; | 
 |  | 
 |     if (NULL == dev_hdl || NULL == internal_hdl || pData == NULL) | 
 |         return -1; | 
 |  | 
 |     if(AUDIO_RUNNING == pcxt->state) | 
 |         return -2; | 
 |  | 
 |     bufsize = pcxt->pcm_packet_size; | 
 |     data = calloc(1, bufsize); | 
 |     if (!data) { | 
 |         fprintf(stderr, "\n%s:could not allocate %d bytes\n",__FUNCTION__,bufsize); | 
 |         pthread_exit(NULL); | 
 |     } | 
 |  | 
 |     if(pcxt->state == AUDIO_OPEN) | 
 |     { | 
 |         mbtk_audio_set_status(dev_hdl, AUDIO_RUNNING); | 
 |  | 
 |     } | 
 | //    if(bufsize > len ) | 
 | //    { | 
 | //        bufsize = len; | 
 | //    } | 
 |  | 
 |     while (pcxt->state != AUDIO_STOP) | 
 |     { | 
 |  | 
 |         memcpy(data,p+read_size, bufsize ); | 
 |         read_size += bufsize; | 
 |  | 
 |         if(read_size > len) | 
 |         { | 
 |          //    printf(">[%d]\n", read_size); | 
 |             break; | 
 |         } | 
 |  | 
 |         while(AUDIO_PAUSE == pcxt->state) | 
 |         { | 
 |             usleep(80000); | 
 |         } | 
 |  | 
 |         if ((0 == first_set || AUDIO_RESUME == pcxt->state)) | 
 |         { | 
 |             first_set = 1; | 
 |             mbtk_audio_set_status(dev_hdl, AUDIO_RUNNING); | 
 |         } | 
 |  | 
 |         ret = pcxt->stream_out->write(pcxt->stream_out, data, bufsize); | 
 |         if (ret < 0) { | 
 |             printf("%s: error writing (child).\n", __FUNCTION__); | 
 |             break; | 
 |         } else if (ret < (signed int)pcxt->pcm_packet_size) { | 
 |             printf("%s: wrote less than buffer size, rc=%d.\n", __FUNCTION__, ret); | 
 |             break; | 
 |         } | 
 |  | 
 |         if(read_size == len) | 
 |         { | 
 |          //    printf("=[%d]", read_size); | 
 |             break; | 
 |         } | 
 |  | 
 |     } | 
 |  | 
 |     if(pcxt->state != AUDIO_STOP) | 
 |     { | 
 |         mbtk_audio_set_status(dev_hdl, AUDIO_OPEN); | 
 |     } | 
 |  | 
 |     free(data); | 
 |     return 0; | 
 |  | 
 | } | 
 |  | 
 |  | 
 | int mbtk_audio_play_file(void *dev_hdl, int file_fd, int offset) | 
 | { | 
 |     unsigned bufsize = 0; | 
 |     char *data = NULL; | 
 |     int first_set = 0; | 
 |     int file_data_sz = 0; | 
 |     int res = 0; | 
 |     int ret; | 
 |  | 
 |     struct mopen_audio_t *pcxt = (struct mopen_audio_t *)dev_hdl; | 
 |     _play_callback audio_play_cb = (_play_callback)pcxt->usrData; | 
 |     if (NULL == dev_hdl || NULL == internal_hdl) | 
 |         return -1; | 
 |  | 
 |     if(AUDIO_RUNNING == pcxt->state) | 
 |         return -2; | 
 |  | 
 |     // file_data_sz = mbtk_wav_pcm16Le_check(file_fd); | 
 |     bufsize = pcxt->pcm_packet_size; | 
 |     data = calloc(1, bufsize); | 
 |     if (!data) { | 
 |         fprintf(stderr, "\n%s:could not allocate %d bytes\n",__FUNCTION__,bufsize); | 
 |         pthread_exit(NULL); | 
 |     } | 
 |     if(offset) | 
 |     { | 
 |         lseek(file_fd, offset, SEEK_SET); | 
 |     } | 
 |  | 
 |     mbtk_audio_set_status(dev_hdl, AUDIO_RUNNING); | 
 |     int all_size = 0; | 
 |  | 
 |     while (pcxt->state != AUDIO_STOP) | 
 |     { | 
 |         res = read(file_fd, data, bufsize); | 
 |       //   printf("%s:read : %d bytes\n", __FUNCTION__, res); | 
 |         if(res == 0 || res < 0) | 
 |         { | 
 |              printf("read:[%d]", res); | 
 |             break; | 
 |         } | 
 |  | 
 |         all_size += res; | 
 | //        if (file_data_sz < all_size || file_data_sz == all_size) { | 
 | //            printf("aplay size :%d - %d\n", file_data_sz, all_size); | 
 |  //           break; | 
 |  //       } | 
 |  | 
 |         while(AUDIO_PAUSE == pcxt->state) | 
 |         { | 
 |             usleep(80000); | 
 |             audio_play_cb(pcxt, AUD_PLAYER_PAUSE); | 
 |         } | 
 |  | 
 |         if ((0 == first_set || AUDIO_RESUME == pcxt->state)) | 
 |         { | 
 |             first_set = 1; | 
 |             mbtk_audio_set_status(dev_hdl, AUDIO_RUNNING); | 
 |             audio_play_cb(pcxt, AUD_PLAYER_RESUME); | 
 |         } | 
 |  | 
 |         ret = pcxt->stream_out->write(pcxt->stream_out, data, bufsize); | 
 |         if (ret < 0) { | 
 |             printf("%s: error writing (child).\n", __FUNCTION__); | 
 |             audio_play_cb(pcxt, AUD_PLAYER_ERROR); | 
 |             break; | 
 |         } else if (ret < (signed int)pcxt->pcm_packet_size) { | 
 |             printf("%s: wrote less than buffer size, rc=%d.\n", __FUNCTION__, ret); | 
 |             audio_play_cb(pcxt, AUD_PLAYER_LESSDATA); | 
 |             break; | 
 |         } | 
 |  | 
 |         if(dsp_rx_gain == 0xFF) { | 
 |             if(!mbtk_dsp_gain_get(&dsp_rx_gain, &dsp_tx_gain)) { | 
 |                 vcm_config_dspgain(CONFIG_DSPGAIN_RX, dsp_rx_gain); | 
 |                 dsp_tx_gain = 0xFF; | 
 |             } | 
 |         } | 
 |     } | 
 |     if (audio_play_cb) | 
 |         audio_play_cb(pcxt, AUD_PLAYER_FINISHED); | 
 |  | 
 |     printf("file_data_sz :%d - all_size: %d\n", file_data_sz, all_size); | 
 |     mbtk_audio_set_status(dev_hdl, AUDIO_OPEN); | 
 |     free(data); | 
 |  | 
 |     return 0; | 
 | } | 
 |  | 
 | int mbtk_audio_record(void *dev_hdl, mbtk_audio_record_cb_func cb_func, void *cb_data) | 
 | { | 
 |     struct mopen_audio_t *pcxt = (struct mopen_audio_t *)dev_hdl; | 
 |     int res = -1; | 
 |     struct record_cb_s *_usrData = NULL; | 
 |  | 
 |     if (NULL == pcxt || NULL == internal_hdl || NULL == cb_func) | 
 |         return -1; | 
 |  | 
 |     if(AUDIO_RUNNING == pcxt->state) | 
 |         return -2; | 
 |  | 
 |     _usrData = malloc(sizeof(struct record_cb_s)); | 
 |     _usrData->_cb = cb_func; | 
 |     _usrData->cb_data = cb_data; | 
 |     pcxt->usrData = (void *)_usrData; | 
 |     res = pthread_create(&pcxt->pid, NULL, mbtk_record_pthread, dev_hdl); | 
 |     if (res != 0) | 
 |     { | 
 |         if(pcxt->usrData) | 
 |         { | 
 |             free(pcxt->usrData); | 
 |             pcxt->usrData = NULL; | 
 |         } | 
 |         fprintf(stderr, "\n%s: Failed to create pthread\n", __FUNCTION__); | 
 |     } | 
 |     // 防止重复录音 | 
 |     usleep(500); | 
 |  | 
 |     return res; | 
 | } | 
 |  | 
 | int mbtk_audio_close(void *dev_hdl) | 
 | { | 
 |     printf("mbtk_audio_close()\n"); | 
 |     int value = 0; | 
 |     struct mopen_audio_t *_hdl = (struct mopen_audio_t *)dev_hdl; | 
 |  | 
 |     if (NULL == _hdl || NULL == internal_hdl ) | 
 |     { | 
 |         printf("mbtk_audio_close() fail dev_hdl is NULL\n"); | 
 |         return -1; | 
 |     } | 
 |  | 
 |     mbtk_audio_set_status(_hdl, AUDIO_STOP); | 
 |     if(0 == _hdl->device) { | 
 |         while (_hdl->pid != 0) { | 
 |             usleep(10000); | 
 |         } | 
 |  | 
 |         vcm_playback_drain(0);//wait for drain the AP audiostub queue. | 
 |         usleep(80000);//delay 80ms until DSP play out its buffered data. | 
 |         _hdl->stream_out->common.standby(&_hdl->stream_out->common); | 
 |         _hdl->audio_ahw_dev_ubus->close_output_stream(_hdl->audio_ahw_dev_ubus, _hdl->stream_out); | 
 |     } else { | 
 |  | 
 |         while (_hdl->pid != 0) { | 
 |             sleep(1); | 
 |         } | 
 |         _hdl->stream_in->common.standby(&_hdl->stream_in->common); | 
 |         _hdl->audio_ahw_dev_ubus->close_input_stream(_hdl->audio_ahw_dev_ubus, _hdl->stream_in); | 
 |         VCMDeinit();//close the fd of audiostub_ctl when exit the thread. | 
 |     } | 
 |  | 
 |     audio_hal_uninstall(); | 
 |     pthread_mutex_destroy(&_hdl->_cond_mutex); | 
 |     pthread_mutex_destroy(&_hdl->_stream_mutex); | 
 |     free(_hdl); | 
 |     _hdl = NULL; | 
 |     internal_hdl = NULL; | 
 |  | 
 |     return 0; | 
 | } | 
 |  | 
 | int mbtk_audio_pause(void* dev_hdl) | 
 | { | 
 |     // struct pcm *_pcm = ((struct mopen_audio_t *)dev_hdl)->_pcm; | 
 |  | 
 |     if (NULL == dev_hdl || NULL == internal_hdl) | 
 |         return -1; | 
 |  | 
 |     if (((struct mopen_audio_t *)dev_hdl)->state != AUDIO_RUNNING) | 
 |     { | 
 |         return -1; | 
 |     } | 
 |  | 
 |     // if (ioctl(_pcm->fd, SNDRV_PCM_IOCTL_PAUSE, 1)) | 
 |     // { | 
 |     //     printf("\n%s: cannot pause channel: errno =%d\n",__FUNCTION__,-errno); | 
 |     //     return -errno; | 
 |     // } | 
 |     mbtk_audio_set_status(dev_hdl, AUDIO_PAUSE); | 
 |     return 0; | 
 | } | 
 |  | 
 | int mbtk_audio_resume(void* dev_hdl) | 
 | { | 
 |     if (NULL == dev_hdl || NULL == internal_hdl) | 
 |         return -1; | 
 |  | 
 |     if (((struct mopen_audio_t *)dev_hdl)->state != AUDIO_PAUSE) | 
 |     { | 
 |         return -1; | 
 |     } | 
 |  | 
 |     // if (ioctl(_pcm->fd, SNDRV_PCM_IOCTL_PAUSE, 0)) | 
 |     // { | 
 |     //     printf("\n%s: cannot Resume channel: errno =%d\n", __FUNCTION__, -errno); | 
 |     //     return -errno; | 
 |     // } | 
 |     mbtk_audio_set_status(dev_hdl, AUDIO_RESUME); | 
 |     return 0; | 
 | } | 
 |  | 
 | int mbtk_audio_stop(void* dev_hdl) | 
 | { | 
 |     struct mopen_audio_t *_hdl = (struct mopen_audio_t *)dev_hdl; | 
 |  | 
 |     if (NULL == dev_hdl || NULL == internal_hdl) | 
 |         return -1; | 
 |  | 
 |     // if (ioctl(_hdl->_pcm->fd, SNDRV_PCM_IOCTL_DROP)) | 
 |     // { | 
 |     //     printf("\n%s: cannot Resume channel: errno =%d\n",__FUNCTION__,-errno); | 
 |     //     return -errno; | 
 |     // } | 
 |  | 
 |     mbtk_audio_set_status(dev_hdl, AUDIO_STOP); | 
 |     _hdl->pid = 0; | 
 |  | 
 |     return 0; | 
 | } | 
 |  | 
 | mbtk_audio_state_enum mbtk_audio_state_get(void *hdl) | 
 | { | 
 |     return ((struct mopen_audio_t *)hdl)->state; | 
 | } |