#include #include #include #include #include #include #include #include #include #include #include #include #include "hiredis/hiredis.h" #include "cjson/cJSON.h" #include "iniparser/iniparser.h" #define Boolean int #define TRUE 1 #define FALSE 0 #define MAX_PIPE_BUFSIZE 256 //BARESIP_STATUS #define IDLE 0 #define INUSE 1 #define RING 2 #define RINGING 3 #define HOLD 4 #define OFFLINE 5 #define DIALING 6 #define LOOPSTART 7 //BARESIP_REG #define REGISTER_FAIL 0 #define REGISTER_OK 1 //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 unix_socket_path "/tmp/redis.sock" //operator log type #define BTN "BUTTON" #define FUN "FUNCTION" #define STA "SIP STATE" #define GPIO_RELAY "gpio67" #define VAR_IP "${ip}" #define VAR_MAC "${mac}" #define VAR_UA "${ua}" #define VAR_NUM "${number}" struct VLC_INFO{ Boolean state; pid_t pid; char param[256]; }; typedef struct _playInfo{ int duration; int volume; char url[128]; } PlayInfo; typedef struct { redisContext *context; const char *socket_path; time_t last_activity; } redis_client_t; static int BARESIP_STATUS = OFFLINE; 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 PLAYING = FALSE; static int delay = 0; struct VLC_INFO vlcInfo; static redis_client_t *redisClient; redis_client_t* create_redis_client(const char *socket_path) { redis_client_t *client = malloc(sizeof(redis_client_t)); client->socket_path = socket_path; client->context = redisConnectUnix(socket_path); client->last_activity = time(NULL); return client; } int ensure_connected(redis_client_t *client) { if (client->context == NULL || client->context->err) { if (client->context) { redisFree(client->context); } client->context = redisConnectUnix(client->socket_path); if (client->context == NULL || client->context->err) { return -1; // 连接失败 } } client->last_activity = time(NULL); return 0; } void redis_command_safe(const char *format, char *value) { if (ensure_connected(redisClient) == 0) { redisReply *reply = redisCommand(redisClient->context, format, value); if (reply) { // 处理回复 freeReplyObject(reply); } } } /* * @cmd 执行命令 * @value 命令结果指针 * @lenth 存储结果长度 int GetCmdValue(char *cmd, char *value, int lenth) { bzero(value, lenth); FILE *fp = popen(cmd,"r"); if(fp != NULL){ fread(value, 1, lenth, fp); pclose(fp); } else { printf("Handle \"%s\" failed.\n", cmd); return FALSE; } return TRUE; } */ 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; } 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); } 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("/etc/scripts/pa_mute.sh 0"); } else { system("/etc/scripts/pa_mute.sh 1"); } } Boolean get_ip(char * pv) { FILE * fp; char cmdbuf[128], value[32]; char *tmp=NULL; sprintf(cmdbuf,"/sbin/ifconfig eth0 | grep inet | cut -d\":\" -f2 | cut -d\" \" -f1"); 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 eth0 | grep HWaddr | tr -d : | awk '{print $5}'"); 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; } void action_url(char *url) { char cmd[320]; sprintf(cmd,"curl -k --connect-timeout 5 '%s' 2>/dev/null &",url); if(DEBUG) printf( "Command: %s\n", cmd); system(cmd); writeLog( FUN, "API HTTP Request", url ); } //发送控制指令 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 outputControl(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); } } //gpio延时控制 void *gpioDelayControl() { usleep(delay*1000*1000); outputControl(GPIO_RELAY, GPIO_OFF); if(DEBUG) printf( "gpio135 set off\n" ); } //呼入触发 void incomingTrigger(cJSON *pJson) { char enable[8],url[256],ipaddr[16],macaddr[16], peeruri[128]; GetCmdValue(SPK_CONF, "call_action_url:incoming_enable", enable, sizeof(enable)); if(strcmp(enable,"yes") == 0) { GetCmdValue(SPK_CONF, "call_action_url:incoming_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)) { strcpy(url, strrpl(url, VAR_UA, cJSON_GetObjectItem(pJson, "exten")->valuestring)); } if(strstr(url,VAR_NUM)) { char *ret, number[64]; strcpy(peeruri, cJSON_GetObjectItem(pJson, "peeruri")->valuestring); ret = strchr(peeruri, '@'); if(ret) { memset(number,0,sizeof(number)); strncpy(number,peeruri,ret - peeruri); strcpy(url, strrpl(url, VAR_NUM, number + 4)); } } action_url(url); } } //呼出触发 void outgoingTrigger(cJSON *pJson) { char enable[8],url[256],ipaddr[16],macaddr[16], peeruri[128]; GetCmdValue(SPK_CONF, "call_action_url:outgoing_enable", enable, sizeof(enable)); if(strcmp(enable,"yes") == 0) { GetCmdValue(SPK_CONF, "call_action_url:outgoing_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)) { strcpy(url, strrpl(url, VAR_UA, cJSON_GetObjectItem(pJson, "exten")->valuestring)); } if(strstr(url,VAR_NUM)) { char *ret, number[64]; strcpy(peeruri, cJSON_GetObjectItem(pJson, "peeruri")->valuestring); ret = strchr(peeruri, '@'); if(ret) { memset(number,0,sizeof(number)); strncpy(number,peeruri,ret - peeruri); strcpy(url, strrpl(url, VAR_NUM, number + 4)); } } action_url(url); } } //应答触发 void answeredTrigger(cJSON *pJson) { char enable[8],url[256],ipaddr[16],macaddr[16], peeruri[128]; GetCmdValue(SPK_CONF, "call_action_url:answered_enable", enable, sizeof(enable)); if(strcmp(enable,"yes") == 0) { GetCmdValue(SPK_CONF, "call_action_url:answered_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)) { strcpy(url, strrpl(url, VAR_UA, cJSON_GetObjectItem(pJson, "exten")->valuestring)); } if(strstr(url,VAR_NUM)) { char *ret, number[64]; strcpy(peeruri, cJSON_GetObjectItem(pJson, "peeruri")->valuestring); ret = strchr(peeruri, '@'); if(ret) { memset(number,0,sizeof(number)); strncpy(number,peeruri,ret - peeruri); strcpy(url, strrpl(url, VAR_NUM, number + 4)); } } action_url(url); } } //应答触发 void hangupTrigger(cJSON *pJson) { char enable[8],url[256],ipaddr[16],macaddr[16], peeruri[128]; GetCmdValue(SPK_CONF, "call_action_url:hangup_enable", enable, sizeof(enable)); if(strcmp(enable,"yes") == 0) { GetCmdValue(SPK_CONF, "call_action_url:hangup_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)) { strcpy(url, strrpl(url, VAR_UA, cJSON_GetObjectItem(pJson, "exten")->valuestring)); } if(strstr(url,VAR_NUM)) { char *ret, number[64]; strcpy(peeruri, cJSON_GetObjectItem(pJson, "peeruri")->valuestring); ret = strchr(peeruri, '@'); if(ret) { memset(number,0,sizeof(number)); strncpy(number,peeruri,ret - peeruri); strcpy(url, strrpl(url, VAR_NUM, number + 4)); } } action_url(url); } } //baresip状态监控 void ProcessReply( redisReply * pReply ) { cJSON *pJson = NULL; 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(strcmp(cJSON_GetObjectItem(pJson, "type")->valuestring, "CALL_ESTABLISHED") == 0) { //通话 BARESIP_STATUS = INUSE; answeredTrigger(pJson); } else if(strcmp(cJSON_GetObjectItem(pJson, "direction")->valuestring, "incoming") == 0 && strcmp(cJSON_GetObjectItem(pJson, "type")->valuestring, "CALL_CLOSED") == 0) { //挂断 if(BARESIP_STATUS != OFFLINE){ BARESIP_STATUS = IDLE; } hangupTrigger(pJson); } else if(strcmp(cJSON_GetObjectItem(pJson, "direction")->valuestring, "outgoing") == 0 && strcmp(cJSON_GetObjectItem(pJson, "type")->valuestring, "CALL_CLOSED") == 0) { //挂断 if(BARESIP_STATUS != OFFLINE){ BARESIP_STATUS = IDLE; } hangupTrigger(pJson); } else if(strcmp(cJSON_GetObjectItem(pJson, "direction")->valuestring, "incoming") == 0 && strcmp(cJSON_GetObjectItem(pJson, "type")->valuestring, "CALL_INCOMING") == 0) { //呼入振铃状态 if(BARESIP_STATUS == IDLE) { BARESIP_STATUS = RING; incomingTrigger(pJson); } } else if(strcmp(cJSON_GetObjectItem(pJson, "direction")->valuestring, "outgoing") == 0 && strcmp(cJSON_GetObjectItem(pJson, "type")->valuestring, "CALL_OUTGOING") == 0) { //呼出回铃状态 if(BARESIP_STATUS == IDLE || BARESIP_STATUS == DIALING) { BARESIP_STATUS = RINGING; outgoingTrigger(pJson); } } 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) { BARESIP_STATUS = IDLE; } 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); 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); 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); return; } } } } 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; } 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; } 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; } cJSON_Delete(pJson); return; } } } } 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; } 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) { ACCOUNTP2P_REG = REGISTER_OK; BARESIP_STATUS = IDLE; } else { ACCOUNTP2P_REG = REGISTER_FAIL; } } } 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 sipphone_call(char *number, char *line) { char cmd[MAX_PIPE_BUFSIZE]; char accountaor[192],strtmp[64]; char account[32],domain[128]; int channel = BARESIP_CHAN, line_id[4]; if(DEBUG) printf( "BARESIP_STATUS [%d]\n", BARESIP_STATUS ); if(BARESIP_STATUS == IDLE) { BARESIP_STATUS = DIALING; if(strlen(number) == 0) { BARESIP_STATUS = IDLE; return; } get_line(line_id); if(strcmp(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; return; } sprintf(cmd,"{\"cmd\":\"dial\",\"data\":\"%s %d\"}",number, line_id[1]); } else if(ACCOUNT2_REG == REGISTER_OK) { if(line_id[2] == -1) { BARESIP_STATUS = IDLE; return; } sprintf(cmd,"{\"cmd\":\"dial\",\"data\":\"%s %d\"}",number, line_id[2]); } else if(ACCOUNT3_REG == REGISTER_OK) { if(line_id[3] == -1) { BARESIP_STATUS = IDLE; return; } sprintf(cmd,"{\"cmd\":\"dial\",\"data\":\"%s %d\"}",number, line_id[3]); } else { BARESIP_STATUS = IDLE; return; } } else if (strcmp(line, "account_info_1") == 0) { if(line_id[1] == -1 || ACCOUNT1_REG != REGISTER_OK) { BARESIP_STATUS = IDLE; return; } sprintf(cmd,"{\"cmd\":\"dial\",\"data\":\"%s %d\"}",number, line_id[1]); } else if (strcmp(line, "account_info_2") == 0) { if(line_id[2] == -1 || ACCOUNT2_REG != REGISTER_OK) { BARESIP_STATUS = IDLE; return; } sprintf(cmd,"{\"cmd\":\"dial\",\"data\":\"%s %d\"}",number, line_id[2]); } else if (strcmp(line, "account_info_3") == 0) { if(line_id[3] == -1 || ACCOUNT3_REG != REGISTER_OK) { BARESIP_STATUS = IDLE; return; } sprintf(cmd,"{\"cmd\":\"dial\",\"data\":\"%s %d\"}",number, line_id[3]); } else if(strcmp(line,"p2p") == 0) { sprintf(cmd,"{\"cmd\":\"dial\",\"data\":\"%s\"}",number); } if(DEBUG) printf( "dial [%s]\n", cmd ); control_cmd(channel, cmd); sprintf(strtmp, "%s <%s>", number, line); writeLog( FUN, "API Call", strtmp ); } } void sipphone_answer() { char cmd[MAX_PIPE_BUFSIZE]; int channel = BARESIP_CHAN; if(DEBUG) printf( "BARESIP_STATUS [%d]\n", BARESIP_STATUS ); if(BARESIP_STATUS == RING) { strcpy(cmd,"{\"cmd\":\"accept\",\"data\":\"\"}"); if(DEBUG) printf( "answer call\n" ); control_cmd(channel, cmd); writeLog( FUN, "API Answer", "" ); } } void sipphone_hangup() { char cmd[MAX_PIPE_BUFSIZE]; int channel = BARESIP_CHAN; if(DEBUG) printf( "BARESIP_STATUS [%d]\n", BARESIP_STATUS ); if(BARESIP_STATUS == RINGING || BARESIP_STATUS == INUSE) { strcpy(cmd,"{\"cmd\":\"hangup\",\"data\":\"\"}"); if(DEBUG) printf( "hangup call\n" ); control_cmd(channel, cmd); writeLog( FUN, "API Hangup", "" ); } } void sipphone_loop_start() { char cmd[MAX_PIPE_BUFSIZE], hversion[16]; int channel = BARESIP_CHAN; if(DEBUG) printf( "BARESIP_STATUS [%d]\n", BARESIP_STATUS ); if(BARESIP_STATUS == IDLE || BARESIP_STATUS == OFFLINE) { strcpy(cmd,"{\"cmd\":\"auloop\",\"data\":\"48000 1\"}"); if(DEBUG) printf( "audio loop\n" ); control_cmd(channel, cmd); GetCmdValue(SPK_CONF, "system:hard_version", hversion, sizeof(hversion)); if(strcmp(hversion, "Ver3.2") == 0) system("/etc/scripts/pa_mute.sh 0;echo 0 > /sys/class/gpio/gpio143/value"); else system("/etc/scripts/pa_mute.sh 0;echo 0 > /sys/class/gpio/gpio134/value"); BARESIP_STATUS = LOOPSTART; writeLog( FUN, "API Audio Loop", "Start" ); } } void sipphone_loop_stop() { char cmd[MAX_PIPE_BUFSIZE], hversion[16]; int channel = BARESIP_CHAN; if(DEBUG) printf( "BARESIP_STATUS [%d]\n", BARESIP_STATUS ); if(BARESIP_STATUS == LOOPSTART) { strcpy(cmd,"{\"cmd\":\"auloop_stop\",\"data\":\"\"}"); if(DEBUG) printf( "hangup call\n" ); control_cmd(channel, cmd); GetCmdValue(SPK_CONF, "system:hard_version", hversion, sizeof(hversion)); if(strcmp(hversion, "Ver3.2") == 0) system("/etc/scripts/pa_mute.sh 1;echo 1 > /sys/class/gpio/gpio143/value"); else system("/etc/scripts/pa_mute.sh 1;echo 1 > /sys/class/gpio/gpio134/value"); BARESIP_STATUS = IDLE; writeLog( FUN, "API Audio Loop", "Stop" ); } } void *playTimer(void *arg) { char cmd[32]; PlayInfo *p = arg; long t = p->duration*1000*1000; usleep(t); vlcInfo.state = FALSE; sprintf(cmd,"kill -9 %d",vlcInfo.pid); system(cmd); writeLog(FUN, "Specified duration expires", vlcInfo.param); } void *handle_playAudio(void *arg) { char syscmd[256]; int status; PlayInfo *p = arg; if(strlen(p->url) > 7 && (strncmp(p->url, "http://", 7) == 0 || strncmp(p->url, "rtsp://", 7) == 0 || strncmp(p->url, "ftp://", 6) == 0)) { if(p->volume >= 0) { sprintf(syscmd, "vlc -I dummy --network-caching=100 --gain=%.02f --play-and-exit '%s'", (float) p->volume/100, p->url); sprintf(vlcInfo.param,"URL: %s; valume: %d", p->url, p->volume); } else { sprintf(syscmd, "vlc -I dummy --network-caching=100 --gain=%.02f --play-and-exit '%s'", (float) p->volume/100, p->url); sprintf(vlcInfo.param,"URL: %s", p->url); } char *argv[] = {"sh","-c",syscmd, NULL}; status = posix_spawn(&vlcInfo.pid,"/bin/sh",NULL,NULL,argv,NULL); if(status == 0) { vlcInfo.state = TRUE; amplifier_switch(TRUE); if(p->duration > 0) { pthread_t thread_audio; char strtmp[32]; pthread_create(&thread_audio, NULL, playTimer, p); pthread_detach(thread_audio); sprintf(strtmp,"; duration: %ds", p->duration); strcat(vlcInfo.param, strtmp); } writeLog(FUN,"API Play URL Audio", vlcInfo.param); if(waitpid(vlcInfo.pid, &status, 0) != -1) { amplifier_switch(FALSE); printf("Child exited with status %i\n", status); if(vlcInfo.state) { writeLog(FUN, "Audio file playback ends", vlcInfo.param); vlcInfo.state = FALSE; } } } } free(p); } //gpio控制指令处理 void ProcessAPIReply( redisReply * pReply ) { cJSON *pJson = NULL, *subJson = NULL; redisReply * pSubReply = NULL; char cmd[MAX_PIPE_BUFSIZE], shellcmd[MAX_PIPE_BUFSIZE]; char sipphone[8],relay[8],player[8],strtmp[64]; int channel = BARESIP_CHAN; if ( pReply->elements == 2 ) { pSubReply = pReply->element[1]; if(DEBUG) printf( "Msg [%s]\n", pSubReply->str ); pJson = cJSON_Parse(pSubReply->str); if ( pJson ) { if(cJSON_GetObjectItem(pJson, "type")) { if(strcmp(cJSON_GetObjectItem(pJson, "type")->valuestring, "sipphone") == 0) { GetCmdValue(SPK_CONF, "api:call_enable", sipphone, sizeof(sipphone)); if(cJSON_GetObjectItem(pJson, "action")){ if(strcmp(sipphone, "yes") == 0) { if(strcmp(cJSON_GetObjectItem(pJson, "action")->valuestring, "call") == 0) { if(cJSON_GetObjectItem(pJson, "data")) { subJson = cJSON_GetObjectItem(pJson, "data"); sipphone_call(cJSON_GetObjectItem(subJson, "number")->valuestring, cJSON_GetObjectItem(subJson, "line")->valuestring); } } else if(strcmp(cJSON_GetObjectItem(pJson, "action")->valuestring, "answer") == 0) { sipphone_answer(); } else if(strcmp(cJSON_GetObjectItem(pJson, "action")->valuestring, "hangup") == 0) { sipphone_hangup(); } } if(strcmp(cJSON_GetObjectItem(pJson, "action")->valuestring, "auloopstart") == 0) { sipphone_loop_start(); } else if(strcmp(cJSON_GetObjectItem(pJson, "action")->valuestring, "auloopstop") == 0) { sipphone_loop_stop(); } } } else if(strcmp(cJSON_GetObjectItem(pJson, "type")->valuestring, "relay") == 0) { if(cJSON_GetObjectItem(pJson, "action")) { if(strcmp(cJSON_GetObjectItem(pJson, "action")->valuestring, "on") == 0) { outputControl(GPIO_RELAY, GPIO_ON); subJson = cJSON_GetObjectItem(pJson, "data"); if(subJson){ delay = cJSON_GetObjectItem(subJson, "duration")->valueint; if(delay > 0) { int ret_thrd_delay; pthread_t thread_delay; ret_thrd_delay = pthread_create(&thread_delay, NULL, gpioDelayControl, NULL); if (ret_thrd_delay != 0) { printf("create thread_delay gpioDelayControl failed\n"); cJSON_Delete(pJson); return; } pthread_detach(thread_delay); } } } else if(strcmp(cJSON_GetObjectItem(pJson, "action")->valuestring, "off") == 0) { outputControl(GPIO_RELAY, GPIO_OFF); } } } else if(strcmp(cJSON_GetObjectItem(pJson, "type")->valuestring, "player") == 0) { if(cJSON_GetObjectItem(pJson, "action")) { if(strcmp(cJSON_GetObjectItem(pJson, "action")->valuestring, "start") == 0) { subJson = cJSON_GetObjectItem(pJson, "data"); if(subJson && cJSON_GetObjectItem(subJson, "repeat") && cJSON_GetObjectItem(subJson, "volume")) { int repeat = cJSON_GetObjectItem(subJson, "repeat")->valueint; int volume = cJSON_GetObjectItem(subJson, "volume")->valueint; if(volume >= 0) { sprintf(cmd,"{\"cmd\":\"setaudiotempvol\",\"data\":\"%d\"}",volume); control_cmd(channel, cmd); } sprintf(cmd,"{\"cmd\":\"play\",\"data\":\"%s:%d\"}",cJSON_GetObjectItem(subJson, "file")->valuestring,repeat); control_cmd(channel, cmd); PLAYING = TRUE; sprintf(strtmp, "File: %s; Repeat: %d; Volume: %d", cJSON_GetObjectItem(subJson, "file")->valuestring, repeat, volume); writeLog( FUN, "API Play Auido", strtmp ); } } else if(strcmp(cJSON_GetObjectItem(pJson, "action")->valuestring, "stop") == 0) { sprintf(cmd,"{\"cmd\":\"play\",\"data\":\"\"}"); control_cmd(channel, cmd); PLAYING = FALSE; writeLog( FUN, "API Stop Auido", "" ); } } } else if(strcmp(cJSON_GetObjectItem(pJson, "type")->valuestring, "urlplayer") == 0) { if(cJSON_GetObjectItem(pJson, "action")) { if(strcmp(cJSON_GetObjectItem(pJson, "action")->valuestring, "start") == 0) { subJson = cJSON_GetObjectItem(pJson, "data"); if(subJson && cJSON_GetObjectItem(subJson, "duration") && cJSON_GetObjectItem(subJson, "volume")) { pthread_t thread_audio; int ret_thrd; PlayInfo *playAudioInfo = malloc(sizeof(PlayInfo)); playAudioInfo->duration = cJSON_GetObjectItem(subJson, "duration")->valueint; playAudioInfo->volume = cJSON_GetObjectItem(subJson, "volume")->valueint; strcpy(playAudioInfo->url, cJSON_GetObjectItem(subJson, "url")->valuestring); ret_thrd = pthread_create(&thread_audio, NULL, handle_playAudio, playAudioInfo); if (ret_thrd != 0) { printf("create thread1 handle_playAudio failed\n"); free(playAudioInfo); cJSON_Delete(pJson); return; } pthread_detach(thread_audio); } } else if(strcmp(cJSON_GetObjectItem(pJson, "action")->valuestring, "stop") == 0) { if(vlcInfo.state) { sprintf(cmd,"kill -9 %d",vlcInfo.pid); system(cmd); vlcInfo.state = FALSE; writeLog(FUN, "Playback stops by API call", vlcInfo.param); } } } } } }else{ printf( "parse failed!\n"); } if(pJson != NULL) cJSON_Delete(pJson); } } /* * 接收控制指令. */ void *api_control() { redisContext * pContext = redisConnectUnix(unix_socket_path); if ( NULL == pContext || pContext->err == 1 ) { printf( "%s\n", pContext->errstr ); exit( -1 ); } char * pKey = "api-channel"; redisReply * pReply; while(1){ pReply = NULL; pReply = redisCommand( pContext, "BRPOP %s 60", pKey ); if(pReply != NULL && pReply->type == REDIS_REPLY_ARRAY){ ProcessAPIReply( pReply ); } if(pReply != NULL) freeReplyObject( pReply ); } redisFree( pContext ); } //解析音量设置数据 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, "sip_volume")) { sprintf(cmd,"{\"cmd\":\"setvol\",\"data\":\"%d\"}",cJSON_GetObjectItem(pJson, "sip_volume")->valueint); control_cmd(channel, cmd); } }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 ); } int main(int argc, char *argv[]){ char model[16]; int ret_thrd1,ret_thrd2; pthread_t thread1, thread2; if(argc == 2 && strcmp(argv[1], "debug") == 0) DEBUG = TRUE; redisClient = create_redis_client(unix_socket_path); //启动线程订阅BARESIP实时状态 ret_thrd1 = pthread_create(&thread1, NULL, baresip_status, NULL); if (ret_thrd1 != 0) { printf("create thread1 baresip_status failed\n"); return 0; } //启动线程订阅音量设置 ret_thrd2 = pthread_create(&thread2, NULL, get_volume_info, NULL); if (ret_thrd2 != 0) { printf("create thread2 get_volume_info failed\n"); return 0; } api_control(); }