#include #include #include #include #include #include #include #include #include "hiredis/hiredis.h" #include "cJSON.h" //#include "Rk_wake_lock.h" #define SAMPLE_RATE 48000 #define CHANNEL 2 #define REC_DEVICE_NAME "fake_record" #define WRITE_DEVICE_NAME "fake_play" #define JACK_DEVICE_NAME "fake_jack" #define READ_FRAME 960 //(768) #define PERIOD_SIZE (960) //(SAMPLE_RATE/8) #define PERIOD_counts (2) //double of delay 200ms #define BUFFER_SIZE (PERIOD_SIZE * PERIOD_counts) #define MUTE_TIME_THRESHOD (4)//seconds #define MUTE_FRAME_THRESHOD (SAMPLE_RATE * MUTE_TIME_THRESHOD / READ_FRAME)//30 seconds //#define ALSA_READ_FORMAT SND_PCM_FORMAT_S32_LE #define ALSA_READ_FORMAT SND_PCM_FORMAT_S16_LE #define ALSA_WRITE_FORMAT SND_PCM_FORMAT_S16_LE #define paging_channel "volume-event-channel" #define volume_channel "volume-value-channel" /* * Select different alsa pathways based on device type. * LINE_OUT: LR-Mix(fake_play)->EqDrcProcess(ladspa)->Speaker(real_playback) * HEAD_SET: fake_jack -> Headset(real_playback) * BLUETOOTH: device as bluetooth source. */ #define DEVICE_FLAG_LINE_OUT 0x01 #define DEVICE_FLAG_HEAD_SET 0x02 #define DEVICE_FLAG_BLUETOOTH 0x04 static char g_bt_mac_addr[17]; static int g_bt_is_connect; static bool g_system_sleep = false; static bool g_paging_state = false; static bool sip_mute = true; static bool sip_paging = false; static bool DEBUG = false; static bool reset = true; struct timeval tv_begin, tv_end; //gettimeofday(&tv_begin, NULL); extern int set_sw_params(snd_pcm_t *pcm, snd_pcm_uframes_t buffer_size, snd_pcm_uframes_t period_size, char **msg); void alsa_fake_device_record_open(snd_pcm_t** capture_handle,int channels,uint32_t rate) { snd_pcm_hw_params_t *hw_params; snd_pcm_uframes_t periodSize = PERIOD_SIZE; snd_pcm_uframes_t bufferSize = BUFFER_SIZE; int dir = 0; int err; err = snd_pcm_open(capture_handle, REC_DEVICE_NAME, SND_PCM_STREAM_CAPTURE, 0); if (err) { printf( "Unable to open capture PCM device: \n"); exit(1); } printf("snd_pcm_open\n"); //err = snd_pcm_hw_params_alloca(&hw_params); err = snd_pcm_hw_params_malloc(&hw_params); if(err) { fprintf(stderr, "cannot allocate hardware parameter structure (%s)\n",snd_strerror(err)); exit(1); } printf("snd_pcm_hw_params_malloc\n"); err = snd_pcm_hw_params_any(*capture_handle, hw_params); if(err) { fprintf(stderr, "cannot initialize hardware parameter structure (%s)\n",snd_strerror(err)); exit(1); } printf("snd_pcm_hw_params_any!\n"); err = snd_pcm_hw_params_set_access(*capture_handle, hw_params, SND_PCM_ACCESS_RW_INTERLEAVED); // err = snd_pcm_hw_params_set_access(*capture_handle, hw_params, SND_PCM_ACCESS_MMAP_NONINTERLEAVED); if (err) { printf("Error setting interleaved mode\n"); exit(1); } printf("snd_pcm_hw_params_set_access!\n"); err = snd_pcm_hw_params_set_format(*capture_handle, hw_params, ALSA_READ_FORMAT); if (err) { printf("Error setting format: %s\n", snd_strerror(err)); exit(1); } printf("snd_pcm_hw_params_set_format\n"); err = snd_pcm_hw_params_set_channels(*capture_handle, hw_params, channels); if (err) { printf("channels = %d\n",channels); printf( "Error setting channels: %s\n", snd_strerror(err)); exit(1); } printf("channels = %d\n",channels); err = snd_pcm_hw_params_set_buffer_size_near(*capture_handle, hw_params, &bufferSize); if (err) { printf("Error setting buffer size (%ld): %s\n", bufferSize, snd_strerror(err)); exit(1); } printf("bufferSize = %ld\n",bufferSize); err = snd_pcm_hw_params_set_period_size_near(*capture_handle, hw_params, &periodSize, 0); if (err) { printf("Error setting period time (%ld): %s\n", periodSize, snd_strerror(err)); exit(1); } printf("periodSize = %ld\n",periodSize); err = snd_pcm_hw_params_set_rate_near(*capture_handle, hw_params, &rate, 0/*&dir*/); if (err) { printf("Error setting sampling rate (%d): %s\n", rate, snd_strerror(err)); //goto error; exit(1); } printf("Rate = %d\n", rate); /* Write the parameters to the driver */ err = snd_pcm_hw_params(*capture_handle, hw_params); if (err < 0) { printf( "Unable to set HW parameters: %s\n", snd_strerror(err)); //goto error; exit(1); } err = snd_pcm_prepare(*capture_handle); printf("Open record device done \n"); //set_sw_params(*capture_handle,bufferSize,periodSize,NULL); if(hw_params) snd_pcm_hw_params_free(hw_params); } void alsa_fake_device_write_open(snd_pcm_t** write_handle, int channels, uint32_t write_sampleRate, int device_flag) { snd_pcm_hw_params_t *write_params; snd_pcm_uframes_t write_periodSize = PERIOD_SIZE; snd_pcm_uframes_t write_bufferSize = BUFFER_SIZE; int write_err; int write_dir; int i = 10; retry: write_err = snd_pcm_open(write_handle, WRITE_DEVICE_NAME, SND_PCM_STREAM_PLAYBACK, 0); // } if (write_err) { usleep(100*1000); i --; if(i > 0) goto retry; printf( "Unable to open playback PCM device: \n"); exit(1); } //printf( "interleaved mode\n"); // snd_pcm_hw_params_alloca(&write_params); snd_pcm_hw_params_malloc(&write_params); //printf("snd_pcm_hw_params_alloca\n"); snd_pcm_hw_params_any(*write_handle, write_params); write_err = snd_pcm_hw_params_set_access(*write_handle, write_params, SND_PCM_ACCESS_RW_INTERLEAVED); //write_err = snd_pcm_hw_params_set_access(*write_handle, write_params, SND_PCM_ACCESS_MMAP_NONINTERLEAVED); if (write_err) { printf("Error setting interleaved mode\n"); exit(1); } //printf( "interleaved mode\n"); write_err = snd_pcm_hw_params_set_format(*write_handle, write_params, ALSA_WRITE_FORMAT); if (write_err) { printf("Error setting format: %s\n", snd_strerror(write_err)); exit(1); } //printf( "format successed\n"); write_err = snd_pcm_hw_params_set_channels(*write_handle, write_params, channels); if (write_err) { printf( "Error setting channels: %s\n", snd_strerror(write_err)); exit(1); } //printf("channels = %d\n",channels); write_err = snd_pcm_hw_params_set_rate_near(*write_handle, write_params, &write_sampleRate, 0/*&write_dir*/); if (write_err) { printf("Error setting sampling rate (%d): %s\n", write_sampleRate, snd_strerror(write_err)); exit(1); } //printf("setting sampling rate (%d)\n", write_sampleRate); write_err = snd_pcm_hw_params_set_buffer_size_near(*write_handle, write_params, &write_bufferSize); if (write_err) { printf("Error setting buffer size (%ld): %s\n", write_bufferSize, snd_strerror(write_err)); exit(1); } //printf("write_bufferSize = %ld\n",write_bufferSize); write_err = snd_pcm_hw_params_set_period_size_near(*write_handle, write_params, &write_periodSize, 0); if (write_err) { printf("Error setting period time (%ld): %s\n", write_periodSize, snd_strerror(write_err)); exit(1); } //printf("write_periodSize = %ld\n",write_periodSize); #if 0 snd_pcm_uframes_t write_final_buffer; write_err = snd_pcm_hw_params_get_buffer_size(write_params, &write_final_buffer); printf(" final buffer size %ld \n" , write_final_buffer); snd_pcm_uframes_t write_final_period; write_err = snd_pcm_hw_params_get_period_size(write_params, &write_final_period, &write_dir); printf(" final period size %ld \n" , write_final_period); #endif /* Write the parameters to the driver */ write_err = snd_pcm_hw_params(*write_handle, write_params); if (write_err < 0) { printf( "Unable to set HW parameters: %s\n", snd_strerror(write_err)); exit(1); } write_err = snd_pcm_prepare(*write_handle); if(DEBUG) printf("open write device is successful\n"); set_sw_params(*write_handle, write_bufferSize, write_periodSize, NULL); if(write_params) snd_pcm_hw_params_free(write_params); } int set_sw_params(snd_pcm_t *pcm, snd_pcm_uframes_t buffer_size, snd_pcm_uframes_t period_size, char **msg) { snd_pcm_sw_params_t *params; char buf[256]; int err; //snd_pcm_sw_params_alloca(¶ms); snd_pcm_sw_params_malloc(¶ms); if ((err = snd_pcm_sw_params_current(pcm, params)) != 0) { snprintf(buf, sizeof(buf), "Get current params: %s", snd_strerror(err)); //goto fail; exit(1); } /* start the transfer when the buffer is full (or almost full) */ snd_pcm_uframes_t threshold = (buffer_size / period_size) * period_size; if ((err = snd_pcm_sw_params_set_start_threshold(pcm, params, threshold)) != 0) { snprintf(buf, sizeof(buf), "Set start threshold: %s: %lu", snd_strerror(err), threshold); exit(1); } /* allow the transfer when at least period_size samples can be processed */ if ((err = snd_pcm_sw_params_set_avail_min(pcm, params, period_size)) != 0) { snprintf(buf, sizeof(buf), "Set avail min: %s: %lu", snd_strerror(err), period_size); exit(1); } if ((err = snd_pcm_sw_params(pcm, params)) != 0) { snprintf(buf, sizeof(buf), "%s", snd_strerror(err)); exit(1); } if(params) snd_pcm_sw_params_free(params); return 0; } // int is_mute_frame(short *in,unsigned int size) // { // int i; // int mute_count = 0; // if (!size) { // printf("frame size is zero!!!\n"); // return 0; // } // for (i = 0; i < size;i ++) { // if(in[i] != 0) // return 0; // } // return 1; // } /* Determine whether to enter the energy saving mode according to * the value of the environment variable "EQ_LOW_POWERMODE" */ // bool low_power_mode_check() // { // char *value = NULL; // /* env: "EQ_LOW_POWERMODE=TRUE" or "EQ_LOW_POWERMODE=true" ? */ // value = getenv("EQ_LOW_POWERMODE"); // if (value && (!strcmp("TRUE", value) || !strcmp("true", value))) // return true; // return false; // } /* Check device changing. */ // int get_device_flag() // { // int fd = 0, ret = 0; // char buff[512] = {0}; // int device_flag = DEVICE_FLAG_LINE_OUT; // const char *path = "/sys/devices/platform/ff560000.acodec/rk3308-acodec-dev/dac_output"; // FILE *pp = NULL; /* pipeline */ // char *bt_mac_addr = NULL; // if (g_bt_is_connect) // return DEVICE_FLAG_BLUETOOTH; // fd = open(path, O_RDONLY); // if (fd < 0) { // printf("Open %s failed!\n", path); // return device_flag; // } // ret = read(fd, buff, sizeof(buff)); // if (ret <= 0) { // printf("Read %s failed!\n", path); // close(fd); // return device_flag; // } // if (strstr(buff, "hp out")) // device_flag = DEVICE_FLAG_HEAD_SET; // close(fd); // return device_flag; // } /* Get device name frome device_flag */ // const char *get_device_name(int device_flag) // { // const char *device_name = NULL; // switch (device_flag) { // case DEVICE_FLAG_BLUETOOTH: // device_name = "BLUETOOTH"; // break; // case DEVICE_FLAG_HEAD_SET: // device_name = JACK_DEVICE_NAME; // break; // case DEVICE_FLAG_LINE_OUT: // device_name = WRITE_DEVICE_NAME; // break; // default: // break; // } // return device_name; // } // void *a2dp_status_listen(void *arg) // { // int ret = 0; // char buff[100] = {0}; // struct sockaddr_un clientAddr; // struct sockaddr_un serverAddr; // int sockfd; // socklen_t addr_len; // char *start = NULL; // snd_pcm_t* audio_bt_handle; // char bluealsa_device[256] = {0}; // int retry_cnt = 5; // sockfd = socket(AF_UNIX, SOCK_DGRAM, 0); // if (sockfd < 0) { // printf("Create socket failed!\n"); // return NULL; // } // serverAddr.sun_family = AF_UNIX; // strcpy(serverAddr.sun_path, "/tmp/a2dp_master_status"); // system("rm -rf /tmp/a2dp_master_status"); // ret = bind(sockfd, (struct sockaddr *)&serverAddr, sizeof(serverAddr)); // if (ret < 0) { // printf("Bind Local addr failed!\n"); // return NULL; // } // while(1) { // memset(buff, 0, sizeof(buff)); // ret = recvfrom(sockfd, buff, sizeof(buff), 0, (struct sockaddr *)&clientAddr, &addr_len); // if (ret <= 0) // break; // printf("###### FUCN:%s. Received a malformed message(%s)\n", __func__, buff); // if (strstr(buff, "status:connect")) { // start = strstr(buff, "address:"); // if (start == NULL) { // printf("FUCN:%s. Received a malformed message(%s)\n", __func__, buff); // continue; // } // start += strlen("address:"); // if (!g_bt_is_connect) { // sleep(2); // memcpy(g_bt_mac_addr, start, sizeof(g_bt_mac_addr)); // sprintf(bluealsa_device, "%s%s", "bluealsa:HCI=hci0,PROFILE=a2dp,DEV=", // g_bt_mac_addr); // retry_cnt = 5; // while (retry_cnt--) { // ret = snd_pcm_open(&audio_bt_handle, bluealsa_device, // SND_PCM_STREAM_PLAYBACK, 0); // if (ret == 0) { // snd_pcm_close(audio_bt_handle); // g_bt_is_connect = 1; // } // usleep(600000); //600ms * 5 = 3s. // } // } // } else if (strstr(buff, "status:disconnect")) { // g_bt_is_connect = 0; // } else if (strstr(buff, "status:suspend")) { // g_system_sleep = true; // } else if (strstr(buff, "status:resume")) { // g_system_sleep = false; // } else { // printf("FUCN:%s. Received a malformed message(%s)\n", __func__, buff); // } // } // close(sockfd); // return NULL; // } //Paging状态监控 void ProcessReply( redisReply * pReply ) { cJSON *pJson; redisReply * pSubReply = NULL; if ( pReply != NULL && pReply->elements == 3 ) { pSubReply = pReply->element[2]; // if(DEBUG) // printf( "Msg [%s]\n", pSubReply->str ); if(DEBUG) printf( "Msg [%s]\n", pSubReply->str ); pJson = cJSON_Parse(pSubReply->str); if ( pJson ) { if(strcmp(cJSON_GetObjectItem(pJson, "name")->valuestring, "SIP") == 0 && strcmp(cJSON_GetObjectItem(pJson, "action")->valuestring, "on") == 0) { //通话 //usleep(100*1000); sip_paging = true; if(reset) g_paging_state = true; } else if(strcmp(cJSON_GetObjectItem(pJson, "name")->valuestring, "SIP") == 0 && strcmp(cJSON_GetObjectItem(pJson, "action")->valuestring, "off") == 0) { //通话 //usleep(100*1000); sip_paging = false; g_paging_state = false; } } } } void *paging_status_listen(void *arg) { redisContext * pContext = redisConnect( "127.0.0.1", 6379 ); if ( NULL == pContext || pContext->err == 1 ) { printf( "%s\n", pContext->errstr ); exit( -1 ); } void* replyPtr = redisCommand( pContext, "SUBSCRIBE %s", paging_channel ); redisReply* pReply = static_cast(replyPtr); freeReplyObject( pReply ); while ( redisGetReply( pContext, (void **)&pReply ) == REDIS_OK ) { ProcessReply( pReply ); freeReplyObject( pReply ); } redisFree( pContext ); return NULL; } //解析音量设置数据 void ProcessVolumeReply( redisReply * pReply ) { cJSON *pJson; redisReply * pSubReply = NULL; if ( pReply != NULL && pReply->elements == 3 ) { pSubReply = pReply->element[2]; if(DEBUG) printf( "Msg [%s]\n", pSubReply->str ); pJson = cJSON_Parse(pSubReply->str); if ( pJson ) { if(cJSON_GetArraySize(pJson) > 11 && cJSON_GetObjectItem(pJson, "sip_volume")->valueint != 0 && cJSON_GetObjectItem(pJson, "onvif_volume")->valueint != 0 && cJSON_GetObjectItem(pJson, "broadcast_volume")->valueint != -1 && cJSON_GetObjectItem(pJson, "multicast_1_volume")->valueint != 0) { reset = true; return; } if(cJSON_GetObjectItem(pJson, "sip_volume")) { if(cJSON_GetObjectItem(pJson, "sip_volume")->valueint == 0) { sip_mute == true; g_paging_state = false; } else { sip_mute == false; if(sip_paging) g_paging_state = true; } reset = false; } cJSON_Delete(pJson); }else{ printf( "parse failed!\n"); } } } /* * 订阅音量信息. */ void *get_volume_info(void * arg) { redisContext * pContext = redisConnect( "127.0.0.1", 6379 ); if ( NULL == pContext || pContext->err == 1 ) { printf( "%s\n", pContext->errstr ); exit( -1 ); } void* replyPtr = redisCommand( pContext, "SUBSCRIBE %s", volume_channel ); redisReply* pReply = static_cast(replyPtr); freeReplyObject( pReply ); while ( redisGetReply( pContext, (void **)&pReply ) == REDIS_OK ) { ProcessVolumeReply( pReply ); freeReplyObject( pReply ); } redisFree( pContext ); return NULL; } int main(int argc, char *argv[]) { snd_pcm_t *capture_handle; snd_pcm_t *write_handle; int err; short buffer[READ_FRAME * 2]; unsigned int sampleRate; unsigned int channels; //int mute_frame_thd; //int mute_frame; /* LINE_OUT is the default output device */ int device_flag, new_flag; pthread_t paging_status_listen_thread; pthread_t volume_value_listen_thread; //struct rk_wake_lock* wake_lock; //bool low_power_mode = low_power_mode_check(); char *silence_data = (char *)calloc(READ_FRAME * 2 * 2, 1);//2ch 16bit int mute_times; if(argc == 2 && strcmp(argv[1], "debug") == 0) DEBUG = true; //wake_lock = RK_wake_lock_new("eq_drc_process"); /* Create a thread to listen for Paging connection status. */ //pthread_create(&paging_status_listen_thread, NULL, paging_status_listen, NULL); /* Create a thread to listen for Volume connection status. */ //pthread_create(&volume_value_listen_thread, NULL, get_volume_info, NULL); repeat: capture_handle = NULL; write_handle = NULL; err = 0; memset(buffer, 0, sizeof(buffer)); sampleRate = SAMPLE_RATE; channels = CHANNEL; //mute_frame_thd = (int)MUTE_FRAME_THRESHOD; //mute_frame = 0; /* LINE_OUT is the default output device */ device_flag = DEVICE_FLAG_LINE_OUT; new_flag = DEVICE_FLAG_LINE_OUT; printf("\n==========EQ/DRC process release version 1.23===============\n"); alsa_fake_device_record_open(&capture_handle, channels, sampleRate); alsa_fake_device_write_open(&write_handle, channels, sampleRate, device_flag); //RK_acquire_wake_lock(wake_lock); while (1) { err = snd_pcm_readi(capture_handle, buffer , READ_FRAME); if (err != READ_FRAME) printf("====read frame error = %d===\n",err); if (err < 0) { if (err == -EPIPE) printf( "Overrun occurred: %d\n", err); err = snd_pcm_recover(capture_handle, err, 0); // Still an error, need to exit. if (err < 0) { printf( "Error occured while recording: %s\n", snd_strerror(err)); usleep(200 * 1000); if (capture_handle) snd_pcm_close(capture_handle); if (write_handle) snd_pcm_close(write_handle); goto repeat; } } // if(g_paging_state) { // /* Reassign to avoid overflow */ // if (write_handle) { // system("echo 1 > /sys/class/gpio/gpio5/value"); // snd_pcm_drop(write_handle); // snd_pcm_close(write_handle); // //RK_release_wake_lock(wake_lock); // if(DEBUG) printf("close write handle for you!!!\n "); // write_handle = NULL; // } // continue; // } // while (write_handle == NULL) { // alsa_fake_device_write_open(&write_handle, channels, sampleRate, device_flag); // if (write_handle == NULL) { // printf("Route change failed! Using default audio path.\n"); // device_flag = DEVICE_FLAG_LINE_OUT; // } // int i, num = PERIOD_counts / 2; // for (i = 0; i < num; i++) { // err = snd_pcm_writei(write_handle, silence_data, READ_FRAME); // if(err != READ_FRAME) // printf("====write frame error = %d, not %d\n",err, READ_FRAME); // } // if(!reset) system("/etc/scripts/pa_mute.sh 0 &"); // } err = snd_pcm_writei(write_handle, buffer, READ_FRAME); if (-EPIPE == err) { snd_pcm_prepare(write_handle); err = snd_pcm_writei(write_handle, buffer, READ_FRAME); if (err < 0) { printf("alsa: write error: %s\n", snd_strerror((int) err)); } } else if (err < 0) { printf("alsa: write error: %s\n", snd_strerror((int) err)); } else if (err != READ_FRAME) { printf("alsa: write: wrote %d of %d samples\n", (int) err, READ_FRAME); } // if(err != READ_FRAME) // printf("====write frame error = %d===\n",err); // if (err < 0) { // if (err == -EPIPE) // printf("Underrun occurred from write: %d\n", err); // err = snd_pcm_recover(write_handle, err, 0); // if (err < 0) { // printf( "Error occured while writing: %s\n", snd_strerror(err)); // usleep(200 * 1000); // if (write_handle) { // snd_pcm_close(write_handle); // write_handle = NULL; // } // // if (device_flag == DEVICE_FLAG_BLUETOOTH) // // g_bt_is_connect = 0; // } // } } error: if (capture_handle) snd_pcm_close(capture_handle); if (write_handle) snd_pcm_close(write_handle); // pthread_cancel(paging_status_listen_thread); // pthread_join(paging_status_listen_thread, NULL); // pthread_cancel(volume_value_listen_thread); // pthread_join(volume_value_listen_thread, NULL); return 0; }