#include #include #include #include #include #include #include #include #include #include #include #include #include "hiredis/hiredis.h" #include "cjson/cJSON.h" #include "iniparser/iniparser.h" #include "log.h" #define Boolean int #define TRUE 1 #define FALSE 0 #define MAX_PIPE_BUFSIZE 256 //KEYS #define UNKEY 0 #define KEY 1 #define KEY2_3 2 #define KEY2_10 3 #define OPEN 4 #define CLOSED 4 //SCHEDULE STATE #define ERROR -1 #define STOP 0 #define RUNNING 1 #define PAUSED 2 #define MAX_PRIORITY 10 #define MAX_TRY 3 //BARESIP_STATUS #define IDLE 0 #define INUSE 1 #define RING 2 #define RINGING 3 #define HOLD 4 #define OFFLINE 5 #define DIALING 6 //BARESIP_REG #define REGISTER_FAIL 0 #define REGISTER_OK 1 //LED_STATUS #define Led_Off 0 #define Led_On 1 #define Led_Fast 2 #define Led_Slow 3 //REDIS_CHANNEL #define BARESIP_CHAN 0 #define GPIO_CHAN 1 //GPIO_STATUS #define GPIO_OFF 0 #define GPIO_ON 1 #define SPK_CONF "/etc/speaker.conf" #define VOL_CONF "/oem/etc/volctrl.conf" #define SIPLOGPATH "/userdata/system.csv" #define CDR_CSV "/userdata/cdr.csv" #define SCHEDULE_CONF "/oem/etc/schedule.conf" #define unix_socket_path "/tmp/redis.sock" //operator log type #define BTN "BUTTON" #define FUN "FUNCTION" #define STA "SIP STATE" #define SCHED "SCHEDULE" #define GPIO_RELAY "gpio112" #define VAR_IP "${ip}" #define VAR_MAC "${mac}" #define VAR_UA "${ua}" #define VAR_NUM "${number}" #define AUDIO_ON "{\"name\": \"SCHEDULER-AUDIO\", \"action\": \"on\"}" #define AUDIO_OFF "{\"name\": \"SCHEDULER-AUDIO\", \"action\": \"off\"}" struct date{ //声明结构体date用于表示日期 int year; int month; int day; }; struct VLC_INFO{ pid_t pid; int prio; char param[96]; }; typedef struct _playInfo{ int key_id; int prio; int vol; char file[64]; char times_str[8]; char enBeep[8]; char enSrceen[8]; } PlayInfo; struct CALL_LOG{ char date[16]; char start[16]; char end[16]; char acc[32]; char num[32]; char direct[8]; char status[16]; time_t answerTime; int duration; char desc[64]; }; typedef struct { int in_use[5]; redisContext *context[5]; const char *socket_path; time_t last_activity[5]; pthread_mutex_t lock; } redis_client_t; static int BARESIP_STATUS = OFFLINE; static int CURRENT_KEY = UNKEY; static int DEBUG = FALSE; static int ACCOUNT1_REG = REGISTER_FAIL; static int ACCOUNT2_REG = REGISTER_FAIL; static int ACCOUNT3_REG = REGISTER_FAIL; static int ACCOUNTP2P_REG = REGISTER_FAIL; static int press_down = FALSE; static int CURRENT_CALLS = 0; static int regcount = 0; static char DTMF_STRING[32] = "\0"; static int SCHEDULE[31]; struct VLC_INFO vlcInfo[64]; struct CALL_LOG callInfo; static redis_client_t *redisClient; redis_client_t* create_redis_pool_client(const char *socket_path) { redis_client_t *client = (redis_client_t *) malloc(sizeof(redis_client_t)); client->socket_path = socket_path; pthread_mutex_init(&client->lock, NULL); for(int i = 0; i < 5; i++) { redisContext *c = redisConnectUnix(socket_path); if (c == NULL || c->err) { if (c) { printf("Connection error: %s\n", c->errstr); redisFree(c); } else { printf("Connection error: can't allocate redis context\n"); } // 可以选择重试或退出 continue; } client->context[i] = c; client->in_use[i] = FALSE; client->last_activity[i] = time(NULL); } return client; } const int redis_pool_get_context(redis_client_t *client) { pthread_mutex_lock(&client->lock); redisContext *context = NULL; int idx = -1; for(int i = 0;i < 5; i++) { if(!client->in_use[i]) { idx = i; client->in_use[idx] = TRUE; context = client->context[idx]; redisReply *reply = redisCommand(context, "PING"); if (reply == NULL || context->err) { // 连接失效,尝试重连 if(DEBUG) printf( "redis connect failed, retry!\n" ); redisFree(context); context = redisConnectUnix(client->socket_path); client->context[idx] = context; } freeReplyObject(reply); client->last_activity[idx] = time(NULL); break; } } pthread_mutex_unlock(&client->lock); if (context == NULL) { printf("No available connections in pool\n"); } return idx; } // 释放连接 void redis_pool_release_connection(redis_client_t *client, const int id) { pthread_mutex_lock(&client->lock); client->in_use[id] = FALSE; pthread_mutex_unlock(&client->lock); } void redis_command_safe(const char *format, const char *value) { const int id = redis_pool_get_context(redisClient); if (id != -1) { redisReply *reply = (redisReply *) redisCommand(redisClient->context[id], format, value); if (reply) { // 处理回复 freeReplyObject(reply); } redis_pool_release_connection(redisClient, id); } } int ensure_connected(redisContext *context) { if (context == NULL || context->err) { if (context) { redisFree(context); } context = redisConnectUnix(unix_socket_path); if (context == NULL || context->err) { return -1; // 连接失败 } } return 0; } void reset_callInfo() { memset(&callInfo,0,sizeof(callInfo)); callInfo.duration = 0; } void *write_opnlog() { char * pKey = "writelog-channel"; redisReply *pReply, *pSubReply; redisContext *redisLogContext = NULL; redisLogContext = redisConnectUnix(unix_socket_path); restart: FILE *logFp = fopen(SIPLOGPATH, "a"); log_add_fp(logFp, LOG_INFO); while(1) { pReply = NULL; if (ensure_connected(redisLogContext) == 0) { pReply = redisCommand( redisLogContext, "BRPOP %s 60", pKey ); if(pReply != NULL && pReply->type == REDIS_REPLY_ARRAY){ pSubReply = NULL; if ( pReply->elements == 2 ) { pSubReply = pReply->element[1]; if(DEBUG) printf( "opnLog [%s]\n", pSubReply->str ); if(strcmp(pSubReply->str, "log_clean") == 0) { fclose(logFp); freeReplyObject( pReply ); sleep(5); goto restart; } else log_info("%s", pSubReply->str); } } } if(pReply != NULL) freeReplyObject( pReply ); usleep(200*1000); } redisFree( redisLogContext ); } void writeLog(char *type,char *action, char *remark) { char logstr[256]; sprintf(logstr, "%s,%s,%s", type, action, remark); redis_command_safe("LPUSH writelog-channel %s", logstr); } //发送状态指令 void state_event(char *info) { redis_command_safe("PUBLISH volume-event-channel %s", info); } //发送屏幕显示指令 void screen_control(char *cmd) { redis_command_safe("PUBLISH screen-channel %s", cmd); } void insert_call_log() { FILE *cdr_fp = fopen(CDR_CSV, "a"); //日期,开始时间,结束时间,账号,号码,通话时长,方向,状态,描述 fprintf(cdr_fp, "%s,%s,%s,%s,%s,%d,%s,%s,%s\n", callInfo.date, callInfo.start, callInfo.end, callInfo.acc, callInfo.num, callInfo.duration, callInfo.direct, callInfo.status, callInfo.desc); fclose(cdr_fp); reset_callInfo(); } void setIncomingCallInfo(char *accuri, char *num) { char acc[32]; time_t nSeconds; struct tm *pTM; int year, month, hour; time(&nSeconds); pTM = localtime(&nSeconds); year = pTM->tm_year + 1900; month = pTM->tm_mon + 1; memset(acc,0,sizeof(acc)); strcpy(callInfo.direct,"in"); sprintf(callInfo.date, "%d-%02d-%02d", year, month, pTM->tm_mday); sprintf(callInfo.start, "%02d:%02d:%02d", pTM->tm_hour, pTM->tm_min, pTM->tm_sec); //strncpy(acc, accuri, strchr(accuri,'@') - accuri); //strcpy(callInfo.acc, acc + 4); strcpy(callInfo.acc, accuri); strcpy(callInfo.num, num); strcpy(callInfo.status, "MISSED CALL"); } void setOutgoingCallInfo(char *accuri, char *num) { char acc[32]; time_t nSeconds; struct tm *pTM; int year, month, hour; time(&nSeconds); pTM = localtime(&nSeconds); year = pTM->tm_year + 1900; month = pTM->tm_mon + 1; memset(acc,0,sizeof(acc)); strcpy(callInfo.direct,"out"); sprintf(callInfo.date, "%d-%02d-%02d", year, month, pTM->tm_mday); sprintf(callInfo.start, "%02d:%02d:%02d", pTM->tm_hour, pTM->tm_min, pTM->tm_sec); //strncpy(acc, accuri, strchr(accuri,'@') - accuri); //strcpy(callInfo.acc, acc + 4); strcpy(callInfo.acc, accuri); strcpy(callInfo.num, num); strcpy(callInfo.status, "NO ANSWER"); } void setAnswerCallInfo() { time_t nSeconds; time(&nSeconds); callInfo.answerTime = nSeconds; strcpy(callInfo.status, "ANSWERED"); } void setClosedCallInfo(char *param) { time_t nSeconds; struct tm *pTM; time(&nSeconds); pTM = localtime(&nSeconds); sprintf(callInfo.end, "%02d:%02d:%02d", pTM->tm_hour, pTM->tm_min, pTM->tm_sec); strcpy(callInfo.desc, param); if(callInfo.answerTime) { callInfo.duration = nSeconds - callInfo.answerTime; } insert_call_log(); } /* * @file 文件路径 * @value 命令结果指针 * @lenth 存储结果长度 */ int GetCmdValue(char *file, char *key, char *value, int lenth) { dictionary * ini ; ini = iniparser_load(file); if (ini==NULL) { fprintf(stderr, "cannot parse file: %s\n", file); return FALSE ; } strcpy(value, iniparser_getstring(ini, key, "")); if(DEBUG) printf("keystr: \"%s\" ; value: %s.\n", key, value); iniparser_freedict(ini); return TRUE; } char *strrpl(char *s, const char *s1, const char *s2) { char *ptr; while (ptr = strstr(s, s1)) /* 如果在s中找到s1 */ { memmove(ptr + strlen(s2) , ptr + strlen(s1), strlen(ptr) - strlen(s1) + 1); memcpy(ptr, &s2[0], strlen(s2)); } return s; } //控制功放的开启/关闭,TRUE/FALSE void amplifier_switch(Boolean enable){ if(enable) system("echo 1 > /sys/class/gpio/gpio5/value"); else system("echo 0 > /sys/class/gpio/gpio5/value"); } Boolean get_ip(char * pv) { FILE * fp; char cmdbuf[128], value[32]; char *tmp=NULL; sprintf(cmdbuf,"/sbin/ifconfig eth1 | grep 'inet ' | awk '{print $2}'"); fp = popen(cmdbuf, "r"); if (fp == NULL) { // printf("Fail to open pipe\n"); return FALSE; } memset(value,0,sizeof(value)); if (!feof(fp) && fgets(value,32,fp) != NULL) ; // printf("value:%s\n", value); else { printf("ip wrong\n"); return FALSE; } pclose(fp); if(strlen(value) < 10) return FALSE; if(tmp = strstr(value,"\n")) { *tmp = '\0'; } strcpy(pv,value); return TRUE; } Boolean get_mac(char * pv) { FILE * fp; char cmdbuf[128], value[32]; char *tmp=NULL; sprintf(cmdbuf,"ifconfig eth1 | grep ether | tr -d : | awk '{print $2}'"); fp = popen(cmdbuf, "r"); if (fp == NULL) { return FALSE; } memset(value,0,sizeof(value)); if (!feof(fp) && fgets(value,32,fp) != NULL) ; // printf("value:%s\n", value); else { printf("ip wrong\n"); return FALSE; } pclose(fp); if(strlen(value) < 10) return FALSE; if(tmp = strstr(value,"\n")) { *tmp = '\0'; } strcpy(pv,value); return TRUE; } int PlayIP() { //add by ssc 2019-12-26 char language[32]; GetCmdValue(SPK_CONF, "system:language", language, sizeof(language)); char ipaddr[16],cmd_line[240]; system("/usr/bin/amixer -q sset 'Master',0 29"); amplifier_switch(TRUE); //开启功放 if(!get_ip(ipaddr)) { if (strcmp(language, "en") == 0){ system("mpg123 -r 48000 /usr/share/sounds/en/get_ip_failed.mp3"); }else{ system("mpg123 -r 48000 /usr/share/sounds/cn/get_ip_failed.mp3"); } return 0; } if (strcmp(language, "en") == 0){ strcpy(cmd_line,"cd /usr/share/sounds/en/;mpg123 -r 48000 "); }else{ strcpy(cmd_line,"cd /usr/share/sounds/cn/;mpg123 -r 48000 "); } int i; for (i=0;i/dev/null &",url); if(DEBUG) printf( "Command: %s\n", cmd); system(cmd); } void playBeep() { char beep[8]; GetCmdValue(VOL_CONF, "volume:key_beep", beep, sizeof(beep)); if(strcmp(beep, "yes") == 0) { if(BARESIP_STATUS == IDLE || BARESIP_STATUS == OFFLINE) system("/usr/sbin/redis-cli PUBLISH volume-event-channel '{\"name\": \"SIP\", \"action\": \"on\"}'"); system("mpg123 /home/new-speaker/target/share/sounds/beep.mp3"); usleep(400*1000); if(BARESIP_STATUS == IDLE || BARESIP_STATUS == OFFLINE) system("/usr/sbin/redis-cli PUBLISH volume-event-channel '{\"name\": \"SIP\", \"action\": \"off\"}'"); //关闭功放 } } //发送控制指令 void control_cmd(int channel, char *cmd) { char redisCmd[256]; switch (channel) { case BARESIP_CHAN: if(DEBUG) printf( "control-channel [%s]\n", cmd ); redis_command_safe("LPUSH control-channel %s", cmd ); break; case GPIO_CHAN: if(DEBUG) printf( "output-channel [%s]\n", cmd ); redis_command_safe("LPUSH output-channel %s", cmd ); break; default: redis_command_safe("LPUSH control-channel %s", cmd ); break; } } void relayControl(char *id, int enable){ char cmd[64]; int channel = GPIO_CHAN; if(enable){ char output_type[32]; GetCmdValue(SPK_CONF, "relay_ctrl:type", output_type, sizeof(output_type)); sprintf(cmd,"{\"id\":\"%s\",\"type\":\"%s\"}",id,output_type); control_cmd(channel,cmd); } else { sprintf(cmd,"{\"id\":\"%s\",\"type\":\"Off\"}",id); control_cmd(channel,cmd); } } void screenControl(int enable){ char cmd[64], output_type[16]; GetCmdValue(SPK_CONF, "screen_ctrl:type", output_type, sizeof(output_type)); if(enable){ sprintf(cmd,"{\"action\": \"on\", \"id\": %s}",output_type); screen_control(cmd); } else { sprintf(cmd,"{\"action\": \"off\", \"id\": %s}",output_type); screen_control(cmd); } } //relay延时控制 void *relayDelayControl() { char delay[8]; GetCmdValue(SPK_CONF, "relay_ctrl:duration", delay, sizeof(delay)); usleep(atoi(delay)*1000*1000); relayControl(GPIO_RELAY, GPIO_OFF); if(DEBUG) printf( "GPIO_RELAY set off\n" ); } //srceen延时控制 void *screenDelayControl() { char delay[8]; GetCmdValue(SPK_CONF, "screen_ctrl:duration", delay, sizeof(delay)); usleep(atoi(delay)*1000*1000); screenControl(FALSE); if(DEBUG) printf( "screen set off\n" ); } void *key1ScreenDelayControl() { char delay[8], srceen_id[16], strtmp[64]; GetCmdValue(SPK_CONF, "intercom:screen_duration", delay, sizeof(delay)); usleep(atoi(delay)*1000*1000); GetCmdValue(SPK_CONF, "intercom:trigger_id", srceen_id, sizeof(srceen_id)); sprintf(strtmp,"{\"action\": \"off\", \"id\": %s}",srceen_id); screen_control(strtmp); if(DEBUG) printf( "screen set off\n" ); } void *key2ScreenDelayControl() { char delay[8], srceen_id[16], strtmp[64]; GetCmdValue(SPK_CONF, "intercom:screen_2_duration", delay, sizeof(delay)); usleep(atoi(delay)*1000*1000); GetCmdValue(SPK_CONF, "intercom:trigger_2_id", srceen_id, sizeof(srceen_id)); sprintf(strtmp,"{\"action\": \"off\", \"id\": %s}",srceen_id); screen_control(strtmp); if(DEBUG) printf( "screen set off\n" ); } //呼入触发 void incomingTrigger() { char relay_call_state[8],relay_state_info[16],relay_mode[16]; GetCmdValue(SPK_CONF, "relay_ctrl:call_state", relay_call_state, sizeof(relay_call_state)); GetCmdValue(SPK_CONF, "relay_ctrl:state_info", relay_state_info, sizeof(relay_state_info)); if( strcmp(relay_call_state, "yes") == 0 && ( strcmp(relay_state_info, "incoming") == 0 || strcmp(relay_state_info, "both") == 0 ) ) { relayControl(GPIO_RELAY, GPIO_ON); if(DEBUG) printf( "GPIO_RELAY set on\n" ); //gpio触发后判断是否为延时复位 GetCmdValue(SPK_CONF, "relay_ctrl:mode", relay_mode, sizeof(relay_mode)); if( strcmp(relay_mode, "delay") == 0 ) { int ret_thrd_delay; pthread_t thread_delay; ret_thrd_delay = pthread_create(&thread_delay, NULL, relayDelayControl, NULL); if (ret_thrd_delay != 0) { printf("create thread_delay relayDelayControl failed\n"); return; } pthread_detach(thread_delay); } } } //呼出触发 void outgoingTrigger() { char relay_call_state[8],relay_state_info[16],relay_mode[16]; char screen_call_state[8], screen_state_info[16], screen_mode[16]; GetCmdValue(SPK_CONF, "relay_ctrl:call_state", relay_call_state, sizeof(relay_call_state)); GetCmdValue(SPK_CONF, "relay_ctrl:state_info", relay_state_info, sizeof(relay_state_info)); if( strcmp(relay_call_state, "yes") == 0 && ( strcmp(relay_state_info, "outgoing") == 0 || strcmp(relay_state_info, "both") == 0 ) ) { relayControl(GPIO_RELAY, GPIO_ON); if(DEBUG) printf( "GPIO_RELAY set on\n" ); //gpio触发后判断是否为延时复位 GetCmdValue(SPK_CONF, "relay_ctrl:mode", relay_mode, sizeof(relay_mode)); if( strcmp(relay_mode, "delay") == 0 ) { int ret_thrd_delay; pthread_t thread_delay; ret_thrd_delay = pthread_create(&thread_delay, NULL, relayDelayControl, NULL); if (ret_thrd_delay != 0) { printf("create thread_delay relayDelayControl failed\n"); return; } pthread_detach(thread_delay); } } } //应答触发 void answeredTrigger() { char cmd[MAX_PIPE_BUFSIZE]; char local_beep[4], local_beep_file[64], local_beep_volume[4]; char remote_beep[4], remote_beep_file[64], remote_beep_volume[4]; char relay_call_state[8],relay_state_info[16],relay_mode[16]; char screen_call_state[8], screen_state_info[16], screen_mode[16]; setAnswerCallInfo(); //判断RELAY是否需要应答复位 GetCmdValue(SPK_CONF, "relay_ctrl:mode", relay_mode, sizeof(relay_mode)); if( strcmp(relay_mode, "answered") == 0 ) { relayControl(GPIO_RELAY, GPIO_OFF); if(DEBUG) printf( "GPIO_RELAY set off\n" ); } else { GetCmdValue(SPK_CONF, "relay_ctrl:call_state", relay_call_state, sizeof(relay_call_state)); GetCmdValue(SPK_CONF, "relay_ctrl:state_info", relay_state_info, sizeof(relay_state_info)); if( strcmp(relay_call_state, "yes") == 0 && strcmp(relay_state_info, "answered") == 0 ) { relayControl(GPIO_RELAY, GPIO_ON); if(DEBUG) printf( "GPIO_RELAY set on\n" ); //gpio触发后判断是否为延时复位 if( strcmp(relay_mode, "delay") == 0 ) { int ret_thrd_delay; pthread_t thread_delay; ret_thrd_delay = pthread_create(&thread_delay, NULL, relayDelayControl, NULL); if (ret_thrd_delay != 0) { printf("create thread_delay relayDelayControl failed\n"); return; } pthread_detach(thread_delay); } } } //触发应答提示音播放 GetCmdValue(SPK_CONF, "sip_function:answer_local_beep", local_beep, sizeof(local_beep)); if(strcmp(local_beep, "yes") == 0) { GetCmdValue(SPK_CONF, "sip_function:answer_local_beep_file", local_beep_file, sizeof(local_beep_file)); GetCmdValue(SPK_CONF, "sip_function:answer_local_beep_volume", local_beep_volume, sizeof(local_beep_volume)); sprintf(cmd,"{\"cmd\":\"mixausrc_dec_start\",\"data\":\"aufile /usr/share/baresip/%s 10 %s\"}", local_beep_file, local_beep_volume); control_cmd(BARESIP_CHAN, cmd); } GetCmdValue(SPK_CONF, "sip_function:answer_remote_beep", remote_beep, sizeof(remote_beep)); if(strcmp(remote_beep, "yes") == 0) { GetCmdValue(SPK_CONF, "sip_function:answer_remote_beep_file", remote_beep_file, sizeof(remote_beep_file)); GetCmdValue(SPK_CONF, "sip_function:answer_remote_beep_volume", remote_beep_volume, sizeof(remote_beep_volume)); sprintf(cmd,"{\"cmd\":\"mixausrc_enc_start\",\"data\":\"aufile /usr/share/baresip/%s 10 %s\"}", remote_beep_file, remote_beep_volume); control_cmd(BARESIP_CHAN, cmd); } } //挂断触发 void hangupTrigger(char *param) { char cmd[MAX_PIPE_BUFSIZE]; char relay_call_state[8],relay_state_info[16],relay_mode[16]; char call_state[8],state_info[16],output_mode[16], beep[4], beep_file[64], beep_volume[4]; char screen_call_state[8], screen_state_info[16], screen_mode[16]; //触发挂断提示音播放 GetCmdValue(SPK_CONF, "sip_function:hangup_beep", beep, sizeof(beep)); if(strcmp(beep, "yes") == 0) { GetCmdValue(SPK_CONF, "sip_function:hangup_beep_file", beep_file, sizeof(beep_file)); GetCmdValue(SPK_CONF, "sip_function:hangup_beep_volume", beep_volume, sizeof(beep_volume)); sprintf(cmd,"{\"cmd\":\"setaudiotempvol\",\"data\":\"%s\"}",beep_volume); control_cmd(BARESIP_CHAN, cmd); sprintf(cmd,"{\"cmd\":\"play\",\"data\":\"%s:0\"}", beep_file); control_cmd(BARESIP_CHAN, cmd); } setClosedCallInfo(param); //判断RELAY是否需要挂断复位 GetCmdValue(SPK_CONF, "relay_ctrl:mode", relay_mode, sizeof(relay_mode)); if( strcmp(relay_mode, "hangup") == 0 ) { relayControl(GPIO_RELAY, GPIO_OFF); if(DEBUG) printf( "GPIO_RELAY set off\n" ); } else { //否则判断是否需要执行挂断触发 GetCmdValue(SPK_CONF, "relay_ctrl:call_state", relay_call_state, sizeof(relay_call_state)); GetCmdValue(SPK_CONF, "relay_ctrl:state_info", relay_state_info, sizeof(relay_state_info)); if( strcmp(relay_call_state, "yes") == 0){ if(strcmp(relay_state_info, "hangup") == 0 ) { relayControl(GPIO_RELAY, GPIO_ON); if(DEBUG) printf( "GPIO_RELAY set on\n" ); //gpio触发后延时复位 int ret_thrd_delay; pthread_t thread_delay; ret_thrd_delay = pthread_create(&thread_delay, NULL, relayDelayControl, NULL); if (ret_thrd_delay != 0) { printf("create thread_delay relayDelayControl failed\n"); return; } pthread_detach(thread_delay); } else { relayControl(GPIO_RELAY, GPIO_OFF); if(DEBUG) printf( "GPIO_RELAY set off\n" ); } } } } //DTMF检测 void dtmfDetect(char *dtmf) { char dtmf_event[8],dtmf_code[32],relay_mode[16]; char srceen_dtmf_event[8],srceen_dtmf_code[32],srceen_mode[16]; char dtmf_tmp[32] = "\0"; int dtmflen,codelen,srceen_codelen, reset = FALSE; GetCmdValue(SPK_CONF, "relay_ctrl:dtmf", dtmf_event, sizeof(dtmf_event)); GetCmdValue(SPK_CONF, "screen_ctrl:dtmf", srceen_dtmf_event, sizeof(srceen_dtmf_event)); if( strcmp(dtmf_event, "yes") == 0 || strcmp(srceen_dtmf_event, "yes") == 0 ) { strcat(DTMF_STRING,dtmf); if(DEBUG) printf( "DTMF is [%s]\n", DTMF_STRING ); dtmflen = strlen(DTMF_STRING); if(strcmp(dtmf_event, "yes") == 0 ) { GetCmdValue(SPK_CONF, "relay_ctrl:dtmf_code", dtmf_code, sizeof(dtmf_code)); codelen = strlen(dtmf_code); if( dtmflen >= codelen ) { strcpy(dtmf_tmp, DTMF_STRING + dtmflen - codelen); if( strcmp(dtmf_tmp, dtmf_code) == 0 ){ relayControl(GPIO_RELAY, GPIO_ON); if(DEBUG) printf( "GPIO_RELAY set on\n" ); //gpio触发后判断是否为延时复位 GetCmdValue(SPK_CONF, "relay_ctrl:mode", relay_mode, sizeof(relay_mode)); if( strcmp(relay_mode, "delay") == 0 ) { int ret_thrd_delay; pthread_t thread_delay; ret_thrd_delay = pthread_create(&thread_delay, NULL, relayDelayControl, NULL); if (ret_thrd_delay != 0) { printf("create thread_delay relayDelayControl failed\n"); return; } pthread_detach(thread_delay); } reset = TRUE; } } } if(strcmp(srceen_dtmf_event, "yes") == 0 ) { GetCmdValue(SPK_CONF, "screen_ctrl:dtmf_code", srceen_dtmf_code, sizeof(srceen_dtmf_code)); srceen_codelen = strlen(srceen_dtmf_code); if( dtmflen >= srceen_codelen ) { strcpy(dtmf_tmp, DTMF_STRING + dtmflen - srceen_codelen); if( strcmp(dtmf_tmp, srceen_dtmf_code) == 0 ){ screenControl(TRUE); if(DEBUG) printf( "screen set on\n" ); //触发后判断是否为延时复位 GetCmdValue(SPK_CONF, "screen_ctrl:mode", srceen_mode, sizeof(srceen_mode)); if( strcmp(srceen_mode, "delay") == 0 ) { int ret_thrd_delay; pthread_t thread_delay; ret_thrd_delay = pthread_create(&thread_delay, NULL, screenDelayControl, NULL); if (ret_thrd_delay != 0) { printf("create thread_delay screenDelayControl failed\n"); return; } pthread_detach(thread_delay); } reset = TRUE; } } } if(reset) memset(DTMF_STRING, 0, sizeof(DTMF_STRING)); } } //baresip状态监控 void ProcessReply( redisReply * pReply ) { cJSON *pJson; redisReply * pSubReply = NULL; char callerid[128],strtmp[256]; 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(strcmp(cJSON_GetObjectItem(pJson, "direction")->valuestring, "incoming") == 0 && strcmp(cJSON_GetObjectItem(pJson, "type")->valuestring, "CALL_ESTABLISHED") == 0) { //通话 writeLog( STA, "CALL ESTABLISHED", "incoming" ); //amplifier_switch(TRUE); BARESIP_STATUS = INUSE; answeredTrigger(); } else if(strcmp(cJSON_GetObjectItem(pJson, "direction")->valuestring, "outgoing") == 0 && strcmp(cJSON_GetObjectItem(pJson, "type")->valuestring, "CALL_ESTABLISHED") == 0) { //通话 writeLog( STA, "CALL ESTABLISHED", "outgoing" ); //amplifier_switch(TRUE); BARESIP_STATUS = INUSE; answeredTrigger(); } else if(strcmp(cJSON_GetObjectItem(pJson, "direction")->valuestring, "incoming") == 0 && strcmp(cJSON_GetObjectItem(pJson, "type")->valuestring, "CALL_CLOSED") == 0) { //挂断 hangupTrigger(cJSON_GetObjectItem(pJson, "param")->valuestring); writeLog( STA, "CALL CLOSED", cJSON_GetObjectItem(pJson, "param")->valuestring ); if(BARESIP_STATUS != OFFLINE){ BARESIP_STATUS = IDLE; } if(strlen(DTMF_STRING)) memset(DTMF_STRING, 0, sizeof(DTMF_STRING)); CURRENT_CALLS --; if(CURRENT_CALLS < 1) { //amplifier_switch(FALSE); CURRENT_CALLS = 0; } else { control_cmd(BARESIP_CHAN, "{\"cmd\":\"resume\",\"data\":\"\"}"); } } else if(strcmp(cJSON_GetObjectItem(pJson, "direction")->valuestring, "outgoing") == 0 && strcmp(cJSON_GetObjectItem(pJson, "type")->valuestring, "CALL_CLOSED") == 0) { //挂断 hangupTrigger(cJSON_GetObjectItem(pJson, "param")->valuestring); writeLog( STA, "CALL CLOSED", cJSON_GetObjectItem(pJson, "param")->valuestring ); if(BARESIP_STATUS != OFFLINE){ BARESIP_STATUS = IDLE; } CURRENT_KEY = UNKEY; if(strlen(DTMF_STRING)) memset(DTMF_STRING, 0, sizeof(DTMF_STRING)); CURRENT_CALLS --; if(CURRENT_CALLS < 1) { CURRENT_CALLS = 0; } else { control_cmd(BARESIP_CHAN, "{\"cmd\":\"resume\",\"data\":\"\"}"); } } else if(strcmp(cJSON_GetObjectItem(pJson, "direction")->valuestring, "incoming") == 0 && strcmp(cJSON_GetObjectItem(pJson, "type")->valuestring, "CALL_INCOMING") == 0) { //呼入振铃状态 writeLog( STA, "INCOMING CALL", cJSON_GetObjectItem(pJson, "peeruri")->valuestring ); CURRENT_CALLS ++; //amplifier_switch(TRUE); if(BARESIP_STATUS == IDLE) { BARESIP_STATUS = RING; CURRENT_KEY = UNKEY; incomingTrigger(); } memset(callerid, 0, sizeof(callerid)); if(strchr(cJSON_GetObjectItem(pJson, "peeruri")->valuestring,'@')) strncpy(callerid, cJSON_GetObjectItem(pJson, "peeruri")->valuestring, strchr(cJSON_GetObjectItem(pJson, "peeruri")->valuestring,'@') - cJSON_GetObjectItem(pJson, "peeruri")->valuestring); else strcpy(callerid, cJSON_GetObjectItem(pJson, "peeruri")->valuestring); setIncomingCallInfo(cJSON_GetObjectItem(pJson, "accountaor")->valuestring, callerid + 4); } else if(strcmp(cJSON_GetObjectItem(pJson, "direction")->valuestring, "outgoing") == 0 && strcmp(cJSON_GetObjectItem(pJson, "type")->valuestring, "CALL_OUTGOING") == 0) { //呼出回铃状态 writeLog( STA, "OUTGOING CALL", cJSON_GetObjectItem(pJson, "peeruri")->valuestring ); CURRENT_CALLS ++; //amplifier_switch(TRUE); if(BARESIP_STATUS == IDLE || BARESIP_STATUS == DIALING) { BARESIP_STATUS = RINGING; outgoingTrigger(); } memset(callerid, 0, sizeof(callerid)); if(strchr(cJSON_GetObjectItem(pJson, "peeruri")->valuestring,'@')) strncpy(callerid, cJSON_GetObjectItem(pJson, "peeruri")->valuestring, strchr(cJSON_GetObjectItem(pJson, "peeruri")->valuestring,'@') - cJSON_GetObjectItem(pJson, "peeruri")->valuestring); else strncpy(callerid, cJSON_GetObjectItem(pJson, "peeruri")->valuestring, strchr(cJSON_GetObjectItem(pJson, "peeruri")->valuestring,';') - cJSON_GetObjectItem(pJson, "peeruri")->valuestring); setOutgoingCallInfo(cJSON_GetObjectItem(pJson, "accountaor")->valuestring, callerid + 4); } else if(strcmp(cJSON_GetObjectItem(pJson, "type")->valuestring, "CALL_DTMF_START") == 0) { //接收DTMF writeLog( FUN, "RECEIVE DTMF", cJSON_GetObjectItem(pJson, "param")->valuestring ); dtmfDetect(cJSON_GetObjectItem(pJson, "param")->valuestring); } else if(strcmp(cJSON_GetObjectItem(pJson, "type")->valuestring, "REGISTER_OK") == 0) { //如果是注册成功点亮指示灯 char enac1[8],enac2[8],enac3[8],accountaor1[192], accountaor2[192], accountaor3[192]; char account1[32], domain1[128], account2[32], domain2[128], account3[32], domain3[128]; if(BARESIP_STATUS == OFFLINE || BARESIP_STATUS == DIALING || strcmp(cJSON_GetObjectItem(pJson, "class")->valuestring, "init register") == 0) { BARESIP_STATUS = IDLE; CURRENT_CALLS = 0; } if(cJSON_GetObjectItem(pJson, "accountaor") != NULL) { GetCmdValue(SPK_CONF, "account_info_1:enable", enac1, sizeof(enac1)); if(strcmp(enac1, "yes") == 0 && ACCOUNT1_REG == REGISTER_FAIL) { GetCmdValue(SPK_CONF, "account_info_1:username", account1, sizeof(account1)); GetCmdValue(SPK_CONF, "account_info_1:domain", domain1, sizeof(domain1)); if(strlen(domain1) == 0) { GetCmdValue(SPK_CONF, "account_info_1:server", domain1, sizeof(domain1)); } memset(accountaor1, '\0', sizeof(accountaor1)); sprintf(accountaor1, "sip:%s@%s", account1, domain1); if (strcmp(cJSON_GetObjectItem(pJson, "accountaor")->valuestring, accountaor1) == 0) { ACCOUNT1_REG = REGISTER_OK; cJSON_Delete(pJson); sprintf(strtmp,"Primary SIP Account <%s>",accountaor1); writeLog( STA, "SIP REGISTERED", strtmp ); return; } } GetCmdValue(SPK_CONF, "account_info_2:enable", enac2, sizeof(enac2)); if(strcmp(enac2, "yes") == 0 && ACCOUNT2_REG == REGISTER_FAIL) { GetCmdValue(SPK_CONF, "account_info_2:username", account2, sizeof(account2)); GetCmdValue(SPK_CONF, "account_info_2:domain", domain2, sizeof(domain2)); if(strlen(domain2) == 0) { GetCmdValue(SPK_CONF, "account_info_2:server", domain2, sizeof(domain2)); } memset(accountaor2, '\0', sizeof(accountaor2)); sprintf(accountaor2, "sip:%s@%s", account2, domain2); if (strcmp(cJSON_GetObjectItem(pJson, "accountaor")->valuestring, accountaor2) == 0) { ACCOUNT2_REG = REGISTER_OK; cJSON_Delete(pJson); sprintf(strtmp,"Secondary SIP Account-1 <%s>",accountaor2); writeLog( STA, "SIP REGISTERED", strtmp ); return; } } GetCmdValue(SPK_CONF, "account_info_3:enable", enac3, sizeof(enac3)); if(strcmp(enac3, "yes") == 0 && ACCOUNT3_REG == REGISTER_FAIL) { GetCmdValue(SPK_CONF, "account_info_3:username", account3, sizeof(account3)); GetCmdValue(SPK_CONF, "account_info_3:domain", domain3, sizeof(domain3)); if(strlen(domain3) == 0) { GetCmdValue(SPK_CONF, "account_info_3:server", domain3, sizeof(domain3)); } memset(accountaor3, '\0', sizeof(accountaor3)); sprintf(accountaor3, "sip:%s@%s", account3, domain3); if (strcmp(cJSON_GetObjectItem(pJson, "accountaor")->valuestring, accountaor3) == 0) { ACCOUNT3_REG = REGISTER_OK; cJSON_Delete(pJson); sprintf(strtmp,"Secondary SIP Account-2 <%s>",accountaor3); writeLog( STA, "SIP REGISTERED", strtmp ); return; } } } regcount ++; } else if(strcmp(cJSON_GetObjectItem(pJson, "type")->valuestring, "REGISTER_FAIL") == 0 ) { char enac1[8],enac2[8],enac3[8],accountaor1[192], accountaor2[192], accountaor3[192]; char account1[32], domain1[128], account2[32], domain2[128], account3[32], domain3[128]; if(cJSON_GetObjectItem(pJson, "accountaor") != NULL) { GetCmdValue(SPK_CONF, "account_info_1:enable", enac1, sizeof(enac1)); if(strcmp(enac1, "yes") == 0 && ACCOUNT1_REG == REGISTER_OK) { GetCmdValue(SPK_CONF, "account_info_1:username", account1, sizeof(account1)); GetCmdValue(SPK_CONF, "account_info_1:domain", domain1, sizeof(domain1)); if(strlen(domain1) == 0) { GetCmdValue(SPK_CONF, "account_info_1:server", domain1, sizeof(domain1)); } memset(accountaor1, '\0', sizeof(accountaor1)); sprintf(accountaor1, "sip:%s@%s", account1, domain1); if (strcmp(cJSON_GetObjectItem(pJson, "accountaor")->valuestring, accountaor1) == 0) { ACCOUNT1_REG = REGISTER_FAIL; if( ACCOUNT2_REG == REGISTER_FAIL && ACCOUNT3_REG == REGISTER_FAIL && ACCOUNTP2P_REG == REGISTER_FAIL ){ BARESIP_STATUS = OFFLINE; } sprintf(strtmp,"Primary Account REGISTER FAILED <%s>",accountaor1); writeLog( STA, strtmp, cJSON_GetObjectItem(pJson, "param")->valuestring ); cJSON_Delete(pJson); return; } } GetCmdValue(SPK_CONF, "account_info_2:enable", enac2, sizeof(enac2)); if(strcmp(enac2, "yes") == 0 && ACCOUNT2_REG == REGISTER_OK) { GetCmdValue(SPK_CONF, "account_info_2:username", account2, sizeof(account2)); GetCmdValue(SPK_CONF, "account_info_2:domain", domain2, sizeof(domain2)); if(strlen(domain2) == 0) { GetCmdValue(SPK_CONF, "account_info_2:server", domain2, sizeof(domain2)); } memset(accountaor2, '\0', sizeof(accountaor2)); sprintf(accountaor2, "sip:%s@%s", account2, domain2); if (strcmp(cJSON_GetObjectItem(pJson, "accountaor")->valuestring, accountaor2) == 0) { ACCOUNT2_REG = REGISTER_FAIL; if( ACCOUNT1_REG == REGISTER_FAIL && ACCOUNT3_REG == REGISTER_FAIL && ACCOUNTP2P_REG == REGISTER_FAIL ){ BARESIP_STATUS = OFFLINE; } sprintf(strtmp,"Secondary Account-1 REGISTER FAILED <%s>",accountaor2); writeLog( STA, strtmp, cJSON_GetObjectItem(pJson, "param")->valuestring ); cJSON_Delete(pJson); return; } } GetCmdValue(SPK_CONF, "account_info_3:enable", enac3, sizeof(enac3)); if(strcmp(enac3, "yes") == 0 && ACCOUNT3_REG == REGISTER_OK) { GetCmdValue(SPK_CONF, "account_info_3:username", account3, sizeof(account3)); GetCmdValue(SPK_CONF, "account_info_3:domain", domain3, sizeof(domain3)); if(strlen(domain3) == 0) { GetCmdValue(SPK_CONF, "account_info_3:server", domain3, sizeof(domain3)); } memset(accountaor3, '\0', sizeof(accountaor3)); sprintf(accountaor3, "sip:%s@%s", account3, domain3); if (strcmp(cJSON_GetObjectItem(pJson, "accountaor")->valuestring, accountaor3) == 0) { ACCOUNT3_REG = REGISTER_FAIL; if( ACCOUNT1_REG == REGISTER_FAIL && ACCOUNT2_REG == REGISTER_FAIL && ACCOUNTP2P_REG == REGISTER_FAIL ){ BARESIP_STATUS = OFFLINE; } sprintf(strtmp,"Secondary Account-2 REGISTER FAILED <%s>",accountaor3); writeLog( STA, strtmp, cJSON_GetObjectItem(pJson, "param")->valuestring ); cJSON_Delete(pJson); return; } } } regcount ++; } else if(strcmp(cJSON_GetObjectItem(pJson, "type")->valuestring, "EXIT") == 0) { //如果是注册失败熄灭指示灯 BARESIP_STATUS = OFFLINE; ACCOUNT1_REG = REGISTER_FAIL; ACCOUNT2_REG = REGISTER_FAIL; ACCOUNT3_REG = REGISTER_FAIL; writeLog( STA, "APP EXIT", "" ); CURRENT_CALLS = 0; } else if(cJSON_GetObjectItem(pJson, "event")->type == 1 && cJSON_GetObjectItem(pJson, "event")->valueint == 0){ if(strncmp(cJSON_GetObjectItem(pJson, "data")->valuestring,"\n--- User Agents",16) == 0) { char p2penable[8]; GetCmdValue(SPK_CONF, "account_info_p2p:enable", p2penable, sizeof(p2penable)); if(strcmp(p2penable,"yes") == 0) { BARESIP_STATUS = IDLE; if(ACCOUNTP2P_REG == REGISTER_FAIL) { ACCOUNTP2P_REG = REGISTER_OK; writeLog( STA, "P2P ACCOUNT", "Enabled" ); } } else if(ACCOUNTP2P_REG == REGISTER_OK) { ACCOUNTP2P_REG = REGISTER_FAIL; writeLog( STA, "P2P ACCOUNT", "Disabled" ); } } } if(DEBUG) printf( "Baresip Status is: %d\n", BARESIP_STATUS ); }else{ printf( "parse failed!\n"); } if(pJson != NULL) cJSON_Delete(pJson); } } /* * 订阅baresip实时状态. */ void *baresip_status() { redisContext * pContext = redisConnectUnix(unix_socket_path); if ( NULL == pContext || pContext->err == 1 ) { printf( "%s\n", pContext->errstr ); exit( -1 ); } char * pKey = "session-channel"; redisReply * pReply = redisCommand( pContext, "SUBSCRIBE %s", pKey ); freeReplyObject( pReply ); while ( redisGetReply( pContext, (void **)&pReply ) == REDIS_OK ) { ProcessReply( pReply ); freeReplyObject( pReply ); } redisFree( pContext ); } int get_line(int * line_id) { char enac[8], strtmp[32]; int id = 0; memset(line_id,-1,sizeof(line_id)); for(int i = 1; i < 4;i ++) { bzero(strtmp, sizeof(strtmp)); sprintf(strtmp,"account_info_%d:enable",i); GetCmdValue(SPK_CONF, strtmp, enac, sizeof(enac)); if(strcmp(enac,"yes") == 0) { line_id[i] = id; id ++; } } return TRUE; } //按键动作 void keyAction(int key) { char cmd[MAX_PIPE_BUFSIZE]; char accountaor[192],strtmp[64]; char account[32], enable[8],url[256],ipaddr[16],macaddr[16]; char onekey_num[32],onekey_line[24],repress_cancel[8]; int channel = BARESIP_CHAN, line_id[4]; if(DEBUG) printf( "BARESIP_STATUS [%d]\n", BARESIP_STATUS ); switch(key){ case KEY://处理按键动作 if( CURRENT_KEY == UNKEY || CURRENT_KEY == KEY ) { switch(BARESIP_STATUS) { case IDLE: CURRENT_KEY = KEY; BARESIP_STATUS = DIALING; GetCmdValue(SPK_CONF, "intercom:onekey_num", onekey_num, sizeof(onekey_num)); GetCmdValue(SPK_CONF, "intercom:onekey_line", onekey_line, sizeof(onekey_line)); if(strlen(onekey_num) == 0) { BARESIP_STATUS = IDLE; break; } get_line(line_id); if(strcmp(onekey_line,"auto") == 0) { if(DEBUG) printf("ACCOUNT1 is %d, ACCOUNT2 is %d, ACCOUNT3 is %d\n",ACCOUNT1_REG,ACCOUNT2_REG,ACCOUNT3_REG); if(ACCOUNT1_REG == REGISTER_OK) { if(line_id[1] == -1) { BARESIP_STATUS = IDLE; break; } sprintf(cmd,"{\"cmd\":\"dial\",\"data\":\"%s %d\"}",onekey_num, line_id[1]); } else if(ACCOUNT2_REG == REGISTER_OK) { if(line_id[2] == -1) { BARESIP_STATUS = IDLE; break; } sprintf(cmd,"{\"cmd\":\"dial\",\"data\":\"%s %d\"}",onekey_num, line_id[2]); } else if(ACCOUNT3_REG == REGISTER_OK) { if(line_id[3] == -1) { BARESIP_STATUS = IDLE; break; } sprintf(cmd,"{\"cmd\":\"dial\",\"data\":\"%s %d\"}",onekey_num, line_id[3]); } else { BARESIP_STATUS = IDLE; break; } } else if (strcmp(onekey_line, "account_info_1") == 0) { if(line_id[1] == -1 || ACCOUNT1_REG != REGISTER_OK) { BARESIP_STATUS = IDLE; break; } sprintf(cmd,"{\"cmd\":\"dial\",\"data\":\"%s %d\"}",onekey_num, line_id[1]); } else if (strcmp(onekey_line, "account_info_2") == 0) { if(line_id[2] == -1 || ACCOUNT2_REG != REGISTER_OK) { BARESIP_STATUS = IDLE; break; } sprintf(cmd,"{\"cmd\":\"dial\",\"data\":\"%s %d\"}",onekey_num, line_id[2]); } else if (strcmp(onekey_line, "account_info_3") == 0) { if(line_id[3] == -1 || ACCOUNT3_REG != REGISTER_OK) { BARESIP_STATUS = IDLE; break; } sprintf(cmd,"{\"cmd\":\"dial\",\"data\":\"%s %d\"}",onekey_num, line_id[3]); } else if(strcmp(onekey_line,"p2p") == 0) { sprintf(cmd,"{\"cmd\":\"dial\",\"data\":\"%s\"}",onekey_num); } if(DEBUG) printf( "dial [%s]\n", cmd ); control_cmd(channel, cmd); sprintf(strtmp, "%s <%s>", onekey_num, onekey_line); writeLog( FUN, "KEY Call", strtmp ); break; case RINGING: case INUSE: GetCmdValue(SPK_CONF, "intercom:repress_cancel", repress_cancel, sizeof(repress_cancel)); if(strcmp(repress_cancel, "yes") == 0){ strcpy(cmd,"{\"cmd\":\"hangup\",\"data\":\"\"}"); if(DEBUG) printf( "hangup call\n" ); control_cmd(channel, cmd); writeLog( FUN, "KEY Hangup", "" ); } break; case RING: CURRENT_KEY = KEY; strcpy(cmd,"{\"cmd\":\"accept\",\"data\":\"\"}"); if(DEBUG) printf( "answer call\n" ); control_cmd(channel, cmd); writeLog( FUN, "KEY Answer", "" ); break; case OFFLINE: GetCmdValue(SPK_CONF, "call_action_url:unregistered_enable", enable, sizeof(enable)); if(strcmp(enable,"yes") == 0) { GetCmdValue(SPK_CONF, "call_action_url:unregistered_url", url, sizeof(url)); if(strstr(url,VAR_IP)) { if(get_ip(ipaddr)) strcpy(url, strrpl(url, VAR_IP, ipaddr)); } if(strstr(url,VAR_MAC)) { if(get_mac(macaddr)) strcpy(url, strrpl(url, VAR_MAC, macaddr)); } if(strstr(url,VAR_UA)) { GetCmdValue(SPK_CONF, "intercom:onekey_line", onekey_line, sizeof(onekey_line)); sprintf(strtmp,"%s:username",onekey_line); GetCmdValue(SPK_CONF, strtmp, account, sizeof(account)); strcpy(url, strrpl(url, VAR_UA, account)); } if(strstr(url,VAR_NUM)) { GetCmdValue(SPK_CONF, "intercom:onekey_num", onekey_num, sizeof(onekey_num)); strcpy(url, strrpl(url, VAR_NUM, onekey_num)); } action_url(url); writeLog(FUN, "HTTP Request", url); } break; } } break; case KEY2_10: system("/etc/scripts/play_rebooting.sh"); system("rm -f /oem/.userdata && /sbin/reboot"); break; case KEY2_3: PlayIP(); break; } } void *checkReg() { dictionary * ini ; ini = iniparser_load(SPK_CONF); if (ini==NULL) { fprintf(stderr, "cannot parse file: %s\n", SPK_CONF); return FALSE; } if((strcmp(iniparser_getstring(ini, "account_info_1:enable", "no"), "yes") == 0 || strcmp(iniparser_getstring(ini, "account_info_2:enable", "no"), "yes") == 0 || strcmp(iniparser_getstring(ini, "account_info_3:enable", "no"), "yes") == 0) && regcount == 0) { system("/etc/scrtips/sipphone.sh stop"); } regcount = 0; iniparser_freedict(ini); } void reset_vlcInfo(int id) { vlcInfo[id].pid = 0; vlcInfo[id].prio = 0; memset(vlcInfo->param, 0, sizeof(vlcInfo->param)); } int file_exists(char *filename) { return (access(filename, 0) == 0); } int vlc_cmd_action(char *action, int id) { char cmd[128], ctrlfile[32]; int i = 0; sprintf(ctrlfile,"/tmp/vlc_%d.sock",id); while(i < MAX_TRY) { if(file_exists(ctrlfile)) { sprintf(cmd,"echo \"%s\" | socat - unix-connect:%s", action, ctrlfile); if(DEBUG) printf("volume CMD: %s\n", cmd); if(system(cmd) == 0) return TRUE; else continue; } usleep(200*1000); i ++; } return FALSE; } int schedule_start_check_prio(int prio) { char cmd[64]; for(int i = 1; i < 31; i++) { if(DEBUG) printf("==============%d,%d,%d,%s=============\n", i, SCHEDULE[i], vlcInfo[i].prio, vlcInfo[i].param); if(SCHEDULE[i] != STOP) { if(prio < vlcInfo[i].prio) return FALSE; else if(SCHEDULE[i] == RUNNING && prio > vlcInfo[i].prio) { if(vlc_cmd_action("pause",i)) SCHEDULE[i] = PAUSED; } } } return TRUE; } void schedule_stop_check_prio(int prio) { char cmd[64]; int paused[30],running[30],c_paused = 0, c_running = 0; int isRunning = FALSE; for(int i = 1; i < 31; i++) { if(SCHEDULE[i] == RUNNING) { return; } if(SCHEDULE[i] == PAUSED) { paused[c_paused] = i; c_paused ++; } } for(int p = prio; p > 0; p--) { for(int n = 0; n < c_paused; n++) { if(p == vlcInfo[paused[n]].prio) { state_event(AUDIO_ON); if(vlc_cmd_action("pause",paused[n])) { SCHEDULE[paused[n]] = RUNNING; isRunning = TRUE; } } } if(isRunning) return; } state_event(AUDIO_OFF); } void playAudio(int id, int times, int isBeep, char *enSrceen, char *file, int prio, int vol) { char filetmp[64], action[128], sockio[32], paused[32],loop[16],cmd[64], gain[32]; int status, isPaused; bzero(paused,sizeof(paused)); if(!schedule_start_check_prio(prio)) { strcpy(paused,"--start-paused"); isPaused = TRUE; } else { strcpy(paused,"--no-start-paused"); isPaused = FALSE; state_event(AUDIO_ON); } if(times == 0) { sprintf(filetmp, "/usr/share/baresip/%s", file); strcpy(loop,"--loop"); } else { sprintf(filetmp,"/tmp/playlist_%d.m3u",id); FILE *fd = fopen(filetmp, "w+"); if(fd == NULL) { if(DEBUG) printf("play failed!\n"); return; } if(isBeep) fprintf(fd,"/usr/share/baresip/s_beep.mp3\n"); for(int i=0;i /sys/class/gpio/gpio5/value"); if(waitpid(vlcInfo[id].pid, &status, 0) != -1) { if(DEBUG) printf("Child exited with status %i\n", status); SCHEDULE[id] = STOP; schedule_stop_check_prio(vlcInfo[id].prio); reset_vlcInfo(id); if(strcmp(enSrceen, "Disabled") != 0) { sprintf(cmd,"{\"action\": \"off\", \"id\": %s}", enSrceen); screen_control(cmd); } //system("echo 1 > /sys/class/gpio/gpio5/value"); sprintf(action,"Stop audio: %s", vlcInfo[id].param); writeLog(FUN, "Audio Control", action); } } if(times) remove(filetmp); } void *handle_playAudio(void *arg) { int selfkey, isBeep = FALSE, times = 0; PlayInfo *p = arg; selfkey = p->key_id; if(strlen(p->times_str)) times = atoi(p->times_str); if(strcmp(p->enBeep, "yes") == 0) isBeep = TRUE; if(strlen(p->file)) { playAudio(selfkey, times, isBeep, p->enSrceen, p->file, p->prio, p->vol); } free(p); } int equalDate(struct date A,struct date B) { if(A.year==B.year && A.month==B.month && A.day==B.day) return TRUE; return FALSE; } int compareDate(struct date A,struct date B) { if(A.yearyear, &s_holiday->month, &s_holiday->day, &e_holiday->year, &e_holiday->month, &e_holiday->day); } int isHoliday(struct date currDate, char *holidays) { cJSON *pJson, *pSub; struct date s_holiday, e_holiday; pJson = cJSON_Parse(holidays); if (pJson) { cJSON *holidaysArray = cJSON_GetObjectItem( pJson, "holidays"); if(holidaysArray != NULL) { int array_size = cJSON_GetArraySize (holidaysArray); for(int n = 0; n < array_size; n++) { pSub = cJSON_GetArrayItem(holidaysArray, n); date_format(pSub->valuestring, &s_holiday, &e_holiday); if(DEBUG) { printf("current date: %d-%d-%d\n",currDate.year, currDate.month, currDate.day); printf("holiday start: %d-%d-%d\n",s_holiday.year, s_holiday.month, s_holiday.day); printf("holiday end: %d-%d-%d\n",e_holiday.year, e_holiday.month, e_holiday.day); } if(equalDate(currDate, s_holiday) || (compareDate(s_holiday, currDate) && compareDate(currDate, e_holiday))) { cJSON_Delete(pJson); return TRUE; } } } } cJSON_Delete(pJson); return FALSE; } void schedule(int year, int month, int day, int hour, int minute, int week) { char actiontype[32], keyaction[16], keyactiontype[32], type[16], action_type[16]; char keystr[32],enable[8],weeks[8], enholiday[8], holidays[4096]; char w[4],action[128],screen_id[16]; int s_hour, e_hour, s_min, e_min; int s_time, e_time, time, interval; struct date s_date, e_date, date; dictionary * ini ; date.year = year; date.month = month; date.day = day; ini = iniparser_load(SCHEDULE_CONF); if (ini==NULL) { fprintf(stderr, "cannot parse file: %s\n", SCHEDULE_CONF); return; } strcpy(holidays, iniparser_getstring(ini, "holidays:data", "{\"holidays\": []}")); for(int i=1;i<31;i++) { sprintf(keystr,"schedule_%d:enable",i); strcpy(enable, iniparser_getstring(ini, keystr, "no")); if(strcmp(enable,"yes") == 0) { sprintf(keystr,"schedule_%d:enholiday",i); strcpy(enholiday, iniparser_getstring(ini, keystr, "no")); if(strcmp(enholiday, "yes") == 0 && isHoliday(date, holidays)) continue; sprintf(keystr,"schedule_%d:weeks",i); strcpy(weeks, iniparser_getstring(ini, keystr, "")); sprintf(w,"%d",week); if(strchr(weeks,w[0]) == NULL) continue; sprintf(keystr,"schedule_%d:s_year",i); s_date.year = iniparser_getint(ini, keystr, 0); sprintf(keystr,"schedule_%d:e_year",i); e_date.year = iniparser_getint(ini, keystr, 0); sprintf(keystr,"schedule_%d:s_month",i); s_date.month = iniparser_getint(ini, keystr, 0); sprintf(keystr,"schedule_%d:e_month",i); e_date.month = iniparser_getint(ini, keystr, 0); sprintf(keystr,"schedule_%d:s_day",i); s_date.day = iniparser_getint(ini, keystr, 0); sprintf(keystr,"schedule_%d:e_day",i); e_date.day = iniparser_getint(ini, keystr, 0); if(compareDate(date, s_date) || compareDate(e_date, date)) continue; sprintf(keystr,"schedule_%d:s_hour",i); s_hour = iniparser_getint(ini, keystr, 0); sprintf(keystr,"schedule_%d:e_hour",i); e_hour = iniparser_getint(ini, keystr, 0); sprintf(keystr,"schedule_%d:s_min",i); s_min = iniparser_getint(ini, keystr, 0); sprintf(keystr,"schedule_%d:e_min",i); e_min = iniparser_getint(ini, keystr, 0); sprintf(keystr,"schedule_%d:interval",i); interval = iniparser_getint(ini, keystr, 60); sprintf(keystr,"schedule_%d:trigger_screen",i); strcpy(screen_id, iniparser_getstring(ini, keystr, "Disabled")); time = hour * 60 + minute; s_time = s_hour * 60 + s_min; e_time = e_hour * 60 + e_min; if(time >= s_time && time <= e_time) { if(time == e_time) { sprintf(keystr,"%d",i); writeLog(SCHED, keystr, "Executed"); if(SCHEDULE[i] == RUNNING) { char strtmp[64],cmd[128]; if(strcmp(screen_id, "Disabled") != 0) { sprintf(strtmp,"{\"action\": \"off\", \"id\": %s}", screen_id); screen_control(strtmp); } sprintf(cmd,"kill -9 %d",vlcInfo[i].pid); system(cmd); // system("echo 1 > /sys/class/gpio/gpio5/value"); // SCHEDULE[i] = STOP; // sprintf(action,"Stop audio: %s", vlcInfo[i].param); // writeLog(FUN, "Audio Control", action); } continue; } if((interval != 0 && (time - s_time) % interval == 0) || (interval == 0 && time == s_time)) { sprintf(keystr,"%d",i); writeLog(SCHED, keystr, "Executed"); char cmd[256], strtmp[64], source[16]; pthread_t thread_audio; int ret_thrd; if(SCHEDULE[i] == STOP) { PlayInfo *playAudioInfo = malloc(sizeof(PlayInfo)); playAudioInfo->key_id = i; bzero(strtmp, sizeof(strtmp)); sprintf(strtmp,"schedule_%d:source",i); strcpy(source, iniparser_getstring(ini, strtmp, "")); bzero(strtmp, sizeof(strtmp)); sprintf(strtmp, "schedule_%d:audio_file", i); strcpy(playAudioInfo->file, iniparser_getstring(ini, strtmp, "")); bzero(strtmp, sizeof(strtmp)); sprintf(strtmp,"schedule_%d:play_times",i); strcpy(playAudioInfo->times_str, iniparser_getstring(ini, strtmp, "")); bzero(strtmp, sizeof(strtmp)); sprintf(strtmp,"schedule_%d:enBeep",i); strcpy(playAudioInfo->enBeep, iniparser_getstring(ini, strtmp, "no")); strcpy(playAudioInfo->enSrceen, screen_id); bzero(strtmp, sizeof(strtmp)); sprintf(strtmp,"schedule_%d:priority",i); playAudioInfo->prio = iniparser_getint(ini, strtmp, 1); bzero(strtmp, sizeof(strtmp)); sprintf(strtmp,"schedule_%d:volume",i); playAudioInfo->vol = iniparser_getint(ini, strtmp, 100); if(strcmp(screen_id, "Disabled") != 0) { sprintf(strtmp,"{\"action\": \"on\", \"id\": %s}", screen_id); screen_control(strtmp); } ret_thrd = pthread_create(&thread_audio, NULL, handle_playAudio, playAudioInfo); if (ret_thrd != 0) { printf("create thread1 handle_playAudio failed\n"); free(playAudioInfo); continue; } pthread_detach(thread_audio); } else { if(strcmp(screen_id, "Disabled") != 0) { sprintf(strtmp,"{\"action\": \"off\", \"id\": %s}", screen_id); screen_control(strtmp); } sprintf(cmd,"kill -9 %d",vlcInfo[i].pid); system(cmd); // system("echo 1 > /sys/class/gpio/gpio5/value"); // SCHEDULE[i] = STOP; // sprintf(action,"Stop audio: %s", vlcInfo[i].param); // writeLog(FUN, "Audio Control", action); } } } } } iniparser_freedict(ini); } void *handleDateTime() { time_t nSeconds; struct tm *pTM; int year, month, hour, count; pthread_t thread1; while(1) { time(&nSeconds); pTM = localtime(&nSeconds); if(pTM->tm_sec == 0) { // year = pTM->tm_year + 1900; // month = pTM->tm_mon + 1; // schedule(year, month, pTM->tm_mday, pTM->tm_hour, pTM->tm_min, pTM->tm_wday); count ++; if(count > 120) { pthread_create(&thread1, NULL, checkReg, NULL); pthread_detach(thread1); count = 0; } } sleep(1); } } //解析音量设置数据 void ProcessVolumeReply( redisReply * pReply ) { cJSON *pJson = NULL; redisReply * pSubReply = NULL; char cmd[MAX_PIPE_BUFSIZE]; int channel = BARESIP_CHAN; if ( pReply != NULL && pReply->elements == 3 ) { pSubReply = pReply->element[2]; pJson = cJSON_Parse(pSubReply->str); if ( pJson ) { if(cJSON_GetObjectItem(pJson, "audio_volume")) { if(cJSON_GetObjectItem(pJson, "audio_volume")->valueint == 0) schedule_start_check_prio(MAX_PRIORITY + 1); else schedule_stop_check_prio(MAX_PRIORITY + 1); } }else{ printf( "parse failed!\n"); } if(pJson != NULL) cJSON_Delete(pJson); } } /* * 订阅音量信息. */ void *get_volume_info() { redisContext * pContext = redisConnectUnix(unix_socket_path); if ( NULL == pContext || pContext->err == 1 ) { printf( "%s\n", pContext->errstr ); exit( -1 ); } char * pKey = "volume-value-channel"; redisReply * pReply = redisCommand( pContext, "SUBSCRIBE %s", pKey ); freeReplyObject( pReply ); while ( redisGetReply( pContext, (void **)&pReply ) == REDIS_OK ) { ProcessVolumeReply( pReply ); freeReplyObject( pReply ); } redisFree( pContext ); } void play_audio(char *audiofile, int repeat) { char cmd[320]; int channel = BARESIP_CHAN; sprintf(cmd,"{\"cmd\":\"play\",\"data\":\"%s:%d\"}",audiofile,repeat); control_cmd(channel, cmd); } const int get_sip_status(char *accountaor) { int status = OFFLINE; const int id = redis_pool_get_context(redisClient); if (id != -1) { redisReply *reply = NULL; reply = (redisReply *) redisCommand(redisClient->context[id], "GET %s", accountaor); if (reply && reply->type == REDIS_REPLY_STRING) { // 处理回复 if(DEBUG) printf("SIP acc: %s, status: %s\n", accountaor, reply->str); if(strcmp(reply->str, "{\"status\":\"idle\"}") == 0) { status = IDLE; } else if(strcmp(reply->str, "{\"status\":\"answer\"}") == 0) { status = INUSE; } else if(strcmp(reply->str, "{\"status\":\"ringing\"}") == 0) { status = RINGING; } else if(strcmp(reply->str, "{\"status\":\"ring\"}") == 0) { status = RING; } } if(reply != NULL) freeReplyObject(reply); redis_pool_release_connection(redisClient, id); } if(BARESIP_STATUS == OFFLINE || BARESIP_STATUS == IDLE) BARESIP_STATUS = status; return status; } void sip_reg_status_init() { //初始化SIP注册状态 char enac1[8],enac2[8],enac3[8],p2penable[8],accountaor1[192], accountaor2[192], accountaor3[192]; char account1[32], domain1[128], account2[32], domain2[128], account3[32], domain3[128]; GetCmdValue(SPK_CONF, "account_info_1:enable", enac1, sizeof(enac1)); if(strcmp(enac1, "yes") == 0) { GetCmdValue(SPK_CONF, "account_info_1:username", account1, sizeof(account1)); GetCmdValue(SPK_CONF, "account_info_1:domain", domain1, sizeof(domain1)); if(strlen(domain1) == 0) { GetCmdValue(SPK_CONF, "account_info_1:server", domain1, sizeof(domain1)); } memset(accountaor1, '\0', sizeof(accountaor1)); sprintf(accountaor1, "baresip-call-status-%s-%s", account1, domain1); if(get_sip_status(accountaor1) != OFFLINE) { ACCOUNT1_REG = REGISTER_OK; } } GetCmdValue(SPK_CONF, "account_info_2:enable", enac2, sizeof(enac2)); if(strcmp(enac2, "yes") == 0) { GetCmdValue(SPK_CONF, "account_info_2:username", account2, sizeof(account2)); GetCmdValue(SPK_CONF, "account_info_2:domain", domain2, sizeof(domain2)); if(strlen(domain2) == 0) { GetCmdValue(SPK_CONF, "account_info_2:server", domain2, sizeof(domain2)); } memset(accountaor2, '\0', sizeof(accountaor2)); sprintf(accountaor2, "baresip-call-status-%s-%s", account2, domain2); if(get_sip_status(accountaor2) != OFFLINE) { ACCOUNT2_REG = REGISTER_OK; } } GetCmdValue(SPK_CONF, "account_info_3:enable", enac3, sizeof(enac3)); if(strcmp(enac3, "yes") == 0) { GetCmdValue(SPK_CONF, "account_info_3:username", account3, sizeof(account3)); GetCmdValue(SPK_CONF, "account_info_3:domain", domain3, sizeof(domain3)); if(strlen(domain3) == 0) { GetCmdValue(SPK_CONF, "account_info_3:server", domain3, sizeof(domain3)); } memset(accountaor3, '\0', sizeof(accountaor3)); sprintf(accountaor3, "baresip-call-status-%s-%s", account3, domain3); if(get_sip_status(accountaor3) != OFFLINE) { ACCOUNT3_REG = REGISTER_OK; } } GetCmdValue(SPK_CONF, "account_info_p2p:enable", p2penable, sizeof(p2penable)); if(strcmp(p2penable,"yes") == 0) { ACCOUNTP2P_REG = REGISTER_OK; } if(ACCOUNT1_REG == REGISTER_OK || ACCOUNT2_REG == REGISTER_OK || ACCOUNT3_REG == REGISTER_OK || ACCOUNTP2P_REG == REGISTER_OK) { } } const int init() { int ret_thrd1,ret_thrd2,ret_thrd3,ret_thrd4; pthread_t thread1, thread2, thread3, thread4; redisClient = create_redis_pool_client(unix_socket_path); memset(SCHEDULE, 0,sizeof(SCHEDULE)); sip_reg_status_init(); //启动线程订阅BARESIP实时状态 ret_thrd1 = pthread_create(&thread1, NULL, baresip_status, NULL); if (ret_thrd1 != 0) { printf("create thread1 baresip_status failed\n"); return FALSE; } //启动日志记录线程 ret_thrd2 = pthread_create(&thread2, NULL, write_opnlog, NULL); if (ret_thrd2 != 0) { printf("create thread2 write_opnlog failed\n"); return FALSE; } //启动系统时间显示线程 ret_thrd3 = pthread_create(&thread3, NULL, handleDateTime, NULL); if (ret_thrd3 != 0) { printf("create thread3 handleDateTime failed\n"); return FALSE; } //启动线程订阅音量设置 ret_thrd4 = pthread_create(&thread4, NULL, get_volume_info, NULL); if (ret_thrd4 != 0) { printf("create thread4 get_volume_info failed\n"); return FALSE; } return TRUE; } int main(int argc, char *argv[]){ struct pollfd fdset[2]; int switch_fd,reset_fd,ret; int len, count, i, key1_action, key2_action; char buf[8], strtmp[64],action[8],url[256], srceen[8], type[16], input[8]; time_t lastime, newtime; if(argc == 2 && strcmp(argv[1], "debug") == 0) DEBUG = TRUE; if(!init()) { printf("init failed!\n"); exit( -1 ); } /* BUTTON */ switch_fd = open("/sys/class/gpio/gpio111/value", O_RDONLY); read(switch_fd, buf, sizeof(buf)); lseek(switch_fd, 0, SEEK_SET); /* RESET */ reset_fd = open("/sys/class/gpio/gpio73/value", O_RDONLY); read(reset_fd, buf, sizeof(buf)); lseek(reset_fd, 0, SEEK_SET); while(1) { memset(fdset, 0x00, sizeof(struct pollfd) * 2); fdset[0].fd = switch_fd; fdset[0].events = POLLPRI; fdset[1].fd = reset_fd; fdset[1].events = POLLPRI; ret = poll(fdset, 2, 3000); if(ret < 0){ printf("npoll() faild! \n"); return -1; } if(ret == 0) continue; /*BUTTON*/ if( fdset[0].revents & POLLPRI ) { count = 0; for(i=0;i<100;i++){ // 100ms bzero(buf,sizeof(buf)); read(fdset[0].fd, buf, sizeof(buf)); lseek(fdset[0].fd, 0, SEEK_SET); if(buf[0]-'0' == 0) count++; usleep(1000); } // printf("zero counts: %d\n", count); if (count >= 70) { playBeep(); if(DEBUG) printf("KEY DOWN\n"); writeLog(BTN, "KEY", "DOWN"); GetCmdValue(SPK_CONF, "intercom:key_action", action, sizeof(action)); if(strcmp(action,"call") == 0) { keyAction(KEY); } if(strcmp(action,"http") == 0) { GetCmdValue(SPK_CONF, "intercom:http_url", url, sizeof(url)); action_url(url); writeLog(FUN, "KEY HTTP Request", url); } else if(strcmp(action,"play") == 0) { char audiofile[32],repeat_tmp[16]; GetCmdValue(SPK_CONF, "intercom:audio_file", audiofile, sizeof(audiofile)); GetCmdValue(SPK_CONF, "intercom:audio_repeat", repeat_tmp, sizeof(repeat_tmp)); int repeat = atoi(repeat_tmp); play_audio(audiofile,repeat); sprintf(strtmp, "File: %s; Repeat: %d", audiofile, repeat); writeLog( FUN, "KEY Play Auido", strtmp ); } } } /*RESET*/ if( fdset[1].revents & POLLPRI ) { count = 0; for(i=0;i<100;i++){ // 100ms bzero(buf,sizeof(buf)); read(fdset[1].fd, buf, sizeof(buf)); lseek(fdset[1].fd, 0, SEEK_SET); if(buf[0]-'0' == 0) count++; usleep(1000); } if (count >= 70) { time(&newtime); printf("KEY DOWN\n"); writeLog(BTN, "RESET", "DOWN"); } else { time(&lastime); len = lastime - newtime; printf("KEY UP, Time:%d\n", len); sprintf(strtmp, "Release ", len); writeLog(BTN, "RESET", strtmp); if(len > 10) { keyAction(KEY2_10); } else if(len > 3) { keyAction(KEY2_3); } } } } }