Yu.Ding 1 vecka sedan
incheckning
3845b0450b
100 ändrade filer med 18547 tillägg och 0 borttagningar
  1. BIN
      Modules/.DS_Store
  2. 21 0
      Modules/api_agent/Makefile
  3. 1231 0
      Modules/api_agent/main.c
  4. 235 0
      Modules/clock/AIP1629A-timedisplay.c
  5. BIN
      Modules/clock/clock.sh
  6. 14 0
      Modules/eq_process/Makefile
  7. 161 0
      Modules/eq_process/Rk_wake_lock.cpp
  8. 21 0
      Modules/eq_process/Rk_wake_lock.h
  9. 20 0
      Modules/eq_process/S97_EQ_init
  10. 739 0
      Modules/eq_process/main.c
  11. 744 0
      Modules/eq_process/main.cpp
  12. 220 0
      Modules/onvif/test-onvif-backchannel.c
  13. 21 0
      Modules/output_control/Makefile
  14. 376 0
      Modules/output_control/main.c
  15. 21 0
      Modules/play_ip/Makefile
  16. 750 0
      Modules/play_ip/cJSON.c
  17. 149 0
      Modules/play_ip/cJSON.h
  18. 173 0
      Modules/play_ip/dictionary.h
  19. 358 0
      Modules/play_ip/iniparser.h
  20. 295 0
      Modules/play_ip/main.c
  21. 20 0
      Modules/playip/Makefile
  22. 92 0
      Modules/playip/main.c
  23. 21 0
      Modules/serial_ctrl/Makefile
  24. 170 0
      Modules/serial_ctrl/log.c
  25. 50 0
      Modules/serial_ctrl/log.h
  26. 1197 0
      Modules/serial_ctrl/main.c
  27. 21 0
      Modules/service_process/Makefile
  28. 2741 0
      Modules/service_process/main.c
  29. BIN
      Modules/sipconf/.DS_Store
  30. 21 0
      Modules/sipconf/Makefile
  31. 905 0
      Modules/sipconf/main.c
  32. 22 0
      Modules/watch_gpio/Makefile
  33. 304 0
      Modules/watch_gpio/main.c
  34. 21 0
      Modules/watchdog/Makefile
  35. 89 0
      Modules/watchdog/main.c
  36. 5 0
      etc/lightdm/lightdm.conf
  37. BIN
      etc/logo/favicon.ico
  38. BIN
      etc/logo/logo.png
  39. BIN
      etc/logo/logo@2x.png
  40. 25 0
      etc/rc.local
  41. 1832 0
      etc/redis.conf
  42. 32 0
      etc/scripts/action.sh
  43. BIN
      etc/scripts/api_agent
  44. 124 0
      etc/scripts/audio_init.sh
  45. 112 0
      etc/scripts/auto_privisioning.sh
  46. 2271 0
      etc/scripts/conf_handle.sh
  47. 47 0
      etc/scripts/config_store.sh
  48. 13 0
      etc/scripts/dhcp_auto_privisioning.sh
  49. 21 0
      etc/scripts/factoryReset_check.sh
  50. 16 0
      etc/scripts/getmodel.sh
  51. 54 0
      etc/scripts/getsubmask.sh
  52. 30 0
      etc/scripts/gpio_init.sh
  53. 22 0
      etc/scripts/httpd.sh
  54. 107 0
      etc/scripts/import_compare.sh
  55. 59 0
      etc/scripts/keep_tcpdump.sh
  56. 30 0
      etc/scripts/merge_conf.sh
  57. 36 0
      etc/scripts/monitor_ptp.sh
  58. BIN
      etc/scripts/onvif-discover
  59. 116 0
      etc/scripts/onvif_upgrade.sh
  60. BIN
      etc/scripts/onvifserver
  61. BIN
      etc/scripts/output_control
  62. 13 0
      etc/scripts/pa_mute.sh
  63. BIN
      etc/scripts/play_ip
  64. 31 0
      etc/scripts/play_rebooting.sh
  65. 34 0
      etc/scripts/product_model.sh
  66. BIN
      etc/scripts/rtspserver
  67. BIN
      etc/scripts/serial_ctrl
  68. BIN
      etc/scripts/service_process
  69. 26 0
      etc/scripts/set_lan.sh
  70. 170 0
      etc/scripts/set_volume.sh
  71. 13 0
      etc/scripts/set_webpid.sh
  72. 40 0
      etc/scripts/settime.sh
  73. 440 0
      etc/scripts/shell_action.sh
  74. BIN
      etc/scripts/sipconf
  75. 41 0
      etc/scripts/sipphone.sh
  76. 19 0
      etc/scripts/system_led.sh
  77. 43 0
      etc/scripts/tcpdump.sh
  78. 35 0
      etc/scripts/trouble_shooting.sh
  79. 102 0
      etc/scripts/upgrade.sh
  80. 43 0
      etc/scripts/watch.sh
  81. 196 0
      etc/scripts/watch_process.sh
  82. 14 0
      etc/scripts/watch_tool.sh
  83. 42 0
      etc/scripts/webpid.sh
  84. 759 0
      oem/etc/schedule.conf
  85. 288 0
      oem/etc/speaker.conf
  86. 23 0
      oem/etc/volctrl.conf
  87. BIN
      usr/bin/bareservice
  88. BIN
      usr/bin/baresip
  89. BIN
      usr/bin/sysconf
  90. BIN
      usr/lib/aarch64-linux-gnu/libaec_bf_process.so
  91. BIN
      usr/lib/aarch64-linux-gnu/libbaresip.so
  92. BIN
      usr/lib/aarch64-linux-gnu/libbaresip.so.14
  93. BIN
      usr/lib/aarch64-linux-gnu/libbaresip.so.14.10.1
  94. BIN
      usr/lib/aarch64-linux-gnu/libcrypto.so.1.1
  95. BIN
      usr/lib/aarch64-linux-gnu/libdeflate.so.0
  96. BIN
      usr/lib/aarch64-linux-gnu/libhiredis.so
  97. BIN
      usr/lib/aarch64-linux-gnu/libhiredis.so.0.14
  98. BIN
      usr/lib/aarch64-linux-gnu/libjbig.so.0
  99. BIN
      usr/lib/aarch64-linux-gnu/libjpeg.so.8
  100. 0 0
      usr/lib/aarch64-linux-gnu/liblzma.so.5

BIN
Modules/.DS_Store


+ 21 - 0
Modules/api_agent/Makefile

@@ -0,0 +1,21 @@
+TARGET = api_agent
+Dir2store = /opt/Rockchip/external/X10/etc/scripts
+objects = *.o
+CFLAGS = -lpthread -lhiredis -lm -liniparser -lcjson
+
+${TARGET}:$(objects)
+	${CC} -o $@ $(objects) $(CFLAGS)
+
+%.o:%.c
+	${CC} -c $<
+
+.PHONY:clean install uninstall
+
+clean:
+	rm -f *.o ${TARGET}
+
+install:
+	cp -f ${TARGET} ${Dir2store}
+
+uninstall:
+	rm -f ${Dir2store}/${TARGET}

Filskillnaden har hållts tillbaka eftersom den är för stor
+ 1231 - 0
Modules/api_agent/main.c


+ 235 - 0
Modules/clock/AIP1629A-timedisplay.c

@@ -0,0 +1,235 @@
+/**************************************************************
+* 数码管时钟显示程序:
+* 1. 宏定义SPI_CS为SPI片选引脚,根据需要修改gpio143的数字即可
+* 2. cmd_dis_mode变量为数码管亮度设置变量,取值为0x88--0x8F
+**************************************************************/
+#include <sys/poll.h>
+#include <signal.h>
+#include <sys/time.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <time.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <linux/spi/spidev.h>
+#include <sys/ioctl.h>
+#include "iniparser.h"
+
+#define TRUE	1
+#define FALSE	0
+#define SPI_CS 	"/sys/class/gpio/gpio143/value"
+#define SPK_CONF    "/etc/speaker.conf"
+#define _DATETIME_SIZE 32
+
+const unsigned char BCD_LABLE_ALL[19]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f,
+											0x00,0x01,0x03,0x07,0x0f,0x1f,0x3f,0x7f,0xff};
+unsigned char BCD_LABLE_anode[16] = {0}; 
+unsigned char cmd_dis_mode = 0x8B;	/* 数码管亮度设置,最小0x88, 最大0x8F */
+int fd;
+static int is24Hour = TRUE;
+
+int send_8bit(unsigned char data)
+{
+	unsigned char tmp[1]={0};
+
+	data=(data<<4) | (data>>4);
+	data=((data<<2)&0xcc) | ((data>>2)&0x33);
+	data=((data<<1)&0xaa) | ((data>>1)&0x55);
+	tmp[0] = data;
+	write(fd, tmp, 1);
+
+	return 0;
+}
+
+void send_command(unsigned char data)
+{
+	system("echo 1 > " SPI_CS);	
+	usleep(1);
+	system("echo 0 > " SPI_CS);		
+	send_8bit(data);
+}
+
+void Write_String(unsigned char *p,unsigned char cnt) 
+{
+	unsigned char i;
+
+	for(i=0; i<cnt; i++){
+		send_8bit(*p++);
+	}
+}
+
+void NE_C(unsigned char ydata,unsigned char cnt)
+{
+	char i=0,j=0;
+	if(cnt>0){
+		if(cnt>8){
+			cnt = cnt - 9;
+			for(i=1;i<16;i=i+2)
+			{
+				if(ydata&0x01 == 0x01)
+				{
+					BCD_LABLE_anode[i] |= (0x01<<cnt);
+				}
+				else
+				{
+					BCD_LABLE_anode[i] &= ~(0x01<<cnt); 
+				}
+				ydata = (ydata>>1);
+			}
+		}else {
+			cnt = cnt -1;
+			for(i=0;i<16;i=i+2)
+			{
+				if((ydata&0x01) == 0x01){
+					BCD_LABLE_anode[i] |= (0x01<<cnt);
+				}
+				else{
+					BCD_LABLE_anode[i] &= ~(0x01<<cnt);
+				}
+				ydata = (ydata>>1);
+			}
+		}
+	}
+}
+
+int is24HourClock()
+{
+	dictionary  *   ini ;
+	ini = iniparser_load(SPK_CONF);
+	char is24hourclock[8];
+	
+    if (ini==NULL) {
+        fprintf(stderr, "cannot parse file: %s\n", SPK_CONF);
+        return FALSE ;
+    }
+	strcpy(is24hourclock, iniparser_getstring(ini, "system:is24hourclock", "yes"));
+	
+	iniparser_freedict(ini);
+	if(strcmp(is24hourclock,"yes") == 0)
+	{
+		return TRUE;
+	}
+	else
+	{
+		return FALSE;
+	}
+}
+
+void display(unsigned char number,unsigned char cnt1)
+{
+	NE_C(BCD_LABLE_ALL[number],cnt1);
+	send_command(0x40); 
+	send_command(0xc0); 
+	Write_String(BCD_LABLE_anode,16);
+	send_command(cmd_dis_mode);
+
+	system("echo 1 > " SPI_CS);	
+}
+
+void display_fixedadd(unsigned char number, unsigned char cnt1, unsigned char addr)
+{
+	NE_C(BCD_LABLE_ALL[number],cnt1);
+	send_command(0x44); 	
+	send_command(addr);
+	send_8bit(BCD_LABLE_anode[number]);		
+	send_command(cmd_dis_mode);
+
+	system("echo 1 > " SPI_CS);	
+}
+
+int gettime(char *psTime)
+{
+	time_t nSeconds;
+	struct tm *pTM;
+	int tmp_hour;
+
+	time(&nSeconds); //same with nSeconds = time(NULL);
+	pTM = localtime(&nSeconds);
+	if(is24Hour)
+	{
+		tmp_hour = pTM->tm_hour;
+	}
+	else
+	{
+		tmp_hour = pTM->tm_hour%12;
+		if(tmp_hour == 0) tmp_hour = 12;
+	}
+
+	sprintf(psTime, "%02d:%02d:%02d", tmp_hour, pTM->tm_min, pTM->tm_sec);
+
+	return 0;		
+}
+
+int main(int argc, char *argv[]){	
+	int ret,i;
+	char DateTime[_DATETIME_SIZE];
+	char Old_Clock[5];
+	unsigned int speed=8000;
+	unsigned char spi_mode=0;
+	char dot_flash=0;
+
+	//printf("+----------hello world-----------+\n");
+	fd = open("/dev/spidev0.0", O_RDWR);
+	if(fd < 0){
+		printf("open spidev error!!\n");
+		return fd;
+	}
+	ret = ioctl(fd, SPI_IOC_WR_MODE, &spi_mode);
+	ret = ioctl(fd, SPI_IOC_WR_MAX_SPEED_HZ, &speed);
+	is24Hour = is24HourClock();
+
+	memset(DateTime, 0, sizeof(DateTime));
+	memset(Old_Clock, 0, sizeof(Old_Clock));
+	ret = gettime(DateTime);
+	if(DateTime[0] - 0x30 == 0)
+		display(10,1);
+	else
+		display(DateTime[0]-0x30, 1);
+	display(DateTime[1]-0x30, 2);
+	display(DateTime[3]-0x30, 3);
+	display(DateTime[4]-0x30, 4);
+	for(i=0; i<5; i++)	
+		Old_Clock[i] = DateTime[i]-0x30;
+
+	while(1){
+		ret = gettime(DateTime);
+
+		if(Old_Clock[0] != (DateTime[0]-0x30)){
+			Old_Clock[0] = DateTime[0]-0x30;
+			if(Old_Clock[0] == 0)
+				display(10, 1);
+			else
+				display(Old_Clock[0], 1);
+		}
+		if(Old_Clock[1] != (DateTime[1]-0x30)){
+			Old_Clock[1] = DateTime[1]-0x30;
+			display(Old_Clock[1], 2);
+		}
+		if(Old_Clock[3] != (DateTime[3]-0x30)){
+			Old_Clock[3] = DateTime[3]-0x30;
+			display(Old_Clock[3], 3);
+		}
+		if(Old_Clock[4] != (DateTime[4]-0x30)){
+			Old_Clock[4] = DateTime[4]-0x30;
+			display(Old_Clock[4], 4);
+		}		
+		sleep(1);	
+		if(!dot_flash){
+			display(18, 5); 
+			//display(18, 6); 
+			dot_flash = 1;
+		}else{
+			display(0, 5); 
+			//display(0, 6); 
+			dot_flash = 0;			
+		}
+	}
+
+	close(fd);	
+
+	return 0;
+}
+

BIN
Modules/clock/clock.sh


+ 14 - 0
Modules/eq_process/Makefile

@@ -0,0 +1,14 @@
+#common makefile header
+PROJECT_DIR := $(shell pwd)
+PROM    = eq_drc_process
+#CXXFLAGS ?= -fPIC -O3 -I$(PROJECT_DIR) -lasound -lm -lhiredis -lpthread
+CXXFLAGS =  -lasound -lm -lhiredis -lpthread -lcjson -liniparser
+OBJ =  main.o 
+$(PROM): $(OBJ)
+	$(CXX) -o $(PROM) $(OBJ) $(CXXFLAGS)
+%.o: %.c
+	$(CXX) -c $< -o $@ $(CXXFLAGS)
+clean:
+	@rm -rf $(OBJ) $(PROM)
+install:
+	sudo install -D -m 755 eq_drc_process -t /usr/bin/

+ 161 - 0
Modules/eq_process/Rk_wake_lock.cpp

@@ -0,0 +1,161 @@
+#include <fcntl.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <errno.h>
+#include <string.h>
+#include <pthread.h>
+#include "Rk_wake_lock.h"
+
+struct rk_wake_lock {
+	char *id;
+};
+
+#define TAG "WAKE_LOCK"
+
+#define debug(fmt, args...) \
+    printf(TAG "[%s] " fmt "\n", __func__, ##args)
+
+enum {
+	ACQUIRE_PARTIAL_WAKE_LOCK = 0,
+	RELEASE_WAKE_LOCK,
+	OUR_FD_COUNT
+};
+
+const char * const WAKE_LOCK_PATHS[] = {
+	"/sys/power/wake_lock",
+	"/sys/power/wake_unlock",
+};
+
+static int g_initialized = 0;
+static int g_fds[2];
+static int g_error = -1;
+
+static int open_file_descriptors(const char * const paths[])
+{
+	for (int i = 0 ; i < 2; i++) {
+		int fd = open(paths[i], O_RDWR | O_CLOEXEC);
+		if (fd < 0) {
+			g_error = -errno;
+			debug("fatal error opening \"%s\": %s", paths[i],
+				  strerror(errno));
+			return -1;
+		}
+		g_fds[i] = fd;
+	}
+
+	g_error = 0;
+	return 0;
+}
+
+static inline void initialize_fds(void) {
+	if (g_initialized == 0) {
+		open_file_descriptors(WAKE_LOCK_PATHS);
+		g_initialized = 1;
+	}
+}
+
+struct rk_wake_lock* RK_wake_lock_new(const char *id) {
+	struct rk_wake_lock* lock;
+	if (!id)
+		return NULL;
+	initialize_fds();
+
+	lock = (struct rk_wake_lock*)malloc(sizeof(struct rk_wake_lock));
+	lock->id = strdup(id);
+	return lock;
+}
+
+void RK_wake_lock_delete(struct rk_wake_lock* lock) {
+	if (lock && lock->id)
+		free(lock->id);
+	if (lock)
+		free(lock);
+}
+
+int RK_acquire_wake_lock(struct rk_wake_lock *wake_lock) {
+	char *id = wake_lock->id;
+	debug("id=%s", id);
+
+	if (g_error)
+		return g_error;
+
+	int fd;
+	size_t len;
+	ssize_t ret;
+
+	fd = g_fds[0];
+
+	ret = write(fd, id, strlen(id));
+	if (ret < 0) {
+		return -errno;
+	}
+
+	return ret;
+}
+
+int RK_release_wake_lock(struct rk_wake_lock *wake_lock) {
+	char *id = wake_lock->id;
+	int fd;
+
+	debug("id=%s", id);
+
+	if (g_error)
+		return g_error;
+
+	fd = g_fds[1];
+
+	ssize_t len = write(fd, id, strlen(id));
+	if (len < 0) {
+		return -errno;
+	}
+	return len;
+}
+
+static int exec(const char *cmd, char *buf, const size_t size) {
+	FILE *stream = NULL;
+	char tmp[1024];
+
+	if ((stream = popen(cmd,"r")) == NULL) {
+		return -1;
+	}
+
+	if (buf == NULL) {
+		pclose(stream);
+		return -2;
+	}
+
+	buf[0] = '\0';
+	while (fgets(tmp, sizeof(tmp) -1, stream)) {
+		if (strlen(buf) + strlen(tmp) >= size) {
+			pclose(stream);
+			return -3;
+		}
+		strcat(buf, tmp);
+	}
+	pclose(stream);
+
+	return 0;
+}
+
+int RK_wait_all_wake_lock_release(int timeout_ms) {
+    int cnt = timeout_ms / 10;
+	char result[1024];
+
+	while(cnt--) {
+		memset(result, 0, 1024);
+        exec("cat /sys/power/wake_lock", result, 1024);
+		if (strlen(result) <= 1) //换行符
+			break;
+        usleep(10*1000);
+        printf("## suspend waiting wake_lock: %s\n", result);
+	}
+	if (cnt == 0) {
+        printf("wait suspend timeout, abort suspend\n");
+        printf("unreleased wake_lock: %s\n", result);
+		return -1;
+	}
+	return 0;
+}
+

+ 21 - 0
Modules/eq_process/Rk_wake_lock.h

@@ -0,0 +1,21 @@
+#ifndef RK_WAKE_LOCK_H
+#define RK_WAKE_LOCK_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct rk_wake_lock;
+struct rk_wake_lock* RK_wake_lock_new(const char *id);//the id must be unique
+void RK_wake_lock_delete(struct rk_wake_lock* lock);
+
+int RK_acquire_wake_lock(struct rk_wake_lock* lock);
+int RK_release_wake_lock(struct rk_wake_lock* lock);
+int RK_wait_all_wake_lock_release(int timeout_ms);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+

+ 20 - 0
Modules/eq_process/S97_EQ_init

@@ -0,0 +1,20 @@
+#!/bin/sh
+#
+# Start 3308 linux service....
+#
+
+case "$1" in
+	start)
+		# ueventd
+		/usr/bin/eq_drc_process &
+		;;
+	stop)
+		printf "stop eq_drc_process finished"
+        ;;
+	*)
+        echo "Usage: $0 {start|stop}"
+        exit 1
+        ;;
+esac
+sleep 1
+exit 0

+ 739 - 0
Modules/eq_process/main.c

@@ -0,0 +1,739 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <math.h>
+#include <pthread.h>
+#include <stdbool.h>
+
+#include <alsa/asoundlib.h>
+//#include <sys/time.h>
+//#include <sys/socket.h>
+//#include <sys/un.h>
+#include <hiredis/hiredis.h>
+#include <cjson/cJSON.h>
+#include <iniparser/iniparser.h>
+
+#define SAMPLE_RATE 48000
+#define CHANNEL 2
+#define REC_DEVICE_NAME "fake_record"
+#define WRITE_DEVICE_NAME "fake_play"
+//#define WRITE_DEVICE_NAME "default"
+#define JACK_DEVICE_NAME "fake_jack"
+#define READ_FRAME  1024    //(768)
+#define PERIOD_SIZE (1024)  //(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"
+// #define volume_temp_channel "volume-temp-channel"
+#define VOL_CONF    "/oem/etc/volctrl.conf"
+#define unix_socket_path "/tmp/redis.sock"
+
+/*
+ * 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
+#define AULEVEL_MIN    -96.0
+#define AULEVEL_MAX      0.0
+
+//current session
+#define IDLE        0
+#define SIP         1
+#define BROADCAST   2
+#define MULTICAST   3
+#define ONVIF       4
+
+typedef struct _vumeter_play {
+	int16_t *ch1_sampv;
+    int16_t *ch2_sampv;
+    size_t au_sampc;
+	double ch1_avg_play;
+	double ch2_avg_play;
+} vumeter_play;
+
+typedef struct {
+    redisContext *context;
+    const char *socket_path;
+    time_t last_activity;
+} redis_client_t;
+
+static bool set_volume = false;
+static int volume = 100;
+static int en_threshold = false;
+static int vol_threshold;
+static int current_sess = IDLE;
+static int ctrl_sess = IDLE;
+static int sip_active = false;
+static int mc_active = false;
+static int onvif_active = false;
+static int bc_active = false;
+
+static bool DEBUG = false;
+
+//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);
+
+redis_client_t* create_redis_client(const char *socket_path) {
+    redis_client_t *client = (redis_client_t *) 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(redis_client_t *client, const char *command) {
+    if (ensure_connected(client) == 0) {
+        redisReply *reply = (redisReply *) redisCommand(client->context, command);
+        if (reply) {
+            // 处理回复
+            freeReplyObject(reply);
+        }
+    }
+}
+
+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)
+{
+    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(&params);
+    snd_pcm_sw_params_malloc(&params);
+    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;
+}
+
+//修改当前音量
+void *control_volume(void *)
+{
+    char cmd[64];
+    set_volume = true;
+    volume -= 10;
+    usleep(1000*1000);
+    set_volume = false;
+    return NULL;
+}
+
+void get_volume_threshold()
+{
+    dictionary  *   ini ;
+	ini = iniparser_load(VOL_CONF);
+	
+    if (ini==NULL) {
+        fprintf(stderr, "cannot parse file: %s\n", VOL_CONF);
+        return;
+    }
+    en_threshold = iniparser_getboolean(ini, "volume:enable_threshold", false);
+	vol_threshold = iniparser_getint(ini, "volume:volume_threshold", -15);
+	iniparser_freedict(ini);
+}
+
+/**
+ * Generic routine to calculate RMS (Root-Mean-Square) from
+ * a set of signed 16-bit values
+ *
+ * \verbatim
+
+	     .---------------
+	     |   N-1
+	     |  ----.
+	     |  \
+	     |   \        2
+	     |    |   s[n]
+	     |   /
+	     |  /
+	 _   |  ----'
+	  \  |   n=0
+	   \ |  ------------
+	    \|       N
+
+   \endverbatim
+ *
+ * @param data Array of signed 16-bit values
+ * @param len  Number of values
+ *
+ * @return RMS value from 0 to 32768
+ */
+static double calc_rms_s16(const int16_t *data, size_t len)
+{
+	int64_t sum = 0;
+	size_t i;
+
+	if (!data || !len)
+		return .0;
+
+	for (i = 0; i < len; i++) {
+		sum += data[i] * data[i];
+	}
+
+	return sqrt(sum / (double)len);
+}
+
+double aout_Aulevel_dbov(const int16_t *sampv, size_t sampc)
+{
+    static const double peak_s16 = 32767.0;
+	double rms, dbov;
+
+	if (!sampv || !sampc)
+		return 0;
+
+	rms = calc_rms_s16(sampv, sampc) / peak_s16;
+
+	dbov = 20 * log10(rms);
+
+	if (dbov < AULEVEL_MIN)
+		dbov = AULEVEL_MIN;
+	else if (dbov > AULEVEL_MAX)
+		dbov = AULEVEL_MAX;
+
+	return dbov;
+}
+
+static void *vumeter_decode(void *arg)
+{
+    char redisCmd[128];
+    int set_idle = false;
+    vumeter_play *vu_p = (vumeter_play *) arg;
+    redis_client_t *redisClient = create_redis_client(unix_socket_path);
+
+    usleep(100*1000);
+    while(1)
+    {
+        usleep(500*1000);
+        if(sip_active || mc_active || onvif_active || bc_active)
+        {
+            vu_p->ch1_avg_play = aout_Aulevel_dbov(vu_p->ch1_sampv, vu_p->au_sampc);
+            sprintf(redisCmd, "HSet volume audio_out_ch1 %d", (int) vu_p->ch1_avg_play);
+            redis_command_safe(redisClient, redisCmd);
+            vu_p->ch2_avg_play = aout_Aulevel_dbov(vu_p->ch2_sampv, vu_p->au_sampc);
+            sprintf(redisCmd, "HSet volume audio_out_ch2 %d", (int) vu_p->ch2_avg_play);
+            redis_command_safe(redisClient, redisCmd);
+            set_idle = false;
+
+            if(DEBUG) printf("vol1: %f, vol2: %f\n", vu_p->ch1_avg_play, vu_p->ch2_avg_play);
+        }
+        else if(!set_idle)
+        {
+            sprintf(redisCmd, "HSet volume audio_out_ch1 %d", (int) AULEVEL_MIN);
+            redis_command_safe(redisClient, redisCmd);
+            sprintf(redisCmd, "HSet volume audio_out_ch2 %d", (int) AULEVEL_MIN);
+            redis_command_safe(redisClient, redisCmd);
+            set_idle = true;
+        }
+    }
+
+    return NULL;
+}
+
+//播放状态监控
+void ProcessReply( char * pReplyStr )
+{
+    cJSON *pJson = NULL;
+
+    if(DEBUG) printf( "Msg [%s]\n", pReplyStr );
+    pJson =  cJSON_Parse(pReplyStr);
+    if ( pJson ) {
+        if(strcmp(cJSON_GetObjectItem(pJson, "name")->valuestring, "SIP") == 0)
+        {
+            if(strcmp(cJSON_GetObjectItem(pJson, "action")->valuestring, "on") == 0)
+            {
+                get_volume_threshold();
+                current_sess = SIP;
+                sip_active = true;
+            }
+            else if(strcmp(cJSON_GetObjectItem(pJson, "action")->valuestring, "off") == 0)
+            {
+                if(ctrl_sess == SIP)
+                {
+                    volume = 100;
+                    ctrl_sess = IDLE;
+                }
+                sip_active = false;
+            }
+        }
+        else if(strcmp(cJSON_GetObjectItem(pJson, "name")->valuestring, "BROADCAST") == 0)
+        {
+            if(strcmp(cJSON_GetObjectItem(pJson, "action")->valuestring, "on") == 0)
+            {
+                get_volume_threshold();
+                current_sess = BROADCAST;
+                bc_active = true;
+            }
+            else if(strcmp(cJSON_GetObjectItem(pJson, "action")->valuestring, "off") == 0)
+            {
+                if(ctrl_sess == BROADCAST)
+                {
+                    volume = 100;
+                    ctrl_sess = IDLE;
+                }
+                bc_active = false;
+            }
+        }
+        else if(strcmp(cJSON_GetObjectItem(pJson, "name")->valuestring, "MULTICAST") == 0)
+        {
+            if(strcmp(cJSON_GetObjectItem(pJson, "action")->valuestring, "on") == 0)
+            {
+                get_volume_threshold();
+                current_sess = MULTICAST;
+                mc_active = true;
+            }
+            else if(strcmp(cJSON_GetObjectItem(pJson, "action")->valuestring, "off") == 0)
+            {
+                if(ctrl_sess == MULTICAST)
+                {
+                    volume = 100;
+                    ctrl_sess = IDLE;
+                }
+                mc_active = false;
+            }
+        }
+        else if(strcmp(cJSON_GetObjectItem(pJson, "name")->valuestring, "ONVIF") == 0)
+        {
+            if(strcmp(cJSON_GetObjectItem(pJson, "action")->valuestring, "on") == 0)
+            {
+                get_volume_threshold();
+                current_sess = ONVIF;
+                onvif_active = true;
+            }
+            else if(strcmp(cJSON_GetObjectItem(pJson, "action")->valuestring, "off") == 0)
+            {
+                if(ctrl_sess == ONVIF)
+                {
+                    volume = 100;
+                    ctrl_sess = IDLE;
+                }
+                onvif_active = false;
+            }
+        }
+    }
+    if(pJson != NULL) cJSON_Delete(pJson);
+}
+
+void *service_status_listen(void *arg)
+{
+    // redisContext * pContext = redisConnect( "127.0.0.1", 6379 );
+    redisContext * pContext = redisConnectUnix(unix_socket_path);
+
+    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<redisReply*>(replyPtr);
+    freeReplyObject( pReply );
+    while ( redisGetReply( pContext, (void **)&pReply ) == REDIS_OK )
+    {
+        if ( pReply->elements == 3 )
+        {
+            redisReply * pSubReply = pReply->element[2];
+            ProcessReply( pSubReply->str );
+        }
+        if(pReply != NULL) freeReplyObject( pReply );
+    }
+
+    redisFree( pContext );
+    return NULL;
+}
+
+void check_volume(int16_t *buffer, int count, vumeter_play *vu)
+{
+    int i;
+    pthread_t thread;
+    if(vu->ch1_avg_play > vol_threshold || vu->ch2_avg_play > vol_threshold)
+    {
+        for(i=0; i<count; i++)
+        {
+            buffer[i*2] = 0x00; //ch1[i]*0.35;
+            buffer[i*2+1] = 0x00; //ch2[i]*0.35;
+        }
+        if(!set_volume)
+        {
+            ctrl_sess = current_sess;
+            pthread_create(&thread, NULL, control_volume, NULL);
+            pthread_detach(thread);
+        }
+    }
+}
+
+static float get_volume(int vol)
+{
+	float v = vol / 100.f;
+	if (v < 0.f)
+		v = 0.f;
+	else if (v > 1.f)
+		v = 1.f;
+
+	return v;
+}
+
+void vol_uint16(int16_t *data, size_t n)
+{
+	size_t i;
+	for (i = 0; i < n; i++)
+    {
+        data[i*2] = (int16_t) (data[i*2] * get_volume(volume));
+        data[i*2+1] = (int16_t) (data[i*2+1] * get_volume(volume));
+    }
+}
+
+
+int main(int argc, char *argv[])
+{
+    snd_pcm_t *capture_handle;
+    snd_pcm_t *write_handle;
+    vumeter_play *vu = ( vumeter_play *) malloc (sizeof (*vu));
+    int err, i;
+    int16_t buffer[READ_FRAME * 2];
+    unsigned int sampleRate;
+    unsigned int channels;
+    pthread_t service_status_listen_thread, thread;
+    // pthread_t volume_temp_value_listen_thread;
+
+    if(argc == 2 && strcmp(argv[1], "debug") == 0)
+        DEBUG = true;
+
+repeat:
+    //capture_handle = NULL;
+    write_handle = NULL;
+    err = 0;
+    memset(buffer, 0, sizeof(buffer));
+    sampleRate = SAMPLE_RATE;
+    channels = CHANNEL;
+
+    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);
+    vu->ch1_sampv = (int16_t *) malloc(READ_FRAME*2*sizeof(int16_t));
+    vu->ch2_sampv = (int16_t *) malloc(READ_FRAME*2*sizeof(int16_t));
+    vu->au_sampc = READ_FRAME;
+
+    //RK_acquire_wake_lock(wake_lock);
+    pthread_create(&thread, NULL, vumeter_decode, vu);
+    pthread_detach(thread);
+
+    pthread_create(&service_status_listen_thread, NULL, service_status_listen, NULL);
+    pthread_detach(service_status_listen_thread);
+
+    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(en_threshold)
+        {
+            vol_uint16(buffer, READ_FRAME);
+            check_volume(buffer, READ_FRAME, vu);
+        }
+
+        for(i=0; i<READ_FRAME; i++)
+        {
+            vu->ch1_sampv[i] = buffer[i*2];
+            vu->ch2_sampv[i] = buffer[i*2+1];
+        }
+
+        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);
+		}
+    }
+
+error:
+    if (capture_handle)
+        snd_pcm_close(capture_handle);
+    if (write_handle)
+        snd_pcm_close(write_handle);
+
+    return 0;
+}

+ 744 - 0
Modules/eq_process/main.cpp

@@ -0,0 +1,744 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <iostream>
+#include <vector>
+
+#include <alsa/asoundlib.h>
+#include <sys/time.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#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(&params);
+    snd_pcm_sw_params_malloc(&params);
+    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<redisReply*>(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<redisReply*>(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;
+}

+ 220 - 0
Modules/onvif/test-onvif-backchannel.c

@@ -0,0 +1,220 @@
+/* GStreamer
+ * Copyright (C) 2017 Sebastian Dröge <sebastian@centricular.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include <gst/gst.h>
+#include <gst/rtsp-server/rtsp-onvif-server.h>
+
+#include <string.h>
+#include <stdio.h>
+#include "iniparser.h"
+
+#define CONF "/oem/etc/config.xml"
+#define SPK_CONF    "/etc/speaker.conf"
+#define MAX_LINE_LENGTH 256
+
+struct SPEAKER_CONF
+{
+    char hw_version[16];
+    char dev_type[32];
+    char enable_mic[8];
+    char media_stream[8];
+};
+
+
+void find_tag_in_file(const char* file_path, const char* tag, char *value);
+void confParse(struct SPEAKER_CONF *conf);
+
+
+void confParse(struct SPEAKER_CONF *conf)
+{
+	dictionary * ini ;
+	ini = iniparser_load(SPK_CONF);
+	
+    if (ini==NULL) {
+        fprintf(stderr, "cannot parse file: %s\n", SPK_CONF);
+        exit(-1);
+    }
+	strcpy(conf->dev_type, iniparser_getstring(ini, "system:ui_model", ""));
+	strcpy(conf->hw_version, iniparser_getstring(ini, "system:hard_version", ""));
+	strcpy(conf->enable_mic, iniparser_getstring(ini, "onvif:enable_mic", "no"));
+	strcpy(conf->media_stream, iniparser_getstring(ini, "onvif:media_stream", "main"));
+    
+	iniparser_freedict(ini);
+}
+
+static gchar *htdigest_path = NULL;
+static gchar *realm = NULL;
+
+static GOptionEntry entries[] = {
+  {"htdigest-path", 'h', 0, G_OPTION_ARG_STRING, &htdigest_path,
+      "Path to an htdigest file to parse (default: None)", "PATH"},
+  {"realm", 'r', 0, G_OPTION_ARG_STRING, &realm,
+      "Authentication realm (default: None)", "REALM"},
+  {NULL}
+};
+
+int
+main (int argc, char *argv[])
+{
+  GMainLoop *loop;
+  GstRTSPServer *server;
+  GstRTSPMountPoints *mounts;
+  GstRTSPMediaFactory *factory;
+  GstRTSPAuth *auth;
+  GstRTSPToken *token;
+  GOptionContext *optctx;
+  GError *error = NULL;
+  struct SPEAKER_CONF conf;
+  confParse(&conf);;
+  char launchstr[512];
+
+  char username[64] = { 0 };
+  char password[64] = { 0 };
+  find_tag_in_file(CONF, "auth_user", username);
+  find_tag_in_file(CONF, "auth_pass", password);
+
+  if (strlen(username) == 0 || strlen(password) == 0) {
+	  g_print ("Please username or password in config.xml\n");
+	  return -1;
+  }
+
+  //putenv("GST_DEBUG=4");
+  gst_init (&argc, &argv);
+
+  optctx = g_option_context_new (NULL);
+  g_option_context_add_main_entries (optctx, entries, NULL);
+  g_option_context_add_group (optctx, gst_init_get_option_group ());
+  if (!g_option_context_parse (optctx, &argc, &argv, &error)) {
+    g_printerr ("Error parsing options: %s\n", error->message);
+    g_option_context_free (optctx);
+    g_clear_error (&error);
+    return -1;
+  }
+  g_option_context_free (optctx);
+
+  loop = g_main_loop_new (NULL, FALSE);
+
+  /* create a server instance */
+  server = gst_rtsp_onvif_server_new ();
+
+  /* get the mount points for this server, every server has a default object
+   * that be used to map uri mount points to media factories */
+  mounts = gst_rtsp_server_get_mount_points (server);
+
+  /* make a media factory for a test stream. The default media factory can use
+   * gst-launch syntax to create pipelines.
+   * any launch line works as long as it contains elements named pay%d. Each
+   * element with pay%d names will be a stream */
+  factory = gst_rtsp_onvif_media_factory_new ();
+  //! video/x-raw, format=(string)RGB, width=(int)640, height=(int)480
+  if(strcmp(conf.dev_type, "Ei-V05") == 0 || strcmp(conf.dev_type, "SQ10-C") == 0 || strcmp(conf.dev_type, "SQ10-V") == 0)
+  {
+    if(strcmp(conf.media_stream, "main") == 0)
+      strcpy(launchstr, "( rtspsrc protocols=tcp latency=100 user-agent='Zycoo rtsp client' location=rtsp://10.231.132.139:554/stream1 ! rtph264depay name=d d. ! queue ! rtph264pay config-interval=1 pt=96 name=pay0 ");
+    else if(strcmp(conf.media_stream, "sub") == 0)
+      strcpy(launchstr, "( rtspsrc protocols=tcp latency=100 user-agent='Zycoo rtsp client' location=rtsp://10.231.132.139:554/stream2 ! rtph264depay name=d d. ! queue ! rtph264pay config-interval=1 pt=96 name=pay0 ");
+  }
+  else
+  {
+    strcpy(launchstr, "( filesrc loop=true location=\"/usr/share/onvif/speaker.h264\" ! video/x-h264 ! h264parse ! rtph264pay pt=96 config-interval=5 name=pay0 ");
+  }
+
+  if(strcmp(conf.enable_mic, "yes") == 0)
+  {
+    strcat(launchstr, "alsasrc device=plug:mixmic ! queue ! audioconvert ! audioresample ! mulawenc ! rtppcmupay name=pay1 )");
+  }
+  else
+  {
+    strcat(launchstr, " )");
+  }
+  gst_rtsp_media_factory_set_launch (factory,launchstr); 
+  
+  gst_rtsp_onvif_media_factory_set_backchannel_launch
+      (GST_RTSP_ONVIF_MEDIA_FACTORY (factory),
+      "( capsfilter caps=\"application/x-rtp, media=audio, payload=0, clock-rate=8000, encoding-name=PCMU, channels=1\" name=depay_backchannel ! rtppcmudepay ! mulawdec ! identity drop-probability=0.01 sync=true ! audioconvert ! audioresample ! alsasink async=false sync=false )");
+      //"( capsfilter caps=\"application/x-rtp, media=audio, payload=8, clock-rate=8000, encoding-name=PCMA, channels=1\" name=depay_backchannel ! rtpjitterbuffer latency=80 ! rtppcmadepay ! alawdec ! identity drop-probability=0.01 sync=true ! audioconvert ! audioresample ! alsasink async=false sync=false )");
+  gst_rtsp_media_factory_set_shared (factory, FALSE);
+  gst_rtsp_media_factory_set_media_gtype (factory, GST_TYPE_RTSP_ONVIF_MEDIA);
+
+  /* attach the test factory to the /test url */
+  gst_rtsp_mount_points_add_factory (mounts, "/MainStream", factory);
+
+  /* allow admin to access this resource */
+  gst_rtsp_media_factory_add_role (factory, username,
+      GST_RTSP_PERM_MEDIA_FACTORY_ACCESS, G_TYPE_BOOLEAN, TRUE,
+      GST_RTSP_PERM_MEDIA_FACTORY_CONSTRUCT, G_TYPE_BOOLEAN, TRUE, NULL);
+
+  /* don't need the ref to the mapper anymore */
+  g_object_unref (mounts);
+
+  /* make a new authentication manager */
+  auth = gst_rtsp_auth_new ();
+  gst_rtsp_auth_set_supported_methods (auth, GST_RTSP_AUTH_DIGEST);
+
+
+  if (realm)
+    gst_rtsp_auth_set_realm (auth, realm);
+  /* make admin token */
+  token =
+      gst_rtsp_token_new (GST_RTSP_TOKEN_MEDIA_FACTORY_ROLE, G_TYPE_STRING,
+      username, NULL);
+  gst_rtsp_auth_add_digest (auth, username, password, token);
+  gst_rtsp_token_unref (token);
+
+  /* set as the server authentication manager */
+  gst_rtsp_server_set_auth (server, auth);
+  g_object_unref (auth);
+
+  /* attach the server to the default maincontext */
+  gst_rtsp_server_attach (server, NULL);
+
+  /* start serving */
+  g_print ("stream ready at rtsp://0.0.0.0:554/MainStream\n");
+  g_main_loop_run (loop);
+
+  return 0;
+}
+
+void find_tag_in_file(const char* file_path, const char* tag, char *value) {
+    FILE* file = fopen(file_path, "r");
+    if (file == NULL) {
+        g_print ("Failed to open file: %s\n", file_path);
+        return;
+    }
+
+    char line[MAX_LINE_LENGTH];
+    char start_tag[MAX_LINE_LENGTH] = { 0 };
+    char end_tag[MAX_LINE_LENGTH] = { 0 };
+
+    sprintf(start_tag, "<%s>", tag);
+    sprintf(end_tag, "</%s>", tag);
+
+    while (fgets(line, MAX_LINE_LENGTH, file)) {
+        if (strstr(line, start_tag) && strstr(line, end_tag)) {
+            // Extract the data between the start and end tags.
+            char* start = strstr(line, start_tag) + strlen(start_tag);
+            char* end = strstr(line, end_tag);
+            *end = '\0';  // Null-terminate the string at the end of the data.
+            strcpy(value, start);
+            break;
+        }
+    }
+
+    fclose(file);
+}

+ 21 - 0
Modules/output_control/Makefile

@@ -0,0 +1,21 @@
+TARGET = output_control
+Dir2store = /opt/Rockchip/external/X10/etc/scripts
+objects = *.o
+CFLAGS = -lpthread -lhiredis -lm -liniparser -lcjson
+
+${TARGET}:$(objects)
+	${CC} -o $@ $(objects) $(CFLAGS)
+
+%.o:%.c
+	${CC} -c $<
+
+.PHONY:clean install uninstall
+
+clean:
+	rm -f *.o ${TARGET}
+
+install:
+	cp -f ${TARGET} ${Dir2store}
+
+uninstall:
+	rm -f ${Dir2store}/${TARGET}

+ 376 - 0
Modules/output_control/main.c

@@ -0,0 +1,376 @@
+#include <sys/poll.h>
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <assert.h>
+#include <time.h>
+#include <pthread.h>
+#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    32
+//GPIO_STATUS
+#define GPIO_Off     0
+#define GPIO_On      1
+#define GPIO_Fast    2
+#define GPIO_Slow    3
+#define GPIO_Simultaneously 4
+#define GPIO_Alternately    5
+
+#define SPK_CONF    "/etc/speaker.conf"
+#define unix_socket_path "/tmp/redis.sock"
+#define VAR_IP      "${ip}"
+#define VAR_MAC     "${mac}"
+
+static int DEBUG = FALSE;
+static int GPIO67_STATUS = GPIO_Off;
+static int GPIO135_STATUS = GPIO_Off;
+
+
+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;
+}
+
+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,MAX_PIPE_BUFSIZE,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,MAX_PIPE_BUFSIZE,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 --connect-timeout 5 '%s' 2>/dev/null &",url);
+    if(DEBUG)
+        printf( "Command: %s\n", cmd);
+    system(cmd);
+}
+
+int get_gpio_type(char *output_type){
+
+    if(strcmp(output_type, "On") == 0)
+    {
+        return GPIO_On;
+    }
+    else if(strcmp(output_type, "FastFlashing") == 0)
+    {
+        return GPIO_Fast;
+    }
+    else if(strcmp(output_type, "SlowFlashing") == 0)
+    {
+        return GPIO_Slow;
+    }
+    else if(strcmp(output_type, "Simultaneously") == 0)
+    {
+        return GPIO_Simultaneously;
+    }
+    else if(strcmp(output_type, "Alternately") == 0)
+    {
+        return GPIO_Alternately;
+    }
+    
+
+    return GPIO_Off;
+}
+
+void gpio_on_trigger()
+{
+    char enable[8],url[256],ipaddr[16],macaddr[16],cmd[320];
+    GetCmdValue(SPK_CONF, "relay_action_url:on_enable", enable, sizeof(enable));
+    if(strcmp(enable,"yes") == 0)
+    {
+        GetCmdValue(SPK_CONF, "relay_action_url:on_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));
+        }
+        action_url(url);
+    }
+}
+
+void gpio_off_trigger()
+{
+    char enable[8],url[256],ipaddr[16],macaddr[16],cmd[320];
+    GetCmdValue(SPK_CONF, "relay_action_url:off_enable", enable, sizeof(enable));
+    if(strcmp(enable,"yes") == 0)
+    {
+        GetCmdValue(SPK_CONF, "relay_action_url:off_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));
+        }
+        action_url(url);
+    }
+}
+
+//gpio控制指令处理
+void ProcessReply( redisReply * pReply )
+{
+    cJSON *pJson = NULL;
+    redisReply * pSubReply = NULL;
+
+    if ( pReply->elements == 2 )
+    {
+        pSubReply = pReply->element[1];
+        if(DEBUG)
+            printf( "Msg [%s]\n", pSubReply->str );
+        pJson =  cJSON_Parse(pSubReply->str);
+        if ( pJson ) {
+            if(strcmp(cJSON_GetObjectItem(pJson, "id")->valuestring, "gpio67") == 0 || strcmp(cJSON_GetObjectItem(pJson, "id")->valuestring, "gpio135") == 0)
+            {
+                GPIO67_STATUS = get_gpio_type(cJSON_GetObjectItem(pJson, "type")->valuestring);
+                if(GPIO67_STATUS == GPIO_Off)
+                {
+                    gpio_off_trigger();
+                }
+                else
+                {
+                    gpio_on_trigger();
+                }
+                if(DEBUG)
+                    printf("RLEAY: %s\n",cJSON_GetObjectItem(pJson, "type")->valuestring);
+            }
+            // else if(strcmp(cJSON_GetObjectItem(pJson, "id")->valuestring, "gpio135") == 0)
+            // {
+            //     GPIO135_STATUS = get_gpio_type(cJSON_GetObjectItem(pJson, "type")->valuestring);
+            //     if(GPIO135_STATUS == GPIO_Off)
+            //     {
+            //         gpio_off_trigger();
+            //     }
+            //     else
+            //     {
+            //         gpio_on_trigger();
+            //     }
+                
+            //     if(DEBUG)
+            //         printf("gpio135: %s\n",cJSON_GetObjectItem(pJson, "type")->valuestring);
+            // }
+        }else{
+            printf( "parse failed!\n");
+        }
+        if(pJson != NULL) cJSON_Delete(pJson);
+    }
+}
+
+/*
+* 接收控制指令.
+*/
+void *get_gpio_control()
+{
+    redisContext * pContext = redisConnectUnix(unix_socket_path);
+
+    if ( NULL == pContext || pContext->err == 1 )
+    {
+        printf( "%s\n", pContext->errstr );
+        exit( -1 );
+    }
+
+    char * pKey = "output-channel";
+    redisReply * pReply;
+    while(1){
+        pReply = NULL;
+        pReply = redisCommand( pContext, "BRPOP %s 60", pKey );
+		if(pReply != NULL && pReply->type == REDIS_REPLY_ARRAY){
+			ProcessReply( pReply );
+		}
+		if(pReply != NULL) freeReplyObject( pReply );
+        usleep(500*1000);
+    }
+    redisFree( pContext );
+}
+
+//gpio状态设置
+void *gpio_status()
+{
+    int gpioFlashTime = 0,gpioFlashTag1 = 0,gpioFlashTag2 = 0;
+    while(1)
+    {
+        usleep(10 * 1000);
+        /*	gpio flash controller	*/
+        gpioFlashTime++;
+
+        if(gpioFlashTime == 47 || gpioFlashTime == 143){
+            // if(GPIO135_STATUS == GPIO_On)
+            //     system("echo 0 > /sys/class/gpio/gpio134/value;echo 0 > /sys/class/gpio/gpio135/value");
+            // else if(GPIO135_STATUS == GPIO_Off)
+            //     system("echo 1 > /sys/class/gpio/gpio134/value;echo 1 > /sys/class/gpio/gpio135/value");
+            if(GPIO67_STATUS == GPIO_On)
+                system("echo 1 > /sys/class/gpio/gpio67/value");
+            else if(GPIO67_STATUS == GPIO_Off)
+                system("echo 0 > /sys/class/gpio/gpio67/value");
+        }
+
+        if(gpioFlashTime % 39 == 0){
+            // if(GPIO135_STATUS == GPIO_Simultaneously){
+            //     gpioFlashTag1 = !gpioFlashTag1;
+            //     if(gpioFlashTag1){
+            //         system("echo 0 > /sys/class/gpio/gpio134/value;echo 0 > /sys/class/gpio/gpio135/value");
+            //     }else{
+            //         system("echo 1 > /sys/class/gpio/gpio134/value;echo 1 > /sys/class/gpio/gpio135/value");
+            //     }
+            // }
+            // if(GPIO135_STATUS == GPIO_Alternately){
+            //     gpioFlashTag1 = !gpioFlashTag1;
+            //     if(gpioFlashTag1){
+            //         system("echo 1 > /sys/class/gpio/gpio134/value;echo 0 > /sys/class/gpio/gpio135/value");
+            //     }else{
+            //         system("echo 0 > /sys/class/gpio/gpio134/value;echo 1 > /sys/class/gpio/gpio135/value");
+            //     }
+            // }
+            if(GPIO67_STATUS == GPIO_Fast){
+                gpioFlashTag2 = !gpioFlashTag2;
+                if(gpioFlashTag2){
+                    system("echo 0 > /sys/class/gpio/gpio67/value");
+                }else{
+                    system("echo 1 > /sys/class/gpio/gpio67/value");
+                }
+            }
+        }
+
+        if(gpioFlashTime % 99 == 0){
+            // if(GPIO135_STATUS == GPIO_Slow){
+            //     gpioFlashTag1 = !gpioFlashTag1;
+            //     if(gpioFlashTag1){
+            //         system("echo 0 > /sys/class/gpio/gpio134/value;echo 0 > /sys/class/gpio/gpio135/value");
+            //     }else{
+            //         system("echo 1 > /sys/class/gpio/gpio134/value;echo 1 > /sys/class/gpio/gpio135/value");
+            //     }
+            // }
+            if(GPIO67_STATUS == GPIO_Slow){
+                gpioFlashTag2 = !gpioFlashTag2;
+                if(gpioFlashTag2){
+                    system("echo 0 > /sys/class/gpio/gpio67/value");
+                }else{
+                    system("echo 1 > /sys/class/gpio/gpio67/value");
+                }
+            }
+        }
+            
+        /*	restart the led flash loop	*/
+        if(gpioFlashTime == 200)
+            gpioFlashTime = 0;
+    }
+}
+
+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;
+
+    //启动线程控制gpio状态
+    ret_thrd2 = pthread_create(&thread2, NULL, gpio_status, NULL);
+    if (ret_thrd2 != 0) {
+        printf("create thread2 gpio_status failed\n");
+        return 0;
+    }
+
+    //启动线程接收gpio控制指令
+    get_gpio_control();
+}

+ 21 - 0
Modules/play_ip/Makefile

@@ -0,0 +1,21 @@
+TARGET = play_ip
+Dir2store = /opt/Rockchip/external/X10/etc/scripts
+objects = *.o
+CFLAGS = -lhiredis -lm -L../../iniparser/iniparser-master -liniparser 
+
+${TARGET}:$(objects)
+	${CC} -o $@ $(objects) $(CFLAGS)
+
+%.o:%.c
+	${CC} -c main.c
+
+.PHONY:clean install uninstall
+
+clean:
+	rm -f *.o ${TARGET}
+
+install:
+	cp -f ${TARGET} ${Dir2store}
+
+uninstall:
+	rm -f ${Dir2store}/${TARGET}

+ 750 - 0
Modules/play_ip/cJSON.c

@@ -0,0 +1,750 @@
+/*
+  Copyright (c) 2009 Dave Gamble
+
+  Permission is hereby granted, free of charge, to any person obtaining a copy
+  of this software and associated documentation files (the "Software"), to deal
+  in the Software without restriction, including without limitation the rights
+  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+  copies of the Software, and to permit persons to whom the Software is
+  furnished to do so, subject to the following conditions:
+
+  The above copyright notice and this permission notice shall be included in
+  all copies or substantial portions of the Software.
+
+  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+  THE SOFTWARE.
+*/
+
+/* cJSON */
+/* JSON parser in C. */
+
+#include <string.h>
+#include <stdio.h>
+#include <math.h>
+#include <stdlib.h>
+#include <float.h>
+#include <limits.h>
+#include <ctype.h>
+#include "cJSON.h"
+
+static const char *ep;
+
+const char *cJSON_GetErrorPtr(void) {return ep;}
+
+static int cJSON_strcasecmp(const char *s1,const char *s2)
+{
+	if (!s1) return (s1==s2)?0:1;if (!s2) return 1;
+	for(; tolower(*s1) == tolower(*s2); ++s1, ++s2)	if(*s1 == 0)	return 0;
+	return tolower(*(const unsigned char *)s1) - tolower(*(const unsigned char *)s2);
+}
+
+static void *(*cJSON_malloc)(size_t sz) = malloc;
+static void (*cJSON_free)(void *ptr) = free;
+
+static char* cJSON_strdup(const char* str)
+{
+      size_t len;
+      char* copy;
+
+      len = strlen(str) + 1;
+      if (!(copy = (char*)cJSON_malloc(len))) return 0;
+      memcpy(copy,str,len);
+      return copy;
+}
+
+void cJSON_InitHooks(cJSON_Hooks* hooks)
+{
+    if (!hooks) { /* Reset hooks */
+        cJSON_malloc = malloc;
+        cJSON_free = free;
+        return;
+    }
+
+	cJSON_malloc = (hooks->malloc_fn)?hooks->malloc_fn:malloc;
+	cJSON_free	 = (hooks->free_fn)?hooks->free_fn:free;
+}
+
+/* Internal constructor. */
+static cJSON *cJSON_New_Item(void)
+{
+	cJSON* node = (cJSON*)cJSON_malloc(sizeof(cJSON));
+	if (node) memset(node,0,sizeof(cJSON));
+	return node;
+}
+
+/* Delete a cJSON structure. */
+void cJSON_Delete(cJSON *c)
+{
+	cJSON *next;
+	while (c)
+	{
+		next=c->next;
+		if (!(c->type&cJSON_IsReference) && c->child) cJSON_Delete(c->child);
+		if (!(c->type&cJSON_IsReference) && c->valuestring) cJSON_free(c->valuestring);
+		if (!(c->type&cJSON_StringIsConst) && c->string) cJSON_free(c->string);
+		cJSON_free(c);
+		c=next;
+	}
+}
+
+/* Parse the input text to generate a number, and populate the result into item. */
+static const char *parse_number(cJSON *item,const char *num)
+{
+	double n=0,sign=1,scale=0;int subscale=0,signsubscale=1;
+
+	if (*num=='-') sign=-1,num++;	/* Has sign? */
+	if (*num=='0') num++;			/* is zero */
+	if (*num>='1' && *num<='9')	do	n=(n*10.0)+(*num++ -'0');	while (*num>='0' && *num<='9');	/* Number? */
+	if (*num=='.' && num[1]>='0' && num[1]<='9') {num++;		do	n=(n*10.0)+(*num++ -'0'),scale--; while (*num>='0' && *num<='9');}	/* Fractional part? */
+	if (*num=='e' || *num=='E')		/* Exponent? */
+	{	num++;if (*num=='+') num++;	else if (*num=='-') signsubscale=-1,num++;		/* With sign? */
+		while (*num>='0' && *num<='9') subscale=(subscale*10)+(*num++ - '0');	/* Number? */
+	}
+
+	n=sign*n*pow(10.0,(scale+subscale*signsubscale));	/* number = +/- number.fraction * 10^+/- exponent */
+	
+	item->valuedouble=n;
+	item->valueint=(int)n;
+	item->type=cJSON_Number;
+	return num;
+}
+
+static int pow2gt (int x)	{	--x;	x|=x>>1;	x|=x>>2;	x|=x>>4;	x|=x>>8;	x|=x>>16;	return x+1;	}
+
+typedef struct {char *buffer; int length; int offset; } printbuffer;
+
+static char* ensure(printbuffer *p,int needed)
+{
+	char *newbuffer;int newsize;
+	if (!p || !p->buffer) return 0;
+	needed+=p->offset;
+	if (needed<=p->length) return p->buffer+p->offset;
+
+	newsize=pow2gt(needed);
+	newbuffer=(char*)cJSON_malloc(newsize);
+	if (!newbuffer) {cJSON_free(p->buffer);p->length=0,p->buffer=0;return 0;}
+	if (newbuffer) memcpy(newbuffer,p->buffer,p->length);
+	cJSON_free(p->buffer);
+	p->length=newsize;
+	p->buffer=newbuffer;
+	return newbuffer+p->offset;
+}
+
+static int update(printbuffer *p)
+{
+	char *str;
+	if (!p || !p->buffer) return 0;
+	str=p->buffer+p->offset;
+	return p->offset+strlen(str);
+}
+
+/* Render the number nicely from the given item into a string. */
+static char *print_number(cJSON *item,printbuffer *p)
+{
+	char *str=0;
+	double d=item->valuedouble;
+	if (d==0)
+	{
+		if (p)	str=ensure(p,2);
+		else	str=(char*)cJSON_malloc(2);	/* special case for 0. */
+		if (str) strcpy(str,"0");
+	}
+	else if (fabs(((double)item->valueint)-d)<=DBL_EPSILON && d<=INT_MAX && d>=INT_MIN)
+	{
+		if (p)	str=ensure(p,21);
+		else	str=(char*)cJSON_malloc(21);	/* 2^64+1 can be represented in 21 chars. */
+		if (str)	sprintf(str,"%d",item->valueint);
+	}
+	else
+	{
+		if (p)	str=ensure(p,64);
+		else	str=(char*)cJSON_malloc(64);	/* This is a nice tradeoff. */
+		if (str)
+		{
+			if (fabs(floor(d)-d)<=DBL_EPSILON && fabs(d)<1.0e60)sprintf(str,"%.0f",d);
+			else if (fabs(d)<1.0e-6 || fabs(d)>1.0e9)			sprintf(str,"%e",d);
+			else												sprintf(str,"%f",d);
+		}
+	}
+	return str;
+}
+
+static unsigned parse_hex4(const char *str)
+{
+	unsigned h=0;
+	if (*str>='0' && *str<='9') h+=(*str)-'0'; else if (*str>='A' && *str<='F') h+=10+(*str)-'A'; else if (*str>='a' && *str<='f') h+=10+(*str)-'a'; else return 0;
+	h=h<<4;str++;
+	if (*str>='0' && *str<='9') h+=(*str)-'0'; else if (*str>='A' && *str<='F') h+=10+(*str)-'A'; else if (*str>='a' && *str<='f') h+=10+(*str)-'a'; else return 0;
+	h=h<<4;str++;
+	if (*str>='0' && *str<='9') h+=(*str)-'0'; else if (*str>='A' && *str<='F') h+=10+(*str)-'A'; else if (*str>='a' && *str<='f') h+=10+(*str)-'a'; else return 0;
+	h=h<<4;str++;
+	if (*str>='0' && *str<='9') h+=(*str)-'0'; else if (*str>='A' && *str<='F') h+=10+(*str)-'A'; else if (*str>='a' && *str<='f') h+=10+(*str)-'a'; else return 0;
+	return h;
+}
+
+/* Parse the input text into an unescaped cstring, and populate item. */
+static const unsigned char firstByteMark[7] = { 0x00, 0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC };
+static const char *parse_string(cJSON *item,const char *str)
+{
+	const char *ptr=str+1;char *ptr2;char *out;int len=0;unsigned uc,uc2;
+	if (*str!='\"') {ep=str;return 0;}	/* not a string! */
+	
+	while (*ptr!='\"' && *ptr && ++len) if (*ptr++ == '\\') ptr++;	/* Skip escaped quotes. */
+	
+	out=(char*)cJSON_malloc(len+1);	/* This is how long we need for the string, roughly. */
+	if (!out) return 0;
+	
+	ptr=str+1;ptr2=out;
+	while (*ptr!='\"' && *ptr)
+	{
+		if (*ptr!='\\') *ptr2++=*ptr++;
+		else
+		{
+			ptr++;
+			switch (*ptr)
+			{
+				case 'b': *ptr2++='\b';	break;
+				case 'f': *ptr2++='\f';	break;
+				case 'n': *ptr2++='\n';	break;
+				case 'r': *ptr2++='\r';	break;
+				case 't': *ptr2++='\t';	break;
+				case 'u':	 /* transcode utf16 to utf8. */
+					uc=parse_hex4(ptr+1);ptr+=4;	/* get the unicode char. */
+
+					if ((uc>=0xDC00 && uc<=0xDFFF) || uc==0)	break;	/* check for invalid.	*/
+
+					if (uc>=0xD800 && uc<=0xDBFF)	/* UTF16 surrogate pairs.	*/
+					{
+						if (ptr[1]!='\\' || ptr[2]!='u')	break;	/* missing second-half of surrogate.	*/
+						uc2=parse_hex4(ptr+3);ptr+=6;
+						if (uc2<0xDC00 || uc2>0xDFFF)		break;	/* invalid second-half of surrogate.	*/
+						uc=0x10000 + (((uc&0x3FF)<<10) | (uc2&0x3FF));
+					}
+
+					len=4;if (uc<0x80) len=1;else if (uc<0x800) len=2;else if (uc<0x10000) len=3; ptr2+=len;
+					
+					switch (len) {
+						case 4: *--ptr2 =((uc | 0x80) & 0xBF); uc >>= 6;
+						case 3: *--ptr2 =((uc | 0x80) & 0xBF); uc >>= 6;
+						case 2: *--ptr2 =((uc | 0x80) & 0xBF); uc >>= 6;
+						case 1: *--ptr2 =(uc | firstByteMark[len]);
+					}
+					ptr2+=len;
+					break;
+				default:  *ptr2++=*ptr; break;
+			}
+			ptr++;
+		}
+	}
+	*ptr2=0;
+	if (*ptr=='\"') ptr++;
+	item->valuestring=out;
+	item->type=cJSON_String;
+	return ptr;
+}
+
+/* Render the cstring provided to an escaped version that can be printed. */
+static char *print_string_ptr(const char *str,printbuffer *p)
+{
+	const char *ptr;char *ptr2,*out;int len=0,flag=0;unsigned char token;
+	
+	for (ptr=str;*ptr;ptr++) flag|=((*ptr>0 && *ptr<32)||(*ptr=='\"')||(*ptr=='\\'))?1:0;
+	if (!flag)
+	{
+		len=ptr-str;
+		if (p) out=ensure(p,len+3);
+		else		out=(char*)cJSON_malloc(len+3);
+		if (!out) return 0;
+		ptr2=out;*ptr2++='\"';
+		strcpy(ptr2,str);
+		ptr2[len]='\"';
+		ptr2[len+1]=0;
+		return out;
+	}
+	
+	if (!str)
+	{
+		if (p)	out=ensure(p,3);
+		else	out=(char*)cJSON_malloc(3);
+		if (!out) return 0;
+		strcpy(out,"\"\"");
+		return out;
+	}
+	ptr=str;while ((token=*ptr) && ++len) {if (strchr("\"\\\b\f\n\r\t",token)) len++; else if (token<32) len+=5;ptr++;}
+	
+	if (p)	out=ensure(p,len+3);
+	else	out=(char*)cJSON_malloc(len+3);
+	if (!out) return 0;
+
+	ptr2=out;ptr=str;
+	*ptr2++='\"';
+	while (*ptr)
+	{
+		if ((unsigned char)*ptr>31 && *ptr!='\"' && *ptr!='\\') *ptr2++=*ptr++;
+		else
+		{
+			*ptr2++='\\';
+			switch (token=*ptr++)
+			{
+				case '\\':	*ptr2++='\\';	break;
+				case '\"':	*ptr2++='\"';	break;
+				case '\b':	*ptr2++='b';	break;
+				case '\f':	*ptr2++='f';	break;
+				case '\n':	*ptr2++='n';	break;
+				case '\r':	*ptr2++='r';	break;
+				case '\t':	*ptr2++='t';	break;
+				default: sprintf(ptr2,"u%04x",token);ptr2+=5;	break;	/* escape and print */
+			}
+		}
+	}
+	*ptr2++='\"';*ptr2++=0;
+	return out;
+}
+/* Invote print_string_ptr (which is useful) on an item. */
+static char *print_string(cJSON *item,printbuffer *p)	{return print_string_ptr(item->valuestring,p);}
+
+/* Predeclare these prototypes. */
+static const char *parse_value(cJSON *item,const char *value);
+static char *print_value(cJSON *item,int depth,int fmt,printbuffer *p);
+static const char *parse_array(cJSON *item,const char *value);
+static char *print_array(cJSON *item,int depth,int fmt,printbuffer *p);
+static const char *parse_object(cJSON *item,const char *value);
+static char *print_object(cJSON *item,int depth,int fmt,printbuffer *p);
+
+/* Utility to jump whitespace and cr/lf */
+static const char *skip(const char *in) {while (in && *in && (unsigned char)*in<=32) in++; return in;}
+
+/* Parse an object - create a new root, and populate. */
+cJSON *cJSON_ParseWithOpts(const char *value,const char **return_parse_end,int require_null_terminated)
+{
+	const char *end=0;
+	cJSON *c=cJSON_New_Item();
+	ep=0;
+	if (!c) return 0;       /* memory fail */
+
+	end=parse_value(c,skip(value));
+	if (!end)	{cJSON_Delete(c);return 0;}	/* parse failure. ep is set. */
+
+	/* if we require null-terminated JSON without appended garbage, skip and then check for a null terminator */
+	if (require_null_terminated) {end=skip(end);if (*end) {cJSON_Delete(c);ep=end;return 0;}}
+	if (return_parse_end) *return_parse_end=end;
+	return c;
+}
+/* Default options for cJSON_Parse */
+cJSON *cJSON_Parse(const char *value) {return cJSON_ParseWithOpts(value,0,0);}
+
+/* Render a cJSON item/entity/structure to text. */
+char *cJSON_Print(cJSON *item)				{return print_value(item,0,1,0);}
+char *cJSON_PrintUnformatted(cJSON *item)	{return print_value(item,0,0,0);}
+
+char *cJSON_PrintBuffered(cJSON *item,int prebuffer,int fmt)
+{
+	printbuffer p;
+	p.buffer=(char*)cJSON_malloc(prebuffer);
+	p.length=prebuffer;
+	p.offset=0;
+	return print_value(item,0,fmt,&p);
+	return p.buffer;
+}
+
+
+/* Parser core - when encountering text, process appropriately. */
+static const char *parse_value(cJSON *item,const char *value)
+{
+	if (!value)						return 0;	/* Fail on null. */
+	if (!strncmp(value,"null",4))	{ item->type=cJSON_NULL;  return value+4; }
+	if (!strncmp(value,"false",5))	{ item->type=cJSON_False; return value+5; }
+	if (!strncmp(value,"true",4))	{ item->type=cJSON_True; item->valueint=1;	return value+4; }
+	if (*value=='\"')				{ return parse_string(item,value); }
+	if (*value=='-' || (*value>='0' && *value<='9'))	{ return parse_number(item,value); }
+	if (*value=='[')				{ return parse_array(item,value); }
+	if (*value=='{')				{ return parse_object(item,value); }
+
+	ep=value;return 0;	/* failure. */
+}
+
+/* Render a value to text. */
+static char *print_value(cJSON *item,int depth,int fmt,printbuffer *p)
+{
+	char *out=0;
+	if (!item) return 0;
+	if (p)
+	{
+		switch ((item->type)&255)
+		{
+			case cJSON_NULL:	{out=ensure(p,5);	if (out) strcpy(out,"null");	break;}
+			case cJSON_False:	{out=ensure(p,6);	if (out) strcpy(out,"false");	break;}
+			case cJSON_True:	{out=ensure(p,5);	if (out) strcpy(out,"true");	break;}
+			case cJSON_Number:	out=print_number(item,p);break;
+			case cJSON_String:	out=print_string(item,p);break;
+			case cJSON_Array:	out=print_array(item,depth,fmt,p);break;
+			case cJSON_Object:	out=print_object(item,depth,fmt,p);break;
+		}
+	}
+	else
+	{
+		switch ((item->type)&255)
+		{
+			case cJSON_NULL:	out=cJSON_strdup("null");	break;
+			case cJSON_False:	out=cJSON_strdup("false");break;
+			case cJSON_True:	out=cJSON_strdup("true"); break;
+			case cJSON_Number:	out=print_number(item,0);break;
+			case cJSON_String:	out=print_string(item,0);break;
+			case cJSON_Array:	out=print_array(item,depth,fmt,0);break;
+			case cJSON_Object:	out=print_object(item,depth,fmt,0);break;
+		}
+	}
+	return out;
+}
+
+/* Build an array from input text. */
+static const char *parse_array(cJSON *item,const char *value)
+{
+	cJSON *child;
+	if (*value!='[')	{ep=value;return 0;}	/* not an array! */
+
+	item->type=cJSON_Array;
+	value=skip(value+1);
+	if (*value==']') return value+1;	/* empty array. */
+
+	item->child=child=cJSON_New_Item();
+	if (!item->child) return 0;		 /* memory fail */
+	value=skip(parse_value(child,skip(value)));	/* skip any spacing, get the value. */
+	if (!value) return 0;
+
+	while (*value==',')
+	{
+		cJSON *new_item;
+		if (!(new_item=cJSON_New_Item())) return 0; 	/* memory fail */
+		child->next=new_item;new_item->prev=child;child=new_item;
+		value=skip(parse_value(child,skip(value+1)));
+		if (!value) return 0;	/* memory fail */
+	}
+
+	if (*value==']') return value+1;	/* end of array */
+	ep=value;return 0;	/* malformed. */
+}
+
+/* Render an array to text */
+static char *print_array(cJSON *item,int depth,int fmt,printbuffer *p)
+{
+	char **entries;
+	char *out=0,*ptr,*ret;int len=5;
+	cJSON *child=item->child;
+	int numentries=0,i=0,fail=0;
+	size_t tmplen=0;
+	
+	/* How many entries in the array? */
+	while (child) numentries++,child=child->next;
+	/* Explicitly handle numentries==0 */
+	if (!numentries)
+	{
+		if (p)	out=ensure(p,3);
+		else	out=(char*)cJSON_malloc(3);
+		if (out) strcpy(out,"[]");
+		return out;
+	}
+
+	if (p)
+	{
+		/* Compose the output array. */
+		i=p->offset;
+		ptr=ensure(p,1);if (!ptr) return 0;	*ptr='[';	p->offset++;
+		child=item->child;
+		while (child && !fail)
+		{
+			print_value(child,depth+1,fmt,p);
+			p->offset=update(p);
+			if (child->next) {len=fmt?2:1;ptr=ensure(p,len+1);if (!ptr) return 0;*ptr++=',';if(fmt)*ptr++=' ';*ptr=0;p->offset+=len;}
+			child=child->next;
+		}
+		ptr=ensure(p,2);if (!ptr) return 0;	*ptr++=']';*ptr=0;
+		out=(p->buffer)+i;
+	}
+	else
+	{
+		/* Allocate an array to hold the values for each */
+		entries=(char**)cJSON_malloc(numentries*sizeof(char*));
+		if (!entries) return 0;
+		memset(entries,0,numentries*sizeof(char*));
+		/* Retrieve all the results: */
+		child=item->child;
+		while (child && !fail)
+		{
+			ret=print_value(child,depth+1,fmt,0);
+			entries[i++]=ret;
+			if (ret) len+=strlen(ret)+2+(fmt?1:0); else fail=1;
+			child=child->next;
+		}
+		
+		/* If we didn't fail, try to malloc the output string */
+		if (!fail)	out=(char*)cJSON_malloc(len);
+		/* If that fails, we fail. */
+		if (!out) fail=1;
+
+		/* Handle failure. */
+		if (fail)
+		{
+			for (i=0;i<numentries;i++) if (entries[i]) cJSON_free(entries[i]);
+			cJSON_free(entries);
+			return 0;
+		}
+		
+		/* Compose the output array. */
+		*out='[';
+		ptr=out+1;*ptr=0;
+		for (i=0;i<numentries;i++)
+		{
+			tmplen=strlen(entries[i]);memcpy(ptr,entries[i],tmplen);ptr+=tmplen;
+			if (i!=numentries-1) {*ptr++=',';if(fmt)*ptr++=' ';*ptr=0;}
+			cJSON_free(entries[i]);
+		}
+		cJSON_free(entries);
+		*ptr++=']';*ptr++=0;
+	}
+	return out;	
+}
+
+/* Build an object from the text. */
+static const char *parse_object(cJSON *item,const char *value)
+{
+	cJSON *child;
+	if (*value!='{')	{ep=value;return 0;}	/* not an object! */
+	
+	item->type=cJSON_Object;
+	value=skip(value+1);
+	if (*value=='}') return value+1;	/* empty array. */
+	
+	item->child=child=cJSON_New_Item();
+	if (!item->child) return 0;
+	value=skip(parse_string(child,skip(value)));
+	if (!value) return 0;
+	child->string=child->valuestring;child->valuestring=0;
+	if (*value!=':') {ep=value;return 0;}	/* fail! */
+	value=skip(parse_value(child,skip(value+1)));	/* skip any spacing, get the value. */
+	if (!value) return 0;
+	
+	while (*value==',')
+	{
+		cJSON *new_item;
+		if (!(new_item=cJSON_New_Item()))	return 0; /* memory fail */
+		child->next=new_item;new_item->prev=child;child=new_item;
+		value=skip(parse_string(child,skip(value+1)));
+		if (!value) return 0;
+		child->string=child->valuestring;child->valuestring=0;
+		if (*value!=':') {ep=value;return 0;}	/* fail! */
+		value=skip(parse_value(child,skip(value+1)));	/* skip any spacing, get the value. */
+		if (!value) return 0;
+	}
+	
+	if (*value=='}') return value+1;	/* end of array */
+	ep=value;return 0;	/* malformed. */
+}
+
+/* Render an object to text. */
+static char *print_object(cJSON *item,int depth,int fmt,printbuffer *p)
+{
+	char **entries=0,**names=0;
+	char *out=0,*ptr,*ret,*str;int len=7,i=0,j;
+	cJSON *child=item->child;
+	int numentries=0,fail=0;
+	size_t tmplen=0;
+	/* Count the number of entries. */
+	while (child) numentries++,child=child->next;
+	/* Explicitly handle empty object case */
+	if (!numentries)
+	{
+		if (p) out=ensure(p,fmt?depth+4:3);
+		else	out=(char*)cJSON_malloc(fmt?depth+4:3);
+		if (!out)	return 0;
+		ptr=out;*ptr++='{';
+		if (fmt) {*ptr++='\n';for (i=0;i<depth-1;i++) *ptr++='\t';}
+		*ptr++='}';*ptr++=0;
+		return out;
+	}
+	if (p)
+	{
+		/* Compose the output: */
+		i=p->offset;
+		len=fmt?2:1;	ptr=ensure(p,len+1);	if (!ptr) return 0;
+		*ptr++='{';	if (fmt) *ptr++='\n';	*ptr=0;	p->offset+=len;
+		child=item->child;depth++;
+		while (child)
+		{
+			if (fmt)
+			{
+				ptr=ensure(p,depth);	if (!ptr) return 0;
+				for (j=0;j<depth;j++) *ptr++='\t';
+				p->offset+=depth;
+			}
+			print_string_ptr(child->string,p);
+			p->offset=update(p);
+			
+			len=fmt?2:1;
+			ptr=ensure(p,len);	if (!ptr) return 0;
+			*ptr++=':';if (fmt) *ptr++='\t';
+			p->offset+=len;
+			
+			print_value(child,depth,fmt,p);
+			p->offset=update(p);
+
+			len=(fmt?1:0)+(child->next?1:0);
+			ptr=ensure(p,len+1); if (!ptr) return 0;
+			if (child->next) *ptr++=',';
+			if (fmt) *ptr++='\n';*ptr=0;
+			p->offset+=len;
+			child=child->next;
+		}
+		ptr=ensure(p,fmt?(depth+1):2);	 if (!ptr) return 0;
+		if (fmt)	for (i=0;i<depth-1;i++) *ptr++='\t';
+		*ptr++='}';*ptr=0;
+		out=(p->buffer)+i;
+	}
+	else
+	{
+		/* Allocate space for the names and the objects */
+		entries=(char**)cJSON_malloc(numentries*sizeof(char*));
+		if (!entries) return 0;
+		names=(char**)cJSON_malloc(numentries*sizeof(char*));
+		if (!names) {cJSON_free(entries);return 0;}
+		memset(entries,0,sizeof(char*)*numentries);
+		memset(names,0,sizeof(char*)*numentries);
+
+		/* Collect all the results into our arrays: */
+		child=item->child;depth++;if (fmt) len+=depth;
+		while (child)
+		{
+			names[i]=str=print_string_ptr(child->string,0);
+			entries[i++]=ret=print_value(child,depth,fmt,0);
+			if (str && ret) len+=strlen(ret)+strlen(str)+2+(fmt?2+depth:0); else fail=1;
+			child=child->next;
+		}
+		
+		/* Try to allocate the output string */
+		if (!fail)	out=(char*)cJSON_malloc(len);
+		if (!out) fail=1;
+
+		/* Handle failure */
+		if (fail)
+		{
+			for (i=0;i<numentries;i++) {if (names[i]) cJSON_free(names[i]);if (entries[i]) cJSON_free(entries[i]);}
+			cJSON_free(names);cJSON_free(entries);
+			return 0;
+		}
+		
+		/* Compose the output: */
+		*out='{';ptr=out+1;if (fmt)*ptr++='\n';*ptr=0;
+		for (i=0;i<numentries;i++)
+		{
+			if (fmt) for (j=0;j<depth;j++) *ptr++='\t';
+			tmplen=strlen(names[i]);memcpy(ptr,names[i],tmplen);ptr+=tmplen;
+			*ptr++=':';if (fmt) *ptr++='\t';
+			strcpy(ptr,entries[i]);ptr+=strlen(entries[i]);
+			if (i!=numentries-1) *ptr++=',';
+			if (fmt) *ptr++='\n';*ptr=0;
+			cJSON_free(names[i]);cJSON_free(entries[i]);
+		}
+		
+		cJSON_free(names);cJSON_free(entries);
+		if (fmt) for (i=0;i<depth-1;i++) *ptr++='\t';
+		*ptr++='}';*ptr++=0;
+	}
+	return out;	
+}
+
+/* Get Array size/item / object item. */
+int    cJSON_GetArraySize(cJSON *array)							{cJSON *c=array->child;int i=0;while(c)i++,c=c->next;return i;}
+cJSON *cJSON_GetArrayItem(cJSON *array,int item)				{cJSON *c=array->child;  while (c && item>0) item--,c=c->next; return c;}
+cJSON *cJSON_GetObjectItem(cJSON *object,const char *string)	{cJSON *c=object->child; while (c && cJSON_strcasecmp(c->string,string)) c=c->next; return c;}
+
+/* Utility for array list handling. */
+static void suffix_object(cJSON *prev,cJSON *item) {prev->next=item;item->prev=prev;}
+/* Utility for handling references. */
+static cJSON *create_reference(cJSON *item) {cJSON *ref=cJSON_New_Item();if (!ref) return 0;memcpy(ref,item,sizeof(cJSON));ref->string=0;ref->type|=cJSON_IsReference;ref->next=ref->prev=0;return ref;}
+
+/* Add item to array/object. */
+void   cJSON_AddItemToArray(cJSON *array, cJSON *item)						{cJSON *c=array->child;if (!item) return; if (!c) {array->child=item;} else {while (c && c->next) c=c->next; suffix_object(c,item);}}
+void   cJSON_AddItemToObject(cJSON *object,const char *string,cJSON *item)	{if (!item) return; if (item->string) cJSON_free(item->string);item->string=cJSON_strdup(string);cJSON_AddItemToArray(object,item);}
+void   cJSON_AddItemToObjectCS(cJSON *object,const char *string,cJSON *item)	{if (!item) return; if (!(item->type&cJSON_StringIsConst) && item->string) cJSON_free(item->string);item->string=(char*)string;item->type|=cJSON_StringIsConst;cJSON_AddItemToArray(object,item);}
+void	cJSON_AddItemReferenceToArray(cJSON *array, cJSON *item)						{cJSON_AddItemToArray(array,create_reference(item));}
+void	cJSON_AddItemReferenceToObject(cJSON *object,const char *string,cJSON *item)	{cJSON_AddItemToObject(object,string,create_reference(item));}
+
+cJSON *cJSON_DetachItemFromArray(cJSON *array,int which)			{cJSON *c=array->child;while (c && which>0) c=c->next,which--;if (!c) return 0;
+	if (c->prev) c->prev->next=c->next;if (c->next) c->next->prev=c->prev;if (c==array->child) array->child=c->next;c->prev=c->next=0;return c;}
+void   cJSON_DeleteItemFromArray(cJSON *array,int which)			{cJSON_Delete(cJSON_DetachItemFromArray(array,which));}
+cJSON *cJSON_DetachItemFromObject(cJSON *object,const char *string) {int i=0;cJSON *c=object->child;while (c && cJSON_strcasecmp(c->string,string)) i++,c=c->next;if (c) return cJSON_DetachItemFromArray(object,i);return 0;}
+void   cJSON_DeleteItemFromObject(cJSON *object,const char *string) {cJSON_Delete(cJSON_DetachItemFromObject(object,string));}
+
+/* Replace array/object items with new ones. */
+void   cJSON_InsertItemInArray(cJSON *array,int which,cJSON *newitem)		{cJSON *c=array->child;while (c && which>0) c=c->next,which--;if (!c) {cJSON_AddItemToArray(array,newitem);return;}
+	newitem->next=c;newitem->prev=c->prev;c->prev=newitem;if (c==array->child) array->child=newitem; else newitem->prev->next=newitem;}
+void   cJSON_ReplaceItemInArray(cJSON *array,int which,cJSON *newitem)		{cJSON *c=array->child;while (c && which>0) c=c->next,which--;if (!c) return;
+	newitem->next=c->next;newitem->prev=c->prev;if (newitem->next) newitem->next->prev=newitem;
+	if (c==array->child) array->child=newitem; else newitem->prev->next=newitem;c->next=c->prev=0;cJSON_Delete(c);}
+void   cJSON_ReplaceItemInObject(cJSON *object,const char *string,cJSON *newitem){int i=0;cJSON *c=object->child;while(c && cJSON_strcasecmp(c->string,string))i++,c=c->next;if(c){newitem->string=cJSON_strdup(string);cJSON_ReplaceItemInArray(object,i,newitem);}}
+
+/* Create basic types: */
+cJSON *cJSON_CreateNull(void)					{cJSON *item=cJSON_New_Item();if(item)item->type=cJSON_NULL;return item;}
+cJSON *cJSON_CreateTrue(void)					{cJSON *item=cJSON_New_Item();if(item)item->type=cJSON_True;return item;}
+cJSON *cJSON_CreateFalse(void)					{cJSON *item=cJSON_New_Item();if(item)item->type=cJSON_False;return item;}
+cJSON *cJSON_CreateBool(int b)					{cJSON *item=cJSON_New_Item();if(item)item->type=b?cJSON_True:cJSON_False;return item;}
+cJSON *cJSON_CreateNumber(double num)			{cJSON *item=cJSON_New_Item();if(item){item->type=cJSON_Number;item->valuedouble=num;item->valueint=(int)num;}return item;}
+cJSON *cJSON_CreateString(const char *string)	{cJSON *item=cJSON_New_Item();if(item){item->type=cJSON_String;item->valuestring=cJSON_strdup(string);}return item;}
+cJSON *cJSON_CreateArray(void)					{cJSON *item=cJSON_New_Item();if(item)item->type=cJSON_Array;return item;}
+cJSON *cJSON_CreateObject(void)					{cJSON *item=cJSON_New_Item();if(item)item->type=cJSON_Object;return item;}
+
+/* Create Arrays: */
+cJSON *cJSON_CreateIntArray(const int *numbers,int count)		{int i;cJSON *n=0,*p=0,*a=cJSON_CreateArray();for(i=0;a && i<count;i++){n=cJSON_CreateNumber(numbers[i]);if(!i)a->child=n;else suffix_object(p,n);p=n;}return a;}
+cJSON *cJSON_CreateFloatArray(const float *numbers,int count)	{int i;cJSON *n=0,*p=0,*a=cJSON_CreateArray();for(i=0;a && i<count;i++){n=cJSON_CreateNumber(numbers[i]);if(!i)a->child=n;else suffix_object(p,n);p=n;}return a;}
+cJSON *cJSON_CreateDoubleArray(const double *numbers,int count)	{int i;cJSON *n=0,*p=0,*a=cJSON_CreateArray();for(i=0;a && i<count;i++){n=cJSON_CreateNumber(numbers[i]);if(!i)a->child=n;else suffix_object(p,n);p=n;}return a;}
+cJSON *cJSON_CreateStringArray(const char **strings,int count)	{int i;cJSON *n=0,*p=0,*a=cJSON_CreateArray();for(i=0;a && i<count;i++){n=cJSON_CreateString(strings[i]);if(!i)a->child=n;else suffix_object(p,n);p=n;}return a;}
+
+/* Duplication */
+cJSON *cJSON_Duplicate(cJSON *item,int recurse)
+{
+	cJSON *newitem,*cptr,*nptr=0,*newchild;
+	/* Bail on bad ptr */
+	if (!item) return 0;
+	/* Create new item */
+	newitem=cJSON_New_Item();
+	if (!newitem) return 0;
+	/* Copy over all vars */
+	newitem->type=item->type&(~cJSON_IsReference),newitem->valueint=item->valueint,newitem->valuedouble=item->valuedouble;
+	if (item->valuestring)	{newitem->valuestring=cJSON_strdup(item->valuestring);	if (!newitem->valuestring)	{cJSON_Delete(newitem);return 0;}}
+	if (item->string)		{newitem->string=cJSON_strdup(item->string);			if (!newitem->string)		{cJSON_Delete(newitem);return 0;}}
+	/* If non-recursive, then we're done! */
+	if (!recurse) return newitem;
+	/* Walk the ->next chain for the child. */
+	cptr=item->child;
+	while (cptr)
+	{
+		newchild=cJSON_Duplicate(cptr,1);		/* Duplicate (with recurse) each item in the ->next chain */
+		if (!newchild) {cJSON_Delete(newitem);return 0;}
+		if (nptr)	{nptr->next=newchild,newchild->prev=nptr;nptr=newchild;}	/* If newitem->child already set, then crosswire ->prev and ->next and move on */
+		else		{newitem->child=newchild;nptr=newchild;}					/* Set newitem->child and move to it */
+		cptr=cptr->next;
+	}
+	return newitem;
+}
+
+void cJSON_Minify(char *json)
+{
+	char *into=json;
+	while (*json)
+	{
+		if (*json==' ') json++;
+		else if (*json=='\t') json++;	/* Whitespace characters. */
+		else if (*json=='\r') json++;
+		else if (*json=='\n') json++;
+		else if (*json=='/' && json[1]=='/')  while (*json && *json!='\n') json++;	/* double-slash comments, to end of line. */
+		else if (*json=='/' && json[1]=='*') {while (*json && !(*json=='*' && json[1]=='/')) json++;json+=2;}	/* multiline comments. */
+		else if (*json=='\"'){*into++=*json++;while (*json && *json!='\"'){if (*json=='\\') *into++=*json++;*into++=*json++;}*into++=*json++;} /* string literals, which are \" sensitive. */
+		else *into++=*json++;			/* All other characters. */
+	}
+	*into=0;	/* and null-terminate. */
+}

+ 149 - 0
Modules/play_ip/cJSON.h

@@ -0,0 +1,149 @@
+/*
+  Copyright (c) 2009 Dave Gamble
+ 
+  Permission is hereby granted, free of charge, to any person obtaining a copy
+  of this software and associated documentation files (the "Software"), to deal
+  in the Software without restriction, including without limitation the rights
+  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+  copies of the Software, and to permit persons to whom the Software is
+  furnished to do so, subject to the following conditions:
+ 
+  The above copyright notice and this permission notice shall be included in
+  all copies or substantial portions of the Software.
+ 
+  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+  THE SOFTWARE.
+*/
+
+#ifndef cJSON__h
+#define cJSON__h
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+/* cJSON Types: */
+#define cJSON_False 0
+#define cJSON_True 1
+#define cJSON_NULL 2
+#define cJSON_Number 3
+#define cJSON_String 4
+#define cJSON_Array 5
+#define cJSON_Object 6
+	
+#define cJSON_IsReference 256
+#define cJSON_StringIsConst 512
+
+/* The cJSON structure: */
+typedef struct cJSON {
+	struct cJSON *next,*prev;	/* next/prev allow you to walk array/object chains. Alternatively, use GetArraySize/GetArrayItem/GetObjectItem */
+	struct cJSON *child;		/* An array or object item will have a child pointer pointing to a chain of the items in the array/object. */
+
+	int type;					/* The type of the item, as above. */
+
+	char *valuestring;			/* The item's string, if type==cJSON_String */
+	int valueint;				/* The item's number, if type==cJSON_Number */
+	double valuedouble;			/* The item's number, if type==cJSON_Number */
+
+	char *string;				/* The item's name string, if this item is the child of, or is in the list of subitems of an object. */
+} cJSON;
+
+typedef struct cJSON_Hooks {
+      void *(*malloc_fn)(size_t sz);
+      void (*free_fn)(void *ptr);
+} cJSON_Hooks;
+
+/* Supply malloc, realloc and free functions to cJSON */
+extern void cJSON_InitHooks(cJSON_Hooks* hooks);
+
+
+/* Supply a block of JSON, and this returns a cJSON object you can interrogate. Call cJSON_Delete when finished. */
+extern cJSON *cJSON_Parse(const char *value);
+/* Render a cJSON entity to text for transfer/storage. Free the char* when finished. */
+extern char  *cJSON_Print(cJSON *item);
+/* Render a cJSON entity to text for transfer/storage without any formatting. Free the char* when finished. */
+extern char  *cJSON_PrintUnformatted(cJSON *item);
+/* Render a cJSON entity to text using a buffered strategy. prebuffer is a guess at the final size. guessing well reduces reallocation. fmt=0 gives unformatted, =1 gives formatted */
+extern char *cJSON_PrintBuffered(cJSON *item,int prebuffer,int fmt);
+/* Delete a cJSON entity and all subentities. */
+extern void   cJSON_Delete(cJSON *c);
+
+/* Returns the number of items in an array (or object). */
+extern int	  cJSON_GetArraySize(cJSON *array);
+/* Retrieve item number "item" from array "array". Returns NULL if unsuccessful. */
+extern cJSON *cJSON_GetArrayItem(cJSON *array,int item);
+/* Get item "string" from object. Case insensitive. */
+extern cJSON *cJSON_GetObjectItem(cJSON *object,const char *string);
+
+/* For analysing failed parses. This returns a pointer to the parse error. You'll probably need to look a few chars back to make sense of it. Defined when cJSON_Parse() returns 0. 0 when cJSON_Parse() succeeds. */
+extern const char *cJSON_GetErrorPtr(void);
+	
+/* These calls create a cJSON item of the appropriate type. */
+extern cJSON *cJSON_CreateNull(void);
+extern cJSON *cJSON_CreateTrue(void);
+extern cJSON *cJSON_CreateFalse(void);
+extern cJSON *cJSON_CreateBool(int b);
+extern cJSON *cJSON_CreateNumber(double num);
+extern cJSON *cJSON_CreateString(const char *string);
+extern cJSON *cJSON_CreateArray(void);
+extern cJSON *cJSON_CreateObject(void);
+
+/* These utilities create an Array of count items. */
+extern cJSON *cJSON_CreateIntArray(const int *numbers,int count);
+extern cJSON *cJSON_CreateFloatArray(const float *numbers,int count);
+extern cJSON *cJSON_CreateDoubleArray(const double *numbers,int count);
+extern cJSON *cJSON_CreateStringArray(const char **strings,int count);
+
+/* Append item to the specified array/object. */
+extern void cJSON_AddItemToArray(cJSON *array, cJSON *item);
+extern void	cJSON_AddItemToObject(cJSON *object,const char *string,cJSON *item);
+extern void	cJSON_AddItemToObjectCS(cJSON *object,const char *string,cJSON *item);	/* Use this when string is definitely const (i.e. a literal, or as good as), and will definitely survive the cJSON object */
+/* Append reference to item to the specified array/object. Use this when you want to add an existing cJSON to a new cJSON, but don't want to corrupt your existing cJSON. */
+extern void cJSON_AddItemReferenceToArray(cJSON *array, cJSON *item);
+extern void	cJSON_AddItemReferenceToObject(cJSON *object,const char *string,cJSON *item);
+
+/* Remove/Detatch items from Arrays/Objects. */
+extern cJSON *cJSON_DetachItemFromArray(cJSON *array,int which);
+extern void   cJSON_DeleteItemFromArray(cJSON *array,int which);
+extern cJSON *cJSON_DetachItemFromObject(cJSON *object,const char *string);
+extern void   cJSON_DeleteItemFromObject(cJSON *object,const char *string);
+	
+/* Update array items. */
+extern void cJSON_InsertItemInArray(cJSON *array,int which,cJSON *newitem);	/* Shifts pre-existing items to the right. */
+extern void cJSON_ReplaceItemInArray(cJSON *array,int which,cJSON *newitem);
+extern void cJSON_ReplaceItemInObject(cJSON *object,const char *string,cJSON *newitem);
+
+/* Duplicate a cJSON item */
+extern cJSON *cJSON_Duplicate(cJSON *item,int recurse);
+/* Duplicate will create a new, identical cJSON item to the one you pass, in new memory that will
+need to be released. With recurse!=0, it will duplicate any children connected to the item.
+The item->next and ->prev pointers are always zero on return from Duplicate. */
+
+/* ParseWithOpts allows you to require (and check) that the JSON is null terminated, and to retrieve the pointer to the final byte parsed. */
+extern cJSON *cJSON_ParseWithOpts(const char *value,const char **return_parse_end,int require_null_terminated);
+
+extern void cJSON_Minify(char *json);
+
+/* Macros for creating things quickly. */
+#define cJSON_AddNullToObject(object,name)		cJSON_AddItemToObject(object, name, cJSON_CreateNull())
+#define cJSON_AddTrueToObject(object,name)		cJSON_AddItemToObject(object, name, cJSON_CreateTrue())
+#define cJSON_AddFalseToObject(object,name)		cJSON_AddItemToObject(object, name, cJSON_CreateFalse())
+#define cJSON_AddBoolToObject(object,name,b)	cJSON_AddItemToObject(object, name, cJSON_CreateBool(b))
+#define cJSON_AddNumberToObject(object,name,n)	cJSON_AddItemToObject(object, name, cJSON_CreateNumber(n))
+#define cJSON_AddStringToObject(object,name,s)	cJSON_AddItemToObject(object, name, cJSON_CreateString(s))
+
+/* When assigning an integer value, it needs to be propagated to valuedouble too. */
+#define cJSON_SetIntValue(object,val)			((object)?(object)->valueint=(object)->valuedouble=(val):(val))
+#define cJSON_SetNumberValue(object,val)		((object)?(object)->valueint=(object)->valuedouble=(val):(val))
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif

+ 173 - 0
Modules/play_ip/dictionary.h

@@ -0,0 +1,173 @@
+
+/*-------------------------------------------------------------------------*/
+/**
+   @file    dictionary.h
+   @author  N. Devillard
+   @brief   Implements a dictionary for string variables.
+
+   This module implements a simple dictionary object, i.e. a list
+   of string/string associations. This object is useful to store e.g.
+   informations retrieved from a configuration file (ini files).
+*/
+/*--------------------------------------------------------------------------*/
+
+#ifndef _DICTIONARY_H_
+#define _DICTIONARY_H_
+
+/*---------------------------------------------------------------------------
+                                Includes
+ ---------------------------------------------------------------------------*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*---------------------------------------------------------------------------
+                                New types
+ ---------------------------------------------------------------------------*/
+
+
+/*-------------------------------------------------------------------------*/
+/**
+  @brief    Dictionary object
+
+  This object contains a list of string/string associations. Each
+  association is identified by a unique string key. Looking up values
+  in the dictionary is speeded up by the use of a (hopefully collision-free)
+  hash function.
+ */
+/*-------------------------------------------------------------------------*/
+typedef struct _dictionary_ {
+    int             n ;     /** Number of entries in dictionary */
+    ssize_t         size ;  /** Storage size */
+    char        **  val ;   /** List of string values */
+    char        **  key ;   /** List of string keys */
+    unsigned     *  hash ;  /** List of hash values for keys */
+} dictionary ;
+
+
+/*---------------------------------------------------------------------------
+                            Function prototypes
+ ---------------------------------------------------------------------------*/
+
+/*-------------------------------------------------------------------------*/
+/**
+  @brief    Compute the hash key for a string.
+  @param    key     Character string to use for key.
+  @return   1 unsigned int on at least 32 bits.
+
+  This hash function has been taken from an Article in Dr Dobbs Journal.
+  This is normally a collision-free function, distributing keys evenly.
+  The key is stored anyway in the struct so that collision can be avoided
+  by comparing the key itself in last resort.
+ */
+/*--------------------------------------------------------------------------*/
+unsigned dictionary_hash(const char * key);
+
+/*-------------------------------------------------------------------------*/
+/**
+  @brief    Create a new dictionary object.
+  @param    size    Optional initial size of the dictionary.
+  @return   1 newly allocated dictionary objet.
+
+  This function allocates a new dictionary object of given size and returns
+  it. If you do not know in advance (roughly) the number of entries in the
+  dictionary, give size=0.
+ */
+/*--------------------------------------------------------------------------*/
+dictionary * dictionary_new(size_t size);
+
+/*-------------------------------------------------------------------------*/
+/**
+  @brief    Delete a dictionary object
+  @param    d   dictionary object to deallocate.
+  @return   void
+
+  Deallocate a dictionary object and all memory associated to it.
+ */
+/*--------------------------------------------------------------------------*/
+void dictionary_del(dictionary * vd);
+
+/*-------------------------------------------------------------------------*/
+/**
+  @brief    Get a value from a dictionary.
+  @param    d       dictionary object to search.
+  @param    key     Key to look for in the dictionary.
+  @param    def     Default value to return if key not found.
+  @return   1 pointer to internally allocated character string.
+
+  This function locates a key in a dictionary and returns a pointer to its
+  value, or the passed 'def' pointer if no such key can be found in
+  dictionary. The returned character pointer points to data internal to the
+  dictionary object, you should not try to free it or modify it.
+ */
+/*--------------------------------------------------------------------------*/
+const char * dictionary_get(const dictionary * d, const char * key, const char * def);
+
+
+/*-------------------------------------------------------------------------*/
+/**
+  @brief    Set a value in a dictionary.
+  @param    d       dictionary object to modify.
+  @param    key     Key to modify or add.
+  @param    val     Value to add.
+  @return   int     0 if Ok, anything else otherwise
+
+  If the given key is found in the dictionary, the associated value is
+  replaced by the provided one. If the key cannot be found in the
+  dictionary, it is added to it.
+
+  It is Ok to provide a NULL value for val, but NULL values for the dictionary
+  or the key are considered as errors: the function will return immediately
+  in such a case.
+
+  Notice that if you dictionary_set a variable to NULL, a call to
+  dictionary_get will return a NULL value: the variable will be found, and
+  its value (NULL) is returned. In other words, setting the variable
+  content to NULL is equivalent to deleting the variable from the
+  dictionary. It is not possible (in this implementation) to have a key in
+  the dictionary without value.
+
+  This function returns non-zero in case of failure.
+ */
+/*--------------------------------------------------------------------------*/
+int dictionary_set(dictionary * vd, const char * key, const char * val);
+
+/*-------------------------------------------------------------------------*/
+/**
+  @brief    Delete a key in a dictionary
+  @param    d       dictionary object to modify.
+  @param    key     Key to remove.
+  @return   void
+
+  This function deletes a key in a dictionary. Nothing is done if the
+  key cannot be found.
+ */
+/*--------------------------------------------------------------------------*/
+void dictionary_unset(dictionary * d, const char * key);
+
+
+/*-------------------------------------------------------------------------*/
+/**
+  @brief    Dump a dictionary to an opened file pointer.
+  @param    d   Dictionary to dump
+  @param    f   Opened file pointer.
+  @return   void
+
+  Dumps a dictionary onto an opened file pointer. Key pairs are printed out
+  as @c [Key]=[Value], one per line. It is Ok to provide stdout or stderr as
+  output file pointers.
+ */
+/*--------------------------------------------------------------------------*/
+void dictionary_dump(const dictionary * d, FILE * out);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif

+ 358 - 0
Modules/play_ip/iniparser.h

@@ -0,0 +1,358 @@
+
+/*-------------------------------------------------------------------------*/
+/**
+   @file    iniparser.h
+   @author  N. Devillard
+   @brief   Parser for ini files.
+*/
+/*--------------------------------------------------------------------------*/
+
+#ifndef _INIPARSER_H_
+#define _INIPARSER_H_
+
+/*---------------------------------------------------------------------------
+                                Includes
+ ---------------------------------------------------------------------------*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+/*
+ * The following #include is necessary on many Unixes but not Linux.
+ * It is not needed for Windows platforms.
+ * Uncomment it if needed.
+ */
+/* #include <unistd.h> */
+
+#include "dictionary.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*-------------------------------------------------------------------------*/
+/**
+  @brief    Configure a function to receive the error messages.
+  @param    errback  Function to call.
+
+  By default, the error will be printed on stderr. If a null pointer is passed
+  as errback the error callback will be switched back to default.
+ */
+/*--------------------------------------------------------------------------*/
+
+void iniparser_set_error_callback(int (*errback)(const char *, ...));
+
+/*-------------------------------------------------------------------------*/
+/**
+  @brief    Get number of sections in a dictionary
+  @param    d   Dictionary to examine
+  @return   int Number of sections found in dictionary
+
+  This function returns the number of sections found in a dictionary.
+  The test to recognize sections is done on the string stored in the
+  dictionary: a section name is given as "section" whereas a key is
+  stored as "section:key", thus the test looks for entries that do not
+  contain a colon.
+
+  This clearly fails in the case a section name contains a colon, but
+  this should simply be avoided.
+
+  This function returns -1 in case of error.
+ */
+/*--------------------------------------------------------------------------*/
+
+int iniparser_getnsec(const dictionary * d);
+
+
+/*-------------------------------------------------------------------------*/
+/**
+  @brief    Get name for section n in a dictionary.
+  @param    d   Dictionary to examine
+  @param    n   Section number (from 0 to nsec-1).
+  @return   Pointer to char string
+
+  This function locates the n-th section in a dictionary and returns
+  its name as a pointer to a string statically allocated inside the
+  dictionary. Do not free or modify the returned string!
+
+  This function returns NULL in case of error.
+ */
+/*--------------------------------------------------------------------------*/
+
+const char * iniparser_getsecname(const dictionary * d, int n);
+
+
+/*-------------------------------------------------------------------------*/
+/**
+  @brief    Save a dictionary to a loadable ini file
+  @param    d   Dictionary to dump
+  @param    f   Opened file pointer to dump to
+  @return   void
+
+  This function dumps a given dictionary into a loadable ini file.
+  It is Ok to specify @c stderr or @c stdout as output files.
+ */
+/*--------------------------------------------------------------------------*/
+
+void iniparser_dump_ini(const dictionary * d, FILE * f);
+
+/*-------------------------------------------------------------------------*/
+/**
+  @brief    Save a dictionary section to a loadable ini file
+  @param    d   Dictionary to dump
+  @param    s   Section name of dictionary to dump
+  @param    f   Opened file pointer to dump to
+  @return   void
+
+  This function dumps a given section of a given dictionary into a loadable ini
+  file.  It is Ok to specify @c stderr or @c stdout as output files.
+ */
+/*--------------------------------------------------------------------------*/
+
+void iniparser_dumpsection_ini(const dictionary * d, const char * s, FILE * f);
+
+/*-------------------------------------------------------------------------*/
+/**
+  @brief    Dump a dictionary to an opened file pointer.
+  @param    d   Dictionary to dump.
+  @param    f   Opened file pointer to dump to.
+  @return   void
+
+  This function prints out the contents of a dictionary, one element by
+  line, onto the provided file pointer. It is OK to specify @c stderr
+  or @c stdout as output files. This function is meant for debugging
+  purposes mostly.
+ */
+/*--------------------------------------------------------------------------*/
+void iniparser_dump(const dictionary * d, FILE * f);
+
+/*-------------------------------------------------------------------------*/
+/**
+  @brief    Get the number of keys in a section of a dictionary.
+  @param    d   Dictionary to examine
+  @param    s   Section name of dictionary to examine
+  @return   Number of keys in section
+ */
+/*--------------------------------------------------------------------------*/
+int iniparser_getsecnkeys(const dictionary * d, const char * s);
+
+/*-------------------------------------------------------------------------*/
+/**
+  @brief    Get the number of keys in a section of a dictionary.
+  @param    d    Dictionary to examine
+  @param    s    Section name of dictionary to examine
+  @param    keys Already allocated array to store the keys in
+  @return   The pointer passed as `keys` argument or NULL in case of error
+
+  This function queries a dictionary and finds all keys in a given section.
+  The keys argument should be an array of pointers which size has been
+  determined by calling `iniparser_getsecnkeys` function prior to this one.
+
+  Each pointer in the returned char pointer-to-pointer is pointing to
+  a string allocated in the dictionary; do not free or modify them.
+ */
+/*--------------------------------------------------------------------------*/
+const char ** iniparser_getseckeys(const dictionary * d, const char * s, const char ** keys);
+
+
+/*-------------------------------------------------------------------------*/
+/**
+  @brief    Get the string associated to a key
+  @param    d       Dictionary to search
+  @param    key     Key string to look for
+  @param    def     Default value to return if key not found.
+  @return   pointer to statically allocated character string
+
+  This function queries a dictionary for a key. A key as read from an
+  ini file is given as "section:key". If the key cannot be found,
+  the pointer passed as 'def' is returned.
+  The returned char pointer is pointing to a string allocated in
+  the dictionary, do not free or modify it.
+ */
+/*--------------------------------------------------------------------------*/
+const char * iniparser_getstring(const dictionary * d, const char * key, const char * def);
+
+/*-------------------------------------------------------------------------*/
+/**
+  @brief    Get the string associated to a key, convert to an int
+  @param    d Dictionary to search
+  @param    key Key string to look for
+  @param    notfound Value to return in case of error
+  @return   integer
+
+  This function queries a dictionary for a key. A key as read from an
+  ini file is given as "section:key". If the key cannot be found,
+  the notfound value is returned.
+
+  Supported values for integers include the usual C notation
+  so decimal, octal (starting with 0) and hexadecimal (starting with 0x)
+  are supported. Examples:
+
+  - "42"      ->  42
+  - "042"     ->  34 (octal -> decimal)
+  - "0x42"    ->  66 (hexa  -> decimal)
+
+  Warning: the conversion may overflow in various ways. Conversion is
+  totally outsourced to strtol(), see the associated man page for overflow
+  handling.
+
+  Credits: Thanks to A. Becker for suggesting strtol()
+ */
+/*--------------------------------------------------------------------------*/
+int iniparser_getint(const dictionary * d, const char * key, int notfound);
+
+/*-------------------------------------------------------------------------*/
+/**
+  @brief    Get the string associated to a key, convert to an long int
+  @param    d Dictionary to search
+  @param    key Key string to look for
+  @param    notfound Value to return in case of error
+  @return   integer
+
+  This function queries a dictionary for a key. A key as read from an
+  ini file is given as "section:key". If the key cannot be found,
+  the notfound value is returned.
+
+  Supported values for integers include the usual C notation
+  so decimal, octal (starting with 0) and hexadecimal (starting with 0x)
+  are supported. Examples:
+
+  - "42"      ->  42
+  - "042"     ->  34 (octal -> decimal)
+  - "0x42"    ->  66 (hexa  -> decimal)
+
+  Warning: the conversion may overflow in various ways. Conversion is
+  totally outsourced to strtol(), see the associated man page for overflow
+  handling.
+ */
+/*--------------------------------------------------------------------------*/
+long int iniparser_getlongint(const dictionary * d, const char * key, long int notfound);
+
+
+/*-------------------------------------------------------------------------*/
+/**
+  @brief    Get the string associated to a key, convert to a double
+  @param    d Dictionary to search
+  @param    key Key string to look for
+  @param    notfound Value to return in case of error
+  @return   double
+
+  This function queries a dictionary for a key. A key as read from an
+  ini file is given as "section:key". If the key cannot be found,
+  the notfound value is returned.
+ */
+/*--------------------------------------------------------------------------*/
+double iniparser_getdouble(const dictionary * d, const char * key, double notfound);
+
+/*-------------------------------------------------------------------------*/
+/**
+  @brief    Get the string associated to a key, convert to a boolean
+  @param    d Dictionary to search
+  @param    key Key string to look for
+  @param    notfound Value to return in case of error
+  @return   integer
+
+  This function queries a dictionary for a key. A key as read from an
+  ini file is given as "section:key". If the key cannot be found,
+  the notfound value is returned.
+
+  A true boolean is found if one of the following is matched:
+
+  - A string starting with 'y'
+  - A string starting with 'Y'
+  - A string starting with 't'
+  - A string starting with 'T'
+  - A string starting with '1'
+
+  A false boolean is found if one of the following is matched:
+
+  - A string starting with 'n'
+  - A string starting with 'N'
+  - A string starting with 'f'
+  - A string starting with 'F'
+  - A string starting with '0'
+
+  The notfound value returned if no boolean is identified, does not
+  necessarily have to be 0 or 1.
+ */
+/*--------------------------------------------------------------------------*/
+int iniparser_getboolean(const dictionary * d, const char * key, int notfound);
+
+
+/*-------------------------------------------------------------------------*/
+/**
+  @brief    Set an entry in a dictionary.
+  @param    ini     Dictionary to modify.
+  @param    entry   Entry to modify (entry name)
+  @param    val     New value to associate to the entry.
+  @return   int     0 if Ok, -1 otherwise.
+
+  If the given entry can be found in the dictionary, it is modified to
+  contain the provided value. If it cannot be found, the entry is created.
+  It is Ok to set val to NULL.
+ */
+/*--------------------------------------------------------------------------*/
+int iniparser_set(dictionary * ini, const char * entry, const char * val);
+
+
+/*-------------------------------------------------------------------------*/
+/**
+  @brief    Delete an entry in a dictionary
+  @param    ini     Dictionary to modify
+  @param    entry   Entry to delete (entry name)
+  @return   void
+
+  If the given entry can be found, it is deleted from the dictionary.
+ */
+/*--------------------------------------------------------------------------*/
+void iniparser_unset(dictionary * ini, const char * entry);
+
+/*-------------------------------------------------------------------------*/
+/**
+  @brief    Finds out if a given entry exists in a dictionary
+  @param    ini     Dictionary to search
+  @param    entry   Name of the entry to look for
+  @return   integer 1 if entry exists, 0 otherwise
+
+  Finds out if a given entry exists in the dictionary. Since sections
+  are stored as keys with NULL associated values, this is the only way
+  of querying for the presence of sections in a dictionary.
+ */
+/*--------------------------------------------------------------------------*/
+int iniparser_find_entry(const dictionary * ini, const char * entry) ;
+
+/*-------------------------------------------------------------------------*/
+/**
+  @brief    Parse an ini file and return an allocated dictionary object
+  @param    ininame Name of the ini file to read.
+  @return   Pointer to newly allocated dictionary
+
+  This is the parser for ini files. This function is called, providing
+  the name of the file to be read. It returns a dictionary object that
+  should not be accessed directly, but through accessor functions
+  instead.
+
+  The returned dictionary must be freed using iniparser_freedict().
+ */
+/*--------------------------------------------------------------------------*/
+dictionary * iniparser_load(const char * ininame);
+
+/*-------------------------------------------------------------------------*/
+/**
+  @brief    Free all memory associated to an ini dictionary
+  @param    d Dictionary to free
+  @return   void
+
+  Free all memory associated to an ini dictionary.
+  It is mandatory to call this function before the dictionary object
+  gets out of the current context.
+ */
+/*--------------------------------------------------------------------------*/
+void iniparser_freedict(dictionary * d);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif

+ 295 - 0
Modules/play_ip/main.c

@@ -0,0 +1,295 @@
+#include <sys/poll.h>
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <assert.h>
+#include <time.h>
+#include <pthread.h>
+#include "hiredis/hiredis.h"
+#include "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
+//BARESIP_REG
+#define REGISTER_FAIL   0
+#define REGISTER_OK     1
+//DEV_TYPE
+#define SPEAKER     0
+#define SPEAKER2    1
+#define SPEAKER3    1
+#define INTERCOM    2
+#define GATEWAYE    3
+//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
+//DIN
+#define DOWN    0
+#define UP      1
+
+#define SPK_CONF    "/etc/speaker.conf"
+#define VOL_CONF    "/oem/etc/volctrl.conf"
+
+//operator log type
+#define BTN			"BUTTON"
+#define FUN			"FUNCTION"
+#define STA         "SIP STATE"
+
+static int BARESIP_STATUS = OFFLINE;
+static int keyLedStatus = Led_On;
+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 RELAY_STATE = GPIO_OFF;
+static int press_down = FALSE;
+static int DEV_TYPE = SPEAKER;
+static int CURRENT_CALLS = 0;
+static int regcount=0;
+static char DTMF_STRING[32] = "\0";
+
+/*
+*   @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;
+}
+
+//控制功放的开启/关闭,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;
+}
+
+void writeLog(char *type,char *action, char *remark)
+{
+	char logstr[256];
+    redisContext *pContext = redisConnect("127.0.0.1", 6379);
+
+    if (NULL == pContext || pContext->err == 1)
+    {
+        printf("%s\n", pContext->errstr);
+        return;
+    }
+	sprintf(logstr, "%s,%s,%s", type, action, remark);
+    redisReply *pReply;
+    pReply = redisCommand(pContext, "LPUSH writelog-channel %s", logstr);
+
+    freeReplyObject(pReply);
+	redisFree(pContext);
+}
+
+int PlayIP()
+{
+    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 /home/new-speaker/target/share/sounds/en/get_ip_failed.mp3");
+        }else{
+            system("mpg123 /home/new-speaker/target/share/sounds/cn/get_ip_failed.mp3");
+        }
+        return 0;
+    }
+
+    if (strcmp(language, "en") == 0){
+        strcpy(cmd_line,"cd /home/new-speaker/target/share/sounds/en/;mpg123 ");
+    }else{
+        strcpy(cmd_line,"cd /home/new-speaker/target/share/sounds/cn/;mpg123 ");
+    }
+
+    int i;
+    for (i=0;i<strlen(ipaddr);i++){
+        switch(ipaddr[i])
+        {
+            case '0':
+                strcat(cmd_line,"digit-0.mp3 ");
+                break;
+            case '1':
+                strcat(cmd_line,"digit-1.mp3 ");
+                break;
+            case '2':
+                strcat(cmd_line,"digit-2.mp3 ");
+                break;
+            case '3':
+                strcat(cmd_line,"digit-3.mp3 ");
+                break;
+            case '4':
+                strcat(cmd_line,"digit-4.mp3 ");
+                break;
+            case '5':
+                strcat(cmd_line,"digit-5.mp3 ");
+                break;
+            case '6':
+                strcat(cmd_line,"digit-6.mp3 ");
+                break;
+            case '7':
+                strcat(cmd_line,"digit-7.mp3 ");
+                break;
+            case '8':
+                strcat(cmd_line,"digit-8.mp3 ");
+                break;
+            case '9':
+                strcat(cmd_line,"digit-9.mp3 ");
+                break;
+            case '.':
+                strcat(cmd_line,"dian.mp3 ");
+                break;
+        }
+    }
+    system(cmd_line);
+
+    amplifier_switch(FALSE); //关闭功放
+    system("/etc/scripts/set_volume.sh resume");
+    writeLog( FUN, "Play IP Address", ipaddr );
+    return 0;
+}
+
+
+int main(int argc, char *argv[]){
+    dictionary  *   ini ;
+    char alwaysPlayIP[8];
+
+    sleep(2);
+    GetCmdValue(VOL_CONF, "volume:always_play_ip", alwaysPlayIP, sizeof(alwaysPlayIP));
+    if (strcmp(alwaysPlayIP, "yes") == 0)
+    {
+        system("/usr/bin/amixer -q sset 'Master',0 29");
+        system("/usr/bin/amixer -q sset 'Master',0 29");
+        system("/usr/bin/amixer -q sset 'Master',0 29");
+        PlayIP();
+        return TRUE;
+    }
+
+    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)
+    {
+        goto end;
+    }
+    else if(strcmp(iniparser_getstring(ini, "account_info_2:enable", "no"),"yes") == 0)
+    {
+        goto end;
+    }
+    else if(strcmp(iniparser_getstring(ini, "account_info_3:enable", "no"),"yes") == 0)
+    {
+        goto end;
+    }
+    else if(strcmp(iniparser_getstring(ini, "account_info_p2p:enable", "no"),"yes") == 0)
+    {
+        goto end;
+    }
+    else if(strcmp(iniparser_getstring(ini, "multicast_player:enable", "no"),"yes") == 0)
+    {
+        goto end;
+    }
+    else if(strcmp(iniparser_getstring(ini, "onvif:enable", "no"),"yes") == 0)
+    {
+        goto end;
+    }
+    system("/usr/bin/amixer -q sset 'Master',0 29");
+    system("/usr/bin/amixer -q sset 'Master',0 29");
+    system("/usr/bin/amixer -q sset 'Master',0 29");
+    PlayIP();
+
+end:
+    iniparser_freedict(ini);
+    return TRUE;
+}

+ 20 - 0
Modules/playip/Makefile

@@ -0,0 +1,20 @@
+TARGET = play_ip
+Dir2store = ${TARGET_DIR}/usr/bin
+CFLAGS =
+
+${TARGET}:*.o
+	${CC} -o $@ ${CFLAGS} $<
+
+%.o:%.c
+	${CC} -c $<
+
+.PHONY:clean install uninstall
+
+clean:
+	rm -f *.o ${TARGET}
+
+install:
+# 	cp -f ${TARGET} ${Dir2store}
+
+uninstall:
+	rm -f ${Dir2store}/${TARGET}

+ 92 - 0
Modules/playip/main.c

@@ -0,0 +1,92 @@
+#include <stdio.h>
+#include <string.h>
+
+#define Boolean	int
+#define TRUE	1
+#define FALSE	0
+#define MAX_PIPE_BUFSIZE 	256
+
+Boolean get_ip(char * pv)
+{
+        FILE * fp;
+        char cmdbuf[128], value[32];
+        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,MAX_PIPE_BUFSIZE,fp) != NULL)
+            ;
+            // printf("value:%s\n", value);
+        else {
+            printf("ip wrong\n");
+            return FALSE;
+        }
+
+        pclose(fp);
+
+        if(strlen(value) < 10)
+            return FALSE;
+
+        strcpy(pv,value);
+        return TRUE;
+}
+
+int main(int argc, char const *argv[])
+{
+	char ipaddr[16],cmd_line[240];
+	if(!get_ip(ipaddr)) {
+		system("mpg123 -r 48000 /home/new-speaker/target/share/sounds/get_ip_failed.mp3");
+		return 0;
+	}
+
+	strcpy(cmd_line,"cd /home/new-speaker/target/share/sounds/;mpg123 -r 48000 ");
+
+	int i;
+	for (i=0;i<strlen(ipaddr);i++){
+		switch(ipaddr[i])
+		{
+			case '0':
+				strcat(cmd_line,"digit-0.mp3 ");
+				break;
+			case '1':
+				strcat(cmd_line,"digit-1.mp3 ");
+				break;
+			case '2':
+				strcat(cmd_line,"digit-2.mp3 ");
+				break;
+			case '3':
+				strcat(cmd_line,"digit-3.mp3 ");
+				break;
+			case '4':
+				strcat(cmd_line,"digit-4.mp3 ");
+				break;
+			case '5':
+				strcat(cmd_line,"digit-5.mp3 ");
+				break;
+			case '6':
+				strcat(cmd_line,"digit-6.mp3 ");
+				break;
+			case '7':
+				strcat(cmd_line,"digit-7.mp3 ");
+				break;
+			case '8':
+				strcat(cmd_line,"digit-8.mp3 ");
+				break;
+			case '9':
+				strcat(cmd_line,"digit-9.mp3 ");
+				break;
+			case '.':
+				strcat(cmd_line,"dian.mp3 ");
+				break;
+		}
+	}
+	// printf("cmd-line:%s\n", cmd_line);
+	system(cmd_line);
+
+	return 0;
+}

+ 21 - 0
Modules/serial_ctrl/Makefile

@@ -0,0 +1,21 @@
+TARGET = serial_ctrl
+# Dir2store = /opt/Rockchip/external/X10/etc/scripts
+objects = *.o
+CFLAGS = -lpthread -lhiredis -lm -liniparser -lcjson
+
+${TARGET}:
+	${CC} *.c -o $@ $(CFLAGS)
+
+%.o:%.c
+	${CC} -c $<
+
+.PHONY:clean install uninstall
+
+clean:
+	rm -f *.o ${TARGET}
+
+install:
+	cp -f ${TARGET} ${Dir2store}
+
+uninstall:
+	rm -f ${Dir2store}/${TARGET}

+ 170 - 0
Modules/serial_ctrl/log.c

@@ -0,0 +1,170 @@
+/*
+ * Copyright (c) 2020 rxi
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "log.h"
+
+#define MAX_CALLBACKS 32
+
+typedef struct {
+  log_LogFn fn;
+  void *udata;
+  int level;
+} Callback;
+
+static struct {
+  void *udata;
+  log_LockFn lock;
+  int level;
+  bool quiet;
+  Callback callbacks[MAX_CALLBACKS];
+} L;
+
+
+static const char *level_strings[] = {
+  "TRACE", "DEBUG", "INFO", "WARN", "ERROR", "FATAL"
+};
+
+#ifdef LOG_USE_COLOR
+static const char *level_colors[] = {
+  "\x1b[94m", "\x1b[36m", "\x1b[32m", "\x1b[33m", "\x1b[31m", "\x1b[35m"
+};
+#endif
+
+
+static void stdout_callback(log_Event *ev) {
+  char buf[16];
+  buf[strftime(buf, sizeof(buf), "%H:%M:%S", ev->time)] = '\0';
+#ifdef LOG_USE_COLOR
+  fprintf(
+    ev->udata, "%s %s%-5s\x1b[0m \x1b[90m%s:%d:\x1b[0m ",
+    buf, level_colors[ev->level], level_strings[ev->level],
+    ev->file, ev->line);
+#else
+  fprintf(
+    ev->udata, "%s %-5s %s:%d: ",
+    buf, level_strings[ev->level], ev->file, ev->line);
+#endif
+  vfprintf(ev->udata, ev->fmt, ev->ap);
+  fprintf(ev->udata, "\n");
+  fflush(ev->udata);
+}
+
+
+static void file_callback(log_Event *ev) {
+  char buf[64];
+  buf[strftime(buf, sizeof(buf), "%Y-%m-%d %H:%M:%S", ev->time)] = '\0';
+  fprintf(ev->udata, "%s,",buf);
+//  fprintf(
+//    ev->udata, "%s %-5s %s:%d: ",
+//    buf, level_strings[ev->level], ev->file, ev->line);
+  vfprintf(ev->udata, ev->fmt, ev->ap);
+  fprintf(ev->udata, "\n");
+  fflush(ev->udata);
+  fdatasync(fileno(ev->udata));
+}
+
+
+static void lock(void)   {
+  if (L.lock) { L.lock(true, L.udata); }
+}
+
+
+static void unlock(void) {
+  if (L.lock) { L.lock(false, L.udata); }
+}
+
+
+const char* log_level_string(int level) {
+  return level_strings[level];
+}
+
+
+void log_set_lock(log_LockFn fn, void *udata) {
+  L.lock = fn;
+  L.udata = udata;
+}
+
+
+void log_set_level(int level) {
+  L.level = level;
+}
+
+
+void log_set_quiet(bool enable) {
+  L.quiet = enable;
+}
+
+
+int log_add_callback(log_LogFn fn, void *udata, int level) {
+  for (int i = 0; i < MAX_CALLBACKS; i++) {
+    if (!L.callbacks[i].fn) {
+      L.callbacks[i] = (Callback) { fn, udata, level };
+      return 0;
+    }
+  }
+  return -1;
+}
+
+
+int log_add_fp(FILE *fp, int level) {
+  return log_add_callback(file_callback, fp, level);
+}
+
+
+static void init_event(log_Event *ev, void *udata) {
+  if (!ev->time) {
+    time_t t = time(NULL);
+    ev->time = localtime(&t);
+  }
+  ev->udata = udata;
+}
+
+
+void log_log(int level, const char *file, int line, const char *fmt, ...) {
+  log_Event ev = {
+    .fmt   = fmt,
+    .file  = file,
+    .line  = line,
+    .level = level,
+  };
+
+  lock();
+
+  if (!L.quiet && level >= L.level) {
+    init_event(&ev, stderr);
+    va_start(ev.ap, fmt);
+    stdout_callback(&ev);
+    va_end(ev.ap);
+  }
+
+  for (int i = 0; i < MAX_CALLBACKS && L.callbacks[i].fn; i++) {
+    Callback *cb = &L.callbacks[i];
+    if (level >= cb->level) {
+      init_event(&ev, cb->udata);
+      va_start(ev.ap, fmt);
+      cb->fn(&ev);
+      va_end(ev.ap);
+    }
+  }
+
+  unlock();
+}

+ 50 - 0
Modules/serial_ctrl/log.h

@@ -0,0 +1,50 @@
+/**
+ * Copyright (c) 2020 rxi
+ *
+ * This library is free software; you can redistribute it and/or modify it
+ * under the terms of the MIT license. See `log.c` for details.
+ */
+
+#ifndef LOG_H
+#define LOG_H
+
+#include <stdio.h>
+#include <stdarg.h>
+#include <stdbool.h>
+#include <time.h>
+#include <unistd.h>
+
+#define LOG_VERSION "0.1.0"
+
+typedef struct {
+  va_list ap;
+  const char *fmt;
+  const char *file;
+  struct tm *time;
+  void *udata;
+  int line;
+  int level;
+} log_Event;
+
+typedef void (*log_LogFn)(log_Event *ev);
+typedef void (*log_LockFn)(bool lock, void *udata);
+
+enum { LOG_TRACE, LOG_DEBUG, LOG_INFO, LOG_WARN, LOG_ERROR, LOG_FATAL };
+
+#define log_trace(...) log_log(LOG_TRACE, __FILE__, __LINE__, __VA_ARGS__)
+#define log_debug(...) log_log(LOG_DEBUG, __FILE__, __LINE__, __VA_ARGS__)
+#define log_info(...)  log_log(LOG_INFO,  __FILE__, __LINE__, __VA_ARGS__)
+#define log_warn(...)  log_log(LOG_WARN,  __FILE__, __LINE__, __VA_ARGS__)
+#define log_error(...) log_log(LOG_ERROR, __FILE__, __LINE__, __VA_ARGS__)
+#define log_fatal(...) log_log(LOG_FATAL, __FILE__, __LINE__, __VA_ARGS__)
+
+const char* log_level_string(int level);
+void log_set_lock(log_LockFn fn, void *udata);
+void log_set_level(int level);
+void log_set_quiet(bool enable);
+int log_add_callback(log_LogFn fn, void *udata, int level);
+int log_add_fp(FILE *fp, int level);
+
+void log_log(int level, const char *file, int line, const char *fmt, ...);
+
+#endif

Filskillnaden har hållts tillbaka eftersom den är för stor
+ 1197 - 0
Modules/serial_ctrl/main.c


+ 21 - 0
Modules/service_process/Makefile

@@ -0,0 +1,21 @@
+TARGET = service_process
+Dir2store = /opt/Rockchip/external/X10/etc/scripts
+objects = *.o
+CFLAGS = -lpthread -lhiredis -lm -lcjson -liniparser
+
+${TARGET}:$(objects)
+	${CC} log.c -o $@ $(objects) $(CFLAGS)
+
+%.o:%.c
+	${CC} -c main.c
+
+.PHONY:clean install uninstall
+
+clean:
+	rm -f *.o ${TARGET}
+
+install:
+	cp -f ${TARGET} ${Dir2store}
+
+uninstall:
+	rm -f ${Dir2store}/${TARGET}

Filskillnaden har hållts tillbaka eftersom den är för stor
+ 2741 - 0
Modules/service_process/main.c


BIN
Modules/sipconf/.DS_Store


+ 21 - 0
Modules/sipconf/Makefile

@@ -0,0 +1,21 @@
+TARGET = sipconf
+Dir2store = /opt/Rockchip/external/X10/etc/scripts
+objects = *.o
+CFLAGS = -lm -liniparser -lcjson
+
+${TARGET}:$(objects)
+	${CC} -o $@ $(objects) $(CFLAGS)
+
+%.o:%.c
+	${CC} -c $<
+
+.PHONY:clean install uninstall
+
+clean:
+	rm -f *.o ${TARGET}
+
+install:
+	cp -f ${TARGET} ${Dir2store}
+
+uninstall:
+	rm -f ${Dir2store}/${TARGET}

+ 905 - 0
Modules/sipconf/main.c

@@ -0,0 +1,905 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include "iniparser.h"
+
+#define Boolean     int
+#define TRUE        1
+#define FALSE       0
+#define ALSA_DEF    "alsa,default"
+#define ALSA_PLUGHW "alsa,default"
+#define SPK_CONF    "/oem/etc/speaker.conf"
+#define ACC_CONF    "/tmp/accounts"
+#define SPHONE_MODULE_CONF  "/tmp/config"
+
+struct sip_account
+{
+    char enable[8];
+    char username[64];
+    char authuser[64];
+    char domain[128];
+    char passwd[64];
+    char server[128];
+    char port[8];
+    char reg_expires[8];
+    char transport[8];
+    char autoanswer[8];
+    char sip_autoanswer[8];
+    char ringfile[64];
+    char nat_mode[16];
+    char stun_server[64];
+    char stun_port[8];
+    char nat_username[64];
+    char nat_password[64];
+    char keepalive[8];
+    char ka_interval[8];
+};
+
+struct sip_p2p
+{
+    char enable[8];
+    char username[64];
+    char auth[8];
+    char transport[8];
+    char autoanswer[8];
+    char sip_autoanswer[8];
+    char ringfile[64];
+};
+
+struct SPEAKER_CONF
+{
+    char hw_version[16];
+    char dev_type[32];
+    char version[16];
+    char mac[16];
+    char localport[8];
+    char startport[8];
+    char endport[8];
+    char rtptimeout[8];
+    char jbufftype[16];
+    struct sip_account acc1;
+    struct sip_account acc2;
+    struct sip_account acc3;
+    struct sip_p2p p2p;
+    char g722[8];
+    char alaw[8];
+    char ulaw[8];
+    char opus[8];
+    char g729[8];
+    char aec[8];
+    char anr[8];
+    char agc[8];
+    char cng[8];
+    char agc_max_gain[4];
+    char agc_gate_threshold[4];
+    char volume[4];
+    char end_beep[4];
+    char second_call[16];
+};
+
+/*
+*   @cmd 执行命令
+*   @value 命令结果指针
+*   @lenth 存储结果长度
+*/
+int GetCmdValue(char *cmd, char *value, int lenth)
+{
+    bzero(value, lenth);
+    FILE *fp = popen(cmd,"r");
+    if(fp){
+        fread(value, 1, lenth, fp);
+        pclose(fp);
+    } else {
+        printf("Handle \"%s\" failed.\n", cmd);
+        return FALSE;
+    }
+    return TRUE;
+}
+
+struct SPEAKER_CONF confParse()
+{
+    struct SPEAKER_CONF conf;
+	dictionary * ini ;
+	ini = iniparser_load(SPK_CONF);
+	
+    if (ini==NULL) {
+        fprintf(stderr, "cannot parse file: %s\n", SPK_CONF);
+        exit(-1);
+    }
+	strcpy(conf.dev_type, iniparser_getstring(ini, "system:model", ""));
+	strcpy(conf.hw_version, iniparser_getstring(ini, "system:hard_version", ""));
+	strcpy(conf.version, iniparser_getstring(ini, "system:firmware", ""));
+    GetCmdValue("ifconfig eth0 | grep HWaddr | awk '{print $5}' | tr -d ':' | tr -d '\n'",conf.mac, sizeof(conf.mac));
+	strcpy(conf.localport, iniparser_getstring(ini, "sip_advance:localport", ""));
+	strcpy(conf.startport, iniparser_getstring(ini, "sip_advance:rtpstartport", ""));
+	strcpy(conf.endport, iniparser_getstring(ini, "sip_advance:rtpendport", ""));
+	strcpy(conf.rtptimeout, iniparser_getstring(ini, "sip_advance:rtptimeout", ""));
+	strcpy(conf.jbufftype, iniparser_getstring(ini, "sip_advance:jbufftype", "off"));
+	strcpy(conf.acc1.enable, iniparser_getstring(ini, "account_info_1:enable", "no"));
+    if(strcmp(conf.acc1.enable, "yes") == 0)
+    {
+        strcpy(conf.acc1.username, iniparser_getstring(ini, "account_info_1:username", ""));
+        strcpy(conf.acc1.authuser, iniparser_getstring(ini, "account_info_1:authuser", ""));
+        if(strlen(conf.acc1.authuser) == 0)
+        {
+            strcpy(conf.acc1.authuser, conf.acc1.username);
+        }
+        GetCmdValue("sysconf /etc/speaker.conf get account_info_1 passwd", conf.acc1.passwd, sizeof(conf.acc1.passwd));
+        //strcpy(conf.acc1.passwd, iniparser_getstring(ini, "account_info_1:passwd", ""));
+        strcpy(conf.acc1.server, iniparser_getstring(ini, "account_info_1:server", ""));
+        strcpy(conf.acc1.port, iniparser_getstring(ini, "account_info_1:port", ""));
+        strcpy(conf.acc1.domain, iniparser_getstring(ini, "account_info_1:domain", ""));
+        if(strlen(conf.acc1.domain) == 0)
+        {
+            strcpy(conf.acc1.domain, conf.acc1.server);
+        }
+        strcpy(conf.acc1.reg_expires, iniparser_getstring(ini, "account_info_1:reg_expires", ""));
+        strcpy(conf.acc1.transport, iniparser_getstring(ini, "account_info_1:transport", ""));
+        strcpy(conf.acc1.autoanswer, iniparser_getstring(ini, "account_info_1:autoanswer", ""));
+        strcpy(conf.acc1.sip_autoanswer, iniparser_getstring(ini, "account_info_1:sip_autoanswer", "yes"));
+        strcpy(conf.acc1.ringfile, iniparser_getstring(ini, "account_info_1:ringfile", ""));
+        strcpy(conf.acc1.nat_mode, iniparser_getstring(ini, "account_info_1:nat_mode", "disabled"));
+        strcpy(conf.acc1.stun_server, iniparser_getstring(ini, "account_info_1:stun_server", ""));
+        strcpy(conf.acc1.stun_port, iniparser_getstring(ini, "account_info_1:stun_port", "3478"));
+        strcpy(conf.acc1.nat_username, iniparser_getstring(ini, "account_info_1:nat_username", ""));
+        strcpy(conf.acc1.nat_password, iniparser_getstring(ini, "account_info_1:nat_password", ""));
+        strcpy(conf.acc1.keepalive, iniparser_getstring(ini, "account_info_1:keepalive", "yes"));
+        strcpy(conf.acc1.ka_interval, iniparser_getstring(ini, "account_info_1:keepalive_interval", "30"));
+    }
+	
+	strcpy(conf.acc2.enable, iniparser_getstring(ini, "account_info_2:enable", "no"));
+    if(strcmp(conf.acc2.enable, "yes") == 0)
+    {
+        strcpy(conf.acc2.username, iniparser_getstring(ini, "account_info_2:username", ""));
+        strcpy(conf.acc2.authuser, iniparser_getstring(ini, "account_info_2:authuser", ""));
+        if(strlen(conf.acc2.authuser) == 0)
+        {
+            strcpy(conf.acc2.authuser, conf.acc2.username);
+        }
+        GetCmdValue("sysconf /etc/speaker.conf get account_info_2 passwd", conf.acc2.passwd, sizeof(conf.acc2.passwd));
+        //strcpy(conf.acc2.passwd, iniparser_getstring(ini, "account_info_2:passwd", ""));
+        strcpy(conf.acc2.server, iniparser_getstring(ini, "account_info_2:server", ""));
+        strcpy(conf.acc2.port, iniparser_getstring(ini, "account_info_2:port", ""));
+        strcpy(conf.acc2.domain, iniparser_getstring(ini, "account_info_2:domain", ""));
+        if(strlen(conf.acc2.domain) == 0)
+        {
+            strcpy(conf.acc2.domain, conf.acc2.server);
+        }
+        strcpy(conf.acc2.reg_expires, iniparser_getstring(ini, "account_info_2:reg_expires", ""));
+        strcpy(conf.acc2.transport, iniparser_getstring(ini, "account_info_2:transport", ""));
+        strcpy(conf.acc2.autoanswer, iniparser_getstring(ini, "account_info_2:autoanswer", ""));
+        strcpy(conf.acc2.sip_autoanswer, iniparser_getstring(ini, "account_info_2:sip_autoanswer", "yes"));
+        strcpy(conf.acc2.ringfile, iniparser_getstring(ini, "account_info_2:ringfile", ""));
+        strcpy(conf.acc2.nat_mode, iniparser_getstring(ini, "account_info_2:nat_mode", "disabled"));
+        strcpy(conf.acc2.stun_server, iniparser_getstring(ini, "account_info_2:stun_server", ""));
+        strcpy(conf.acc2.stun_port, iniparser_getstring(ini, "account_info_2:stun_port", "3478"));
+        strcpy(conf.acc2.nat_username, iniparser_getstring(ini, "account_info_2:nat_username", ""));
+        strcpy(conf.acc2.nat_password, iniparser_getstring(ini, "account_info_2:nat_password", ""));
+        strcpy(conf.acc2.keepalive, iniparser_getstring(ini, "account_info_2:keepalive", "yes"));
+        strcpy(conf.acc2.ka_interval, iniparser_getstring(ini, "account_info_2:keepalive_interval", "30"));
+    }
+	strcpy(conf.acc3.enable, iniparser_getstring(ini, "account_info_3:enable", "no"));
+    if(strcmp(conf.acc3.enable, "yes") == 0)
+    {
+        strcpy(conf.acc3.username, iniparser_getstring(ini, "account_info_3:username", ""));
+        strcpy(conf.acc3.authuser, iniparser_getstring(ini, "account_info_3:authuser", ""));
+        if(strlen(conf.acc3.authuser) == 0)
+        {
+            strcpy(conf.acc3.authuser, conf.acc3.username);
+        }
+        GetCmdValue("sysconf /etc/speaker.conf get account_info_3 passwd", conf.acc3.passwd, sizeof(conf.acc3.passwd));
+        //strcpy(conf.acc3.passwd, iniparser_getstring(ini, "account_info_3:passwd", ""));
+        strcpy(conf.acc3.server, iniparser_getstring(ini, "account_info_3:server", ""));
+        strcpy(conf.acc3.port, iniparser_getstring(ini, "account_info_3:port", ""));
+        strcpy(conf.acc3.domain, iniparser_getstring(ini, "account_info_3:domain", ""));
+        if(strlen(conf.acc3.domain) == 0)
+        {
+            strcpy(conf.acc3.domain, conf.acc3.server);
+        }
+        strcpy(conf.acc3.reg_expires, iniparser_getstring(ini, "account_info_3:reg_expires", ""));
+        strcpy(conf.acc3.transport, iniparser_getstring(ini, "account_info_3:transport", ""));
+        strcpy(conf.acc3.autoanswer, iniparser_getstring(ini, "account_info_3:autoanswer", ""));
+        strcpy(conf.acc3.sip_autoanswer, iniparser_getstring(ini, "account_info_3:sip_autoanswer", "yes"));
+        strcpy(conf.acc3.ringfile, iniparser_getstring(ini, "account_info_3:ringfile", ""));
+        strcpy(conf.acc3.nat_mode, iniparser_getstring(ini, "account_info_3:nat_mode", "disabled"));
+        strcpy(conf.acc3.stun_server, iniparser_getstring(ini, "account_info_3:stun_server", ""));
+        strcpy(conf.acc3.stun_port, iniparser_getstring(ini, "account_info_3:stun_port", "3478"));
+        strcpy(conf.acc3.nat_username, iniparser_getstring(ini, "account_info_3:nat_username", ""));
+        strcpy(conf.acc3.nat_password, iniparser_getstring(ini, "account_info_3:nat_password", ""));
+        strcpy(conf.acc3.keepalive, iniparser_getstring(ini, "account_info_3:keepalive", "yes"));
+        strcpy(conf.acc3.ka_interval, iniparser_getstring(ini, "account_info_3:keepalive_interval", "30"));
+    }
+	strcpy(conf.p2p.enable, iniparser_getstring(ini, "account_info_p2p:enable", "no"));
+	strcpy(conf.p2p.username, iniparser_getstring(ini, "account_info_p2p:username", ""));
+	strcpy(conf.p2p.auth, iniparser_getstring(ini, "account_info_p2p:auth", "no"));
+	strcpy(conf.p2p.transport, iniparser_getstring(ini, "account_info_p2p:transport", ""));
+	strcpy(conf.p2p.autoanswer, iniparser_getstring(ini, "account_info_p2p:autoanswer", ""));
+	strcpy(conf.p2p.sip_autoanswer, iniparser_getstring(ini, "account_info_p2p:sip_autoanswer", "yes"));
+	strcpy(conf.p2p.ringfile, iniparser_getstring(ini, "account_info_p2p:ringfile", ""));
+	strcpy(conf.g722, iniparser_getstring(ini, "codec:g722", "yes"));
+	strcpy(conf.alaw, iniparser_getstring(ini, "codec:alaw", "yes"));
+	strcpy(conf.ulaw, iniparser_getstring(ini, "codec:ulaw", "yes"));
+	strcpy(conf.opus, iniparser_getstring(ini, "codec:opus", "no"));
+	strcpy(conf.g729, iniparser_getstring(ini, "codec:g729", "no"));
+	strcpy(conf.aec, iniparser_getstring(ini, "sip_advance:echocancel", "yes"));
+	strcpy(conf.anr, iniparser_getstring(ini, "sip_advance:anr", "yes"));
+	strcpy(conf.agc, iniparser_getstring(ini, "sip_advance:agc", "no"));
+	strcpy(conf.agc_max_gain, iniparser_getstring(ini, "sip_advance:agc_max_gain", "30"));
+	strcpy(conf.agc_gate_threshold, iniparser_getstring(ini, "sip_advance:agc_gate_threshold", "-65"));
+	strcpy(conf.cng, iniparser_getstring(ini, "sip_advance:cng", "no"));
+	strcpy(conf.end_beep, iniparser_getstring(ini, "sip_function:hangup_beep", "no"));
+	strcpy(conf.second_call, iniparser_getstring(ini, "sip_function:second_call", "hangup"));
+    GetCmdValue("sysconf /oem/etc/volctrl.conf get volume sip_volume",conf.volume, sizeof(conf.volume));
+    if(strlen(conf.volume) == 0)
+    {
+        strcpy(conf.volume, "90");
+    }
+    
+	iniparser_freedict(ini);
+
+    return conf;
+}
+
+int main(int argc, char *argv[]){
+    char audio_src[32], lport_line[32] = "", acc1_answermode[32], acc2_answermode[32], acc3_answermode[32], p2p_answermode[32],\
+    acc1_natstring[256] = "", acc2_natstring[256] = "", acc3_natstring[256] = "", acc1_extrastring[64] = "", acc2_extrastring[64] = "",\
+    acc3_extrastring[64] = "", nat_tmp[256], codecs[64], localip[32], sec_call[128] = "";
+	struct SPEAKER_CONF conf;
+	
+    conf = confParse();
+
+    FILE *phone_modules_fp = fopen(SPHONE_MODULE_CONF, "w+");
+    if (phone_modules_fp == NULL){
+        perror("Open phone module conf file Error: ");
+        exit(1);
+    }
+
+//    if(strcmp(conf.echocancel,"yes") == 0)
+//    {
+//        strcpy(audio_src,ALSA_DEF);
+//    }
+//    else
+//    {
+        strcpy(audio_src,ALSA_PLUGHW);
+//    }
+    
+
+    if(strlen(conf.localport) != 0 && strcmp(conf.localport,"0") != 0)
+    {
+        sprintf(lport_line,"sip_listen		0.0.0.0:%s", conf.localport);
+    }
+    if(strcmp(conf.second_call, "hangup") == 0)
+    {
+        sprintf(sec_call, "call_max_calls          1");
+    }
+    else if(strcmp(conf.second_call, "hold") == 0)
+    {
+        sprintf(sec_call, "call_max_calls          2");
+    }
+    else if(strcmp(conf.second_call, "merge") == 0)
+    {
+        sprintf(sec_call, "\
+call_max_calls          2\n\
+call_hold_other_calls   no");
+    }
+    else
+    {
+        sprintf(sec_call, "call_max_calls          1");
+    }
+
+    fprintf(phone_modules_fp, "\
+poll_method             epoll\n\
+%s\n\
+sip_certificate         /etc/ssl/certs/cert.pem\n\
+\n\
+call_local_timeout      120\n\
+%s\n\
+\n\
+# Audio\n\
+audio_path              /usr/share/baresip\n\
+audio_player            alsa,default\n\
+audio_source            %s\n\
+audio_alert             alsa,default\n\
+auplay_channels         1\n\
+audio_level             no\n\
+ausrc_format            s16\n\
+auplay_format           s16\n\
+auenc_format            s16\n\
+audec_format            s16\n\
+audio_buffer            20-120\n\
+audio_buffer_mode       adaptive\n\
+\n\
+# AVT - Audio/Video Transport\n\
+rtp_tos                 184\n\
+rtp_ports               %s-%s\n\
+rtcp_mux                no\n\
+audio_jitter_buffer_type      %s\n\
+audio_jitter_buffer_delay     0-6\n\
+rtp_stats               no\n\
+rtp_timeout             %s\n\
+\n\
+#------------------------------------------------------------------------------\n\
+# Speaker\n\
+model                   %s\n\
+version                 %s\n\
+dev_mac                 %s\n\
+au_en_aec               %s\n\
+au_en_anr               %s\n\
+au_en_anr_out           no\n\
+au_en_agc               %s\n\
+agc_max_gain            %s\n\
+agc_gate_threshold      %s\n\
+au_en_cng               %s\n\
+volume                  %s\n\
+end_beep                %s\n\
+\n\
+#------------------------------------------------------------------------------\n\
+# Modules\n\
+\n\
+module_path             /usr/lib/baresip/modules\n\
+\n\
+# UI Modules\n\
+module                  stdio.so\n\
+module                  cons.so\n\
+\n\
+# Audio codec Modules (in order)\n\
+module                  opus.so\n\
+module                  g722.so\n\
+module                  g711.so\n\
+\n\
+# Audio driver Modules\n\
+module                  alsa.so\n\
+\n\
+# Audio filter Modules\n\
+module                  aufile.so\n\
+module                  mixausrc.so\n\
+\n\
+# Media NAT modules\n\
+module                  stun.so\n\
+module                  turn.so\n\
+module                  ice.so\n\
+\n\
+#------------------------------------------------------------------------------\n\
+# Compatibility modules\n\
+\n\
+module                  uuid.so\n\
+\n\
+#------------------------------------------------------------------------------\n\
+# Application Modules\n\
+\n\
+module_app              account.so\n\
+module_app              auloop.so\n\
+module_app              menu.so\n\
+module_app              ctrl_tcp.so\n\
+module_app              debug_cmd.so\n\
+module_app		        kaoptions.so\n\
+\n\
+#------------------------------------------------------------------------------\n\
+# Module parameters\n\
+\n\
+# UI Modules parameters\n\
+ctrl_tcp_listen         127.0.0.1:4444\n\
+cons_listen             127.0.0.1:5555\n\
+\n\
+# Opus codec parameters\n\
+opus_bitrate            128000\n\
+opus_stereo             no\n\
+\n\
+",\
+lport_line,\
+sec_call,\
+audio_src,\
+conf.startport,\
+conf.endport,\
+conf.jbufftype,\
+conf.rtptimeout,\
+conf.dev_type,\
+conf.version,\
+conf.mac,\
+conf.aec,\
+conf.anr,\
+conf.agc,\
+conf.agc_max_gain,\
+conf.agc_gate_threshold,\
+conf.cng,\
+conf.volume,\
+conf.end_beep
+);
+    FILE *acc_conf_fp = fopen(ACC_CONF, "w+");
+    if (acc_conf_fp == NULL){
+        perror("Open accounts conf file Error: ");
+        exit(1);
+    }
+
+    if(strcmp(conf.acc1.enable, "yes") == 0)
+    {
+        if(strcmp(conf.acc1.autoanswer, "yes") == 0)
+        {
+            strcpy(acc1_answermode, "auto");
+        }
+        else if(strcmp(conf.acc1.autoanswer, "no") == 0)
+        {
+            strcpy(acc1_answermode, "manual");
+        }
+        else
+        {
+            sprintf(acc1_answermode, "manual;answerdelay=%d", (int) (atof(conf.acc1.autoanswer)*1000));
+        }
+        
+        memset(codecs, 0, sizeof(codecs));
+        if(strcmp(conf.g722, "yes") == 0)
+        {
+            strcpy(codecs,"g722/16000/1");
+        }
+
+        if(strcmp(conf.alaw, "yes") == 0)
+        {
+            if(strlen(codecs))
+            {
+                strcat(codecs,",pcma");
+            }
+            else
+            {
+                strcpy(codecs,"pcma");
+            }
+        }
+
+        if(strcmp(conf.ulaw, "yes") == 0)
+        {
+            if(strlen(codecs))
+            {
+                strcat(codecs,",pcmu");
+            }
+            else
+            {
+                strcpy(codecs,"pcmu");
+            }
+        }
+
+        if(strcmp(conf.opus, "yes") == 0)
+        {
+            if(strlen(codecs))
+            {
+                strcat(codecs,",opus/48000/1");
+            }
+            else
+            {
+                strcpy(codecs,"opus/48000/1");
+            }
+        }
+
+        if(strcmp(conf.g729, "yes") == 0)
+        {
+            if(strlen(codecs))
+            {
+                strcat(codecs,",g729");
+            }
+            else
+            {
+                strcpy(codecs,"g729");
+            }
+        }
+
+        if(strcmp(conf.acc1.nat_mode, "stun") == 0)
+        {
+            sprintf(acc1_natstring, ";medianat=stun;stunserver=\"stun:%s:%s\"", conf.acc1.stun_server, conf.acc1.stun_port);
+        }
+        else if(strcmp(conf.acc1.nat_mode, "turn") == 0)
+        {
+            sprintf(acc1_natstring, ";medianat=turn;stunserver=\"turn:%s:%s\";stunuser=%s;stunpass=%s", conf.acc1.stun_server, conf.acc1.stun_port, conf.acc1.nat_username, conf.acc1.nat_password);
+        }
+        else if(strcmp(conf.acc1.nat_mode, "ice") == 0)
+        {
+            strcpy(acc1_natstring, ";medianat=ice");
+            if(strlen(conf.acc1.stun_server) != 0)
+            {
+                if(strlen(conf.acc1.nat_username) != 0)
+                {
+                    memset(nat_tmp,0,sizeof(nat_tmp));
+                    sprintf(nat_tmp, ";stunserver=\"turn:%s:%s\";stunuser=%s;stunpass=%s", conf.acc1.stun_server, conf.acc1.stun_port, conf.acc1.nat_username, conf.acc1.nat_password);
+                    strcat(acc1_natstring, nat_tmp);
+                }
+                else
+                {
+                    memset(nat_tmp,0,sizeof(nat_tmp));
+                    sprintf(nat_tmp, ";stunserver=\"stun:%s:%s\"", conf.acc1.stun_server, conf.acc1.stun_port);
+                    strcat(acc1_natstring, nat_tmp);
+                }
+            }
+        }
+        if(strcmp(conf.acc1.keepalive, "yes") == 0)
+        {
+            sprintf(acc1_extrastring,";extra=kaoptions=%s",conf.acc1.ka_interval);
+        }
+        if(strlen(conf.acc1.domain) == 0)
+        {
+            strcpy(conf.acc1.domain,conf.acc1.server);
+        }
+        
+        fprintf(acc_conf_fp, "\
+<sip:%s@%s>%s%s;auth_user=%s;auth_pass=%s;outbound=\"sip:%s:%s;transport=%s\";answermode=%s;sip_autoanswer=%s;audio_codecs=%s;regint=%s;rwait=50;ringfile=%s\n\
+",\
+conf.acc1.username,\
+conf.acc1.domain,\
+acc1_natstring,\
+acc1_extrastring,\
+conf.acc1.authuser,\
+conf.acc1.passwd,\
+conf.acc1.server,\
+conf.acc1.port,\
+conf.acc1.transport,\
+acc1_answermode,\
+conf.acc1.sip_autoanswer,\
+codecs,\
+conf.acc1.reg_expires,\
+conf.acc1.ringfile\
+);
+    }
+
+    if(strcmp(conf.acc2.enable, "yes") == 0)
+    {
+        if(strcmp(conf.acc2.autoanswer, "yes") == 0)
+        {
+            strcpy(acc2_answermode, "auto");
+        }
+        else if(strcmp(conf.acc2.autoanswer, "no") == 0)
+        {
+            strcpy(acc2_answermode, "manual");
+        }
+        else
+        {
+            sprintf(acc2_answermode, "manual;answerdelay=%d", (int) (atof(conf.acc2.autoanswer)*1000));
+        }
+        
+        memset(codecs, 0, sizeof(codecs));
+        if(strcmp(conf.g722, "yes") == 0)
+        {
+            strcpy(codecs,"g722/16000/1");
+        }
+
+        if(strcmp(conf.alaw, "yes") == 0)
+        {
+            if(strlen(codecs))
+            {
+                strcat(codecs,",pcma");
+            }
+            else
+            {
+                strcpy(codecs,"pcma");
+            }
+        }
+
+        if(strcmp(conf.ulaw, "yes") == 0)
+        {
+            if(strlen(codecs))
+            {
+                strcat(codecs,",pcmu");
+            }
+            else
+            {
+                strcpy(codecs,"pcmu");
+            }
+        }
+
+        if(strcmp(conf.opus, "yes") == 0)
+        {
+            if(strlen(codecs))
+            {
+                strcat(codecs,",opus/48000/1");
+            }
+            else
+            {
+                strcpy(codecs,"opus/48000/1");
+            }
+        }
+
+        if(strcmp(conf.g729, "yes") == 0)
+        {
+            if(strlen(codecs))
+            {
+                strcat(codecs,",g729");
+            }
+            else
+            {
+                strcpy(codecs,"g729");
+            }
+        }
+
+        if(strcmp(conf.acc2.nat_mode, "stun") == 0)
+        {
+            sprintf(acc2_natstring, ";medianat=stun;stunserver=\"stun:%s:%s\"", conf.acc2.stun_server, conf.acc2.stun_port);
+        }
+        else if(strcmp(conf.acc2.nat_mode, "turn") == 0)
+        {
+            sprintf(acc2_natstring, ";medianat=turn;stunserver=\"turn:%s:%s\";stunuser=%s;stunpass=%s", conf.acc2.stun_server, conf.acc2.stun_port, conf.acc2.nat_username, conf.acc2.nat_password);
+        }
+        else if(strcmp(conf.acc2.nat_mode, "ice") == 0)
+        {
+            strcpy(acc2_natstring, ";medianat=ice");
+            if(strlen(conf.acc2.stun_server) != 0)
+            {
+                if(strlen(conf.acc2.nat_username) != 0)
+                {
+                    memset(nat_tmp,0,sizeof(nat_tmp));
+                    sprintf(nat_tmp, ";stunserver=\"turn:%s:%s\";stunuser=%s;stunpass=%s", conf.acc2.stun_server, conf.acc2.stun_port, conf.acc2.nat_username, conf.acc2.nat_password);
+                    strcat(acc2_natstring, nat_tmp);
+                }
+                else
+                {
+                    memset(nat_tmp,0,sizeof(nat_tmp));
+                    sprintf(nat_tmp, ";stunserver=\"stun:%s:%s\"", conf.acc2.stun_server, conf.acc2.stun_port);
+                    strcat(acc2_natstring, nat_tmp);
+                }
+            }
+        }
+        if(strcmp(conf.acc2.keepalive, "yes") == 0)
+        {
+            sprintf(acc2_extrastring,";extra=kaoptions=%s",conf.acc2.ka_interval);
+        }
+        if(strlen(conf.acc2.domain) == 0)
+        {
+            strcpy(conf.acc2.domain,conf.acc2.server);
+        }
+        
+        fprintf(acc_conf_fp, "\
+<sip:%s@%s>%s%s;auth_user=%s;auth_pass=%s;outbound=\"sip:%s:%s;transport=%s\";answermode=%s;sip_autoanswer=%s;audio_codecs=%s;regint=%s;rwait=50;ringfile=%s\n\
+",\
+conf.acc2.username,\
+conf.acc2.domain,\
+acc2_natstring,\
+acc2_extrastring,\
+conf.acc2.authuser,\
+conf.acc2.passwd,\
+conf.acc2.server,\
+conf.acc2.port,\
+conf.acc2.transport,\
+acc2_answermode,\
+conf.acc2.sip_autoanswer,\
+codecs,\
+conf.acc2.reg_expires,\
+conf.acc2.ringfile\
+);
+    }
+
+    if(strcmp(conf.acc3.enable, "yes") == 0)
+    {
+        if(strcmp(conf.acc3.autoanswer, "yes") == 0)
+        {
+            strcpy(acc3_answermode, "auto");
+        }
+        else if(strcmp(conf.acc3.autoanswer, "no") == 0)
+        {
+            strcpy(acc3_answermode, "manual");
+        }
+        else
+        {
+            sprintf(acc3_answermode, "manual;answerdelay=%d", (int) (atof(conf.acc3.autoanswer)*1000));
+        }
+        
+        memset(codecs, 0, sizeof(codecs));
+        if(strcmp(conf.g722, "yes") == 0)
+        {
+            strcpy(codecs,"g722/16000/1");
+        }
+
+        if(strcmp(conf.alaw, "yes") == 0)
+        {
+            if(strlen(codecs))
+            {
+                strcat(codecs,",pcma");
+            }
+            else
+            {
+                strcpy(codecs,"pcma");
+            }
+            
+        }
+
+        if(strcmp(conf.ulaw, "yes") == 0)
+        {
+            if(strlen(codecs))
+            {
+                strcat(codecs,",pcmu");
+            }
+            else
+            {
+                strcpy(codecs,"pcmu");
+            }
+            
+        }
+
+        if(strcmp(conf.opus, "yes") == 0)
+        {
+            if(strlen(codecs))
+            {
+                strcat(codecs,",opus/48000/1");
+            }
+            else
+            {
+                strcpy(codecs,"opus/48000/1");
+            }
+        }
+
+        if(strcmp(conf.g729, "yes") == 0)
+        {
+            if(strlen(codecs))
+            {
+                strcat(codecs,",g729");
+            }
+            else
+            {
+                strcpy(codecs,"g729");
+            }
+        }
+
+        if(strcmp(conf.acc3.nat_mode, "stun") == 0)
+        {
+            sprintf(acc3_natstring, ";medianat=stun;stunserver=\"stun:%s:%s\"", conf.acc3.stun_server, conf.acc3.stun_port);
+        }
+        else if(strcmp(conf.acc3.nat_mode, "turn") == 0)
+        {
+            sprintf(acc3_natstring, ";medianat=turn;stunserver=\"turn:%s:%s\";stunuser=%s;stunpass=%s", conf.acc3.stun_server, conf.acc3.stun_port, conf.acc3.nat_username, conf.acc3.nat_password);
+        }
+        else if(strcmp(conf.acc3.nat_mode, "ice") == 0)
+        {
+            strcpy(acc3_natstring, ";medianat=ice");
+            if(strlen(conf.acc3.stun_server) != 0)
+            {
+                if(strlen(conf.acc3.nat_username) != 0)
+                {
+                    memset(nat_tmp,0,sizeof(nat_tmp));
+                    sprintf(nat_tmp, ";stunserver=\"turn:%s:%s\";stunuser=%s;stunpass=%s", conf.acc3.stun_server, conf.acc3.stun_port, conf.acc3.nat_username, conf.acc3.nat_password);
+                    strcat(acc3_natstring, nat_tmp);
+                }
+                else
+                {
+                    memset(nat_tmp,0,sizeof(nat_tmp));
+                    sprintf(nat_tmp, ";stunserver=\"stun:%s:%s\"", conf.acc3.stun_server, conf.acc3.stun_port);
+                    strcat(acc3_natstring, nat_tmp);
+                }
+                
+            }
+        }
+        if(strcmp(conf.acc3.keepalive, "yes") == 0)
+        {
+            sprintf(acc3_extrastring,";extra=kaoptions=%s",conf.acc3.ka_interval);
+        }
+        if(strlen(conf.acc3.domain) == 0)
+        {
+            strcpy(conf.acc3.domain,conf.acc3.server);
+        }
+        
+        fprintf(acc_conf_fp, "\
+<sip:%s@%s>%s%s;auth_user=%s;auth_pass=%s;outbound=\"sip:%s:%s;transport=%s\";answermode=%s;sip_autoanswer=%s;audio_codecs=%s;regint=%s;rwait=50;ringfile=%s\n\
+",\
+conf.acc3.username,\
+conf.acc3.domain,\
+acc3_natstring,\
+acc3_extrastring,\
+conf.acc3.authuser,\
+conf.acc3.passwd,\
+conf.acc3.server,\
+conf.acc3.port,\
+conf.acc3.transport,\
+acc3_answermode,\
+conf.acc3.sip_autoanswer,\
+codecs,\
+conf.acc3.reg_expires,\
+conf.acc3.ringfile\
+);
+    }
+
+    if(strcmp(conf.p2p.enable, "yes") == 0)
+    {
+        if(strcmp(conf.p2p.autoanswer, "yes") == 0)
+        {
+            strcpy(p2p_answermode, "auto");
+        }
+        else if(strcmp(conf.p2p.autoanswer, "no") == 0)
+        {
+            strcpy(p2p_answermode, "manual");
+        }
+        else
+        {
+            sprintf(p2p_answermode, "manual;answerdelay=%d", (int) (atof(conf.p2p.autoanswer)*1000));
+        }
+        
+        memset(codecs, 0, sizeof(codecs));
+        if(strcmp(conf.g722, "yes") == 0)
+        {
+            strcpy(codecs,"g722/16000/1");
+        }
+
+        if(strcmp(conf.alaw, "yes") == 0)
+        {
+            if(strlen(codecs))
+            {
+                strcat(codecs,",pcma");
+            }
+            else
+            {
+                strcpy(codecs,"pcma");
+            }
+            
+        }
+
+        if(strcmp(conf.ulaw, "yes") == 0)
+        {
+            if(strlen(codecs))
+            {
+                strcat(codecs,",pcmu");
+            }
+            else
+            {
+                strcpy(codecs,"pcmu");
+            }
+            
+        }
+
+        if(strcmp(conf.opus, "yes") == 0)
+        {
+            if(strlen(codecs))
+            {
+                strcat(codecs,",opus/48000/1");
+            }
+            else
+            {
+                strcpy(codecs,"opus/48000/1");
+            }
+            
+        }
+
+        if(strcmp(conf.g729, "yes") == 0)
+        {
+            if(strlen(codecs))
+            {
+                strcat(codecs,",g729");
+            }
+            else
+            {
+                strcpy(codecs,"g729");
+            }
+        }
+
+        GetCmdValue("/sbin/ifconfig eth0 | grep 'inet addr' | cut -d':' -f2 | cut -d' ' -f1", localip, sizeof(localip));
+        
+        if(strlen(localip) == 0)
+        {
+            memset(localip, 0, sizeof(localip));
+            strcpy(localip,"127.0.0.1");
+        }
+        else
+        {
+            localip[strlen(localip) - 1] = '\0';
+        }
+        if(strcmp(conf.p2p.auth,"yes") == 0)
+            fprintf(acc_conf_fp, "\
+<sip:%s@%s:%s;transport=%s>;answermode=%s;sip_autoanswer=%s;audio_codecs=%s;regint=0;ringfile=%s\n\
+",\
+conf.p2p.username,\
+localip,\
+conf.localport,\
+conf.p2p.transport,\
+p2p_answermode,\
+conf.p2p.sip_autoanswer,\
+codecs,\
+conf.p2p.ringfile\
+);
+        else
+            fprintf(acc_conf_fp, "\
+<sip:%s:%s;transport=%s>;answermode=%s;sip_autoanswer=%s;audio_codecs=%s;regint=0;ringfile=%s\n\
+",\
+localip,\
+conf.localport,\
+conf.p2p.transport,\
+p2p_answermode,\
+conf.p2p.sip_autoanswer,\
+codecs,\
+conf.p2p.ringfile\
+);
+    }
+
+fclose(phone_modules_fp);
+fclose(acc_conf_fp);
+}

+ 22 - 0
Modules/watch_gpio/Makefile

@@ -0,0 +1,22 @@
+TARGET = watch_gpio
+GIT_DIR = /opt/Rockchip/external/X10
+Dir2store = ${GIT_DIR}/etc/scripts
+CFLAGS =
+
+${TARGET}:*.o
+	${CC} -o $@ ${CFLAGS} $<
+
+%.o:%.c
+	${CC} -c $<
+
+.PHONY:clean install uninstall
+
+clean:
+	rm -f *.o ${TARGET}
+
+install:
+	cp -f ${TARGET} ${Dir2store}
+
+uninstall:
+	rm -f ${Dir2store}/${TARGET}
+

+ 304 - 0
Modules/watch_gpio/main.c

@@ -0,0 +1,304 @@
+/*
+*   X10 IP播报和出厂设置检测程序
+*   2019.7.30 lpc
+*
+*   Intercom device Funtions: Dial && PlayIP
+*   Speaker device Funtions: PlayIP && FactoryREST
+*/
+
+#include <sys/poll.h>
+#include <string.h>
+#include <signal.h>
+#include <sys/time.h>
+#include <time.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <pthread.h>
+
+#define Boolean int
+#define TRUE    1
+#define FALSE   0
+#define MAX_PIPE_BUFSIZE    256
+
+static int playip_lock = FALSE;
+static int press_down = FALSE;
+
+static enum devType
+{
+    INTERCOM = 0,
+    SPEAKER
+};
+
+static int devType;
+
+Boolean get_ip(char * pv)
+{
+        FILE * fp;
+        char cmdbuf[128], value[32];
+        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,MAX_PIPE_BUFSIZE,fp) != NULL)
+            ;
+            // printf("value:%s\n", value);
+        else {
+            printf("ip wrong\n");
+            return FALSE;
+        }
+
+        pclose(fp);
+
+        if(strlen(value) < 10)
+            return FALSE;
+
+        strcpy(pv,value);
+        return TRUE;
+}
+
+int PlayIP()
+{
+    //add by ssc 2019-12-26
+    char language[32];
+    FILE *fp = popen("sysconf /etc/speaker.conf get system language","r");
+    if(!fp)
+        perror("popen wrong");
+    bzero(language,sizeof(language));
+    fread(language,1,sizeof(language),fp);
+    pclose(fp);
+    language[strlen(language)] = '\0';
+
+    playip_lock = TRUE;
+    char ipaddr[16],cmd_line[240];
+    if(!get_ip(ipaddr)) {
+        if (strcmp(language, "en") == 0){
+            system("mpg123 -r 48000 /home/new-speaker/target/share/sounds/en/get_ip_failed.mp3");
+        }else{
+            system("mpg123 -r 48000 /home/new-speaker/target/share/sounds/cn/get_ip_failed.mp3");
+        }
+        return 0;
+    }
+
+    if (strcmp(language, "en") == 0){
+        strcpy(cmd_line,"cd /home/new-speaker/target/share/sounds/en/;mpg123 -r 48000 ");
+    }else{
+        strcpy(cmd_line,"cd /home/new-speaker/target/share/sounds/cn/;mpg123 -r 48000 ");
+    }
+
+    int i;
+    for (i=0;i<strlen(ipaddr);i++){
+        switch(ipaddr[i])
+        {
+            case '0':
+                strcat(cmd_line,"digit-0.mp3 ");
+                break;
+            case '1':
+                strcat(cmd_line,"digit-1.mp3 ");
+                break;
+            case '2':
+                strcat(cmd_line,"digit-2.mp3 ");
+                break;
+            case '3':
+                strcat(cmd_line,"digit-3.mp3 ");
+                break;
+            case '4':
+                strcat(cmd_line,"digit-4.mp3 ");
+                break;
+            case '5':
+                strcat(cmd_line,"digit-5.mp3 ");
+                break;
+            case '6':
+                strcat(cmd_line,"digit-6.mp3 ");
+                break;
+            case '7':
+                strcat(cmd_line,"digit-7.mp3 ");
+                break;
+            case '8':
+                strcat(cmd_line,"digit-8.mp3 ");
+                break;
+            case '9':
+                strcat(cmd_line,"digit-9.mp3 ");
+                break;
+            case '.':
+                strcat(cmd_line,"dian.mp3 ");
+                break;
+        }
+    }
+    // printf("cmd-line:%s\n", cmd_line);
+    system(cmd_line);
+    playip_lock = FALSE;
+
+    return 0;
+}
+
+static int checkSIPActive()
+{
+    char enable[8];
+    FILE *fp1;
+    bzero(enable,sizeof(enable));
+    fp1 = popen("sysconf /etc/speaker.conf get system enabled", "r");
+    fread(enable,1,sizeof(enable),fp1);
+    pclose(fp1);
+    if(!strcmp(enable,"yes")) return TRUE;
+    else
+        return FALSE;
+}
+
+void *thread_playIP(void *p)
+{
+    if(!playip_lock){
+        system("/etc/scripts/change_output_vol.sh reduce;/etc/scripts/pa_mute.sh 0");
+        PlayIP();
+        system("/etc/scripts/pa_mute.sh 1;/etc/scripts/change_output_vol.sh recover");
+    }
+    pthread_exit(NULL);
+}
+
+void whoami()
+{
+    char tmp[32];
+    FILE *fp = popen("sysconf /etc/speaker.conf get system model","r");
+    if(!fp)
+        perror("popen wrong");
+    bzero(tmp,sizeof(tmp));
+    fread(tmp,1,sizeof(tmp),fp);
+    pclose(fp);
+    tmp[strlen(tmp)] = '\0';
+
+    if(!strncasecmp(tmp, "SH30", 4) || !strncasecmp(tmp, "SW15", 4) || !strncasecmp(tmp, "SC15", 4))
+        devType = SPEAKER;
+    else if (!strncasecmp(tmp, "IA03", 4) || !strncasecmp(tmp, "IV03", 4))
+        devType = INTERCOM;
+    else
+        devType = SPEAKER;
+}
+
+void emergencyCall()
+{
+    char tmp[32],exten[15],buf[128];
+    FILE *fp1;
+    bzero(tmp,sizeof(tmp));
+    fp1 = popen("sysconf /etc/speaker.conf get intercom repress_cancel", "r");
+    fread(tmp,1,sizeof(tmp),fp1);
+    pclose(fp1);
+
+    if (!strcmp(tmp,"no")){
+        bzero(exten,sizeof(exten));
+        fp1 = popen("sysconf /etc/speaker.conf get intercom onekey_num", "r");
+        fread(exten,1,sizeof(exten),fp1);
+        pclose(fp1);
+        if(strlen(exten)){
+            sprintf(buf,"linphonecsh dial %s",exten);
+            system(buf);
+        }
+    } else {
+        bzero(tmp,sizeof(tmp));
+        fp1 = popen("sysconf /userdata/tmp_state.conf get intercom onekey_state", "r");
+        fread(tmp,1,sizeof(tmp),fp1);
+        pclose(fp1);
+
+        if(strlen(tmp)) {
+            if(!strncasecmp(tmp,"idle",4)) // Dial action
+            {
+                bzero(exten,sizeof(exten));
+                fp1 = popen("sysconf /etc/speaker.conf get intercom onekey_num", "r");
+                fread(exten,1,sizeof(exten),fp1);
+                pclose(fp1);
+                if(strlen(exten)){
+                    sprintf(buf,"linphonecsh dial %s &",exten);
+                    system(buf);
+                }
+            } else if (!strncasecmp(tmp,"inUse",5)) { // Cancel or Hangup
+                system("linphonecsh generic terminate");
+                system("sysconf /userdata/tmp_state.conf set intercom onekey_state idle");
+
+            }
+        }
+    }
+}
+
+int main(int argc, char *argv[]){
+    struct pollfd fdset;
+    int key1_fd, ret, len, count, i;
+    char buf[128];
+    time_t lastime, newtime;
+    FILE *fp1;
+    pthread_t  thread;
+
+    // Short delay
+    sleep(5);
+
+    /* KEY1 */
+    key1_fd = open("/sys/class/gpio/gpio140/value", O_RDONLY);
+    read(key1_fd, buf, sizeof(buf));
+    lseek(key1_fd, 0, SEEK_SET);
+
+    whoami();
+
+    while(1)
+    {
+        memset(&fdset, 0x00, sizeof(struct pollfd));
+        fdset.fd = key1_fd;
+        fdset.events = POLLPRI;
+
+
+        ret = poll(&fdset, 1, 3000);
+        if(ret < 0){
+            printf("npoll() faild! \n");
+            return -1;
+        }
+        if(ret == 0)
+            continue;
+
+        /*KEY1*/
+        if( fdset.revents & POLLPRI )
+        {
+            count = 0;
+            for(i=0;i<50;i++){ // 50ms
+                bzero(buf,sizeof(buf));
+                read(fdset.fd, buf, sizeof(buf));
+                lseek(fdset.fd, 0, SEEK_SET);
+                if(buf[0]-'0' == 0)
+                    count++;
+                usleep(1000);
+            }
+            // printf("zero counts: %d\n", count);
+            if (count >= 30) {
+                press_down = TRUE;
+                time(&newtime);
+                printf("KEY DOWN\n");
+            } else {
+                time(&lastime);
+                len = lastime - newtime;
+                printf("KEY UP, Time:%d\n", len);
+
+                if(press_down){
+                    press_down = FALSE;
+                    if(devType == SPEAKER){
+                        if ( len >= 2 && len <= 9) // Play IP
+                            pthread_create(&thread, NULL, thread_playIP, NULL);
+                        else if ( len >= 1000)
+                            pthread_create(&thread, NULL, thread_playIP, NULL);
+                        else if ( len >= 10){
+                            system("/etc/scripts/play_rebooting.sh;rm -f /oem/.userdata && /sbin/reboot");
+                        }
+                    } else {
+                        if (len >= 5)
+                            pthread_create(&thread, NULL, thread_playIP, NULL);
+                        else // Make a phone call.
+                            if(checkSIPActive())
+                                emergencyCall();
+                    }
+                }
+            }
+        }
+    }
+}

+ 21 - 0
Modules/watchdog/Makefile

@@ -0,0 +1,21 @@
+TARGET = wd_soft
+Dir2store = ${TARGET_DIR}/usr/bin
+objects = *.o
+CFLAGS =
+
+${TARGET}:$(objects)
+	${CC} -o $@ $(objects) $(CFLAGS)
+
+%.o:%.c
+	${CC} -c $<
+
+.PHONY:clean install uninstall
+
+clean:
+	rm -f *.o ${TARGET}
+
+install:
+	cp -f ${TARGET} ${Dir2store}
+
+uninstall:
+	rm -f ${Dir2store}/${TARGET}

+ 89 - 0
Modules/watchdog/main.c

@@ -0,0 +1,89 @@
+/*
+ * Watchdog Driver Test Program
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <signal.h>
+#include <sys/ioctl.h>
+#include <linux/types.h>
+#include <linux/watchdog.h>
+
+int fd;
+
+/*
+ * This function simply sends an IOCTL to the driver, which in turn ticks
+ * the PC Watchdog card to reset its internal timer so it doesn't trigger
+ * a computer reset.
+ */
+static void keep_alive(void)
+{
+    int dummy;
+
+    ioctl(fd, WDIOC_KEEPALIVE, &dummy);
+}
+
+/*
+ * The main program.  Run the program with "-d" to disable the card,
+ * or "-e" to enable the card.
+ */
+
+static void term(int sig)
+{
+    close(fd);
+    printf("Stopping watchdog ticks...\n");
+    exit(0);
+}
+
+int main(int argc, char *argv[])
+{
+    int flags;
+    int timeout=6;
+
+    fd = open("/dev/watchdog", O_WRONLY);
+
+    if (fd == -1) {
+        fprintf(stderr, "Watchdog device not enabled.\n");
+        fflush(stderr);
+        exit(-1);
+    }
+    if (argc > 1) {
+        if (!strncasecmp(argv[1], "-d", 2)) {
+            flags = WDIOS_DISABLECARD;
+            ioctl(fd, WDIOC_SETOPTIONS, &flags);
+            fprintf(stderr, "Watchdog card disabled.\n");
+            fflush(stderr);
+            goto end;
+        } else if (!strncasecmp(argv[1], "-e", 2)) {
+            flags = WDIOS_ENABLECARD;
+            ioctl(fd, WDIOC_SETOPTIONS, &flags);
+            fprintf(stderr, "Watchdog card enabled.\n");
+            fflush(stderr);
+            //goto end;
+        } else {
+            fprintf(stderr, "-d to disable, -e to enable.\n");
+            fprintf(stderr, "run by itself to tick the card.\n");
+            fflush(stderr);
+            goto end;
+        }
+    } else {
+        fprintf(stderr, "Watchdog Ticking Away!\n");
+        fflush(stderr);
+    }
+
+    signal(SIGTERM, term);
+    ioctl(fd, WDIOC_SETTIMEOUT, &timeout);
+    ioctl(fd, WDIOC_GETTIMEOUT, &timeout);
+
+    while(1) {
+        keep_alive();
+        sleep(4);
+    }
+end:
+    close(fd);
+    return 0;
+}
+

+ 5 - 0
etc/lightdm/lightdm.conf

@@ -0,0 +1,5 @@
+[Seat:*]
+autologin-user=jhc
+autologin-session=xfce
+autologin-user-timeout=0
+xserver-command=X -bs -core -nocursor

BIN
etc/logo/favicon.ico


BIN
etc/logo/logo.png


BIN
etc/logo/logo@2x.png


+ 25 - 0
etc/rc.local

@@ -0,0 +1,25 @@
+#!/bin/bash
+
+#Don't modify these lines of code
+#if [ -f "/root/restart_count.log" ];then
+#	/bin/bash /usr/local/bin/test_reboot.sh
+#fi
+chmod 777 /dev/ttyS*
+# Create dummy video node for chromium V4L2 VDA/VEA with rkmpp plugin
+echo dec > /dev/video-dec0
+echo enc > /dev/video-enc0
+chmod 660 /dev/video-*
+chown root:video /dev/video-*
+# The chromium using fixed pathes for libv4l2.so
+ln -rsf /usr/lib/*/libv4l2.so /usr/lib/
+if [ -e /usr/lib/aarch64-linux-gnu/ ]; then
+    ln -Tsf lib /usr/lib64
+fi
+bash /etc/init.d/rkwifibt.sh &
+bash /usr/local/bin/init.sh
+/etc/scripts/httpd.sh start
+
+sleep 5
+udhcpc -i usb0 -n
+
+exit 0

Filskillnaden har hållts tillbaka eftersom den är för stor
+ 1832 - 0
etc/redis.conf


+ 32 - 0
etc/scripts/action.sh

@@ -0,0 +1,32 @@
+#!/bin/bash
+
+action="$1"
+
+CONFPATH="/etc/speaker.conf"
+
+case ${action} in
+    set_rtsp)
+        rtsp_access="`sysconf ${CONFPATH} get ipc rtsp_access`"
+        if [ "foo${rtsp_access}" = "fooyes" ];then
+            echo "1" > /proc/sys/net/ipv4/ip_forward
+            iptables -F && iptables -t nat -F
+            iptables -t nat -A PREROUTING  -p tcp --dport 554 -j DNAT --to-destination 10.231.132.139:554
+            exit 0
+        else
+            echo "0" > /proc/sys/net/ipv4/ip_forward
+            iptables -F && iptables -t nat -F
+            exit 0
+        fi
+    ;;
+
+    set_yaml)
+        sed -i '/^!!omap/d' /tmp/conf
+        sed -i 's/!!omap//g' /tmp/conf
+        sed -i 's/^- //g' /tmp/conf
+        sed -i 's/^  - /  /g' /tmp/conf
+    ;;
+
+    *)
+        exit 0
+    ;;
+esac

BIN
etc/scripts/api_agent


+ 124 - 0
etc/scripts/audio_init.sh

@@ -0,0 +1,124 @@
+#!/bin/sh
+#
+# initial audio set.
+#
+
+ajust_snd_params()
+{
+    times=3
+    volume_out=`sysconf ${volctrl_path} get volume volume_out`
+
+    # Set output volume
+    case ${volume_out} in
+        9)
+            value_out=99
+            ;;
+        8)
+            value_out=95
+            ;;
+        7)
+            value_out=92
+            ;;
+        6)
+            value_out=90
+            ;;
+        5)
+            value_out=88
+            ;;
+        4)
+            value_out=81
+            ;;
+        3)
+            value_out=66
+            ;;
+        2)
+            value_out=47
+            ;;
+        1)
+            value_out=19
+            ;;
+        0)
+            value_out=0
+            ;;
+    esac
+
+
+    while [ 1 ]
+    do
+        /usr/bin/amixer -q sset 'Master',0 ${value_out}
+
+        times=`expr $times - 1`
+
+        if [ ${times} -le 0 ];then
+            break;
+        fi
+    done
+}
+
+volctrl_path="/oem/etc/volctrl.conf"
+
+EQ_STAT="`ps|grep 'eq_drc_process'|grep -v grep`"
+if [ -z "${EQ_STAT}" ];then
+        /usr/bin/eq_drc_process > /dev/null 2>&1 &
+fi
+
+volume_in=`sysconf ${volctrl_path} get volume volume_in`
+
+case ${volume_in} in
+    9)
+        value_in=31
+        ;;
+    8)
+        value_in=30
+        ;;
+    7)
+        value_in=29
+        ;;
+    6)
+        value_in=28
+        ;;
+    5)
+        value_in=27
+        ;;
+    4)
+        value_in=26
+        ;;
+    3)
+        value_in=24
+        ;;
+    2)
+        value_in=23
+        ;;
+    1)
+        value_in=21
+        ;;
+    0)
+        value_in=0
+        ;;
+esac
+
+if [ ${value_in} = 0 ];then
+    /usr/bin/amixer -q sset 'ADC MIC Group 3 Left' 'Mute'
+    /usr/bin/amixer -q sset 'ADC MIC Group 3 Right' 'Mute'
+else
+    /usr/bin/amixer -q sset 'ADC MIC Group 3 Left' 'Work'
+    /usr/bin/amixer -q sset 'ADC MIC Group 3 Right' 'Work'
+    /usr/bin/amixer -q sset 'ADC ALC Group 3 Left' ${value_in}
+    /usr/bin/amixer -q sset 'ADC ALC Group 3 Right' ${value_in}
+fi
+
+/usr/bin/amixer -q sset 'DAC HPMIX Left' 1
+/usr/bin/amixer -q sset 'DAC LINEOUT Left' 2
+/usr/bin/amixer -q sset 'DAC HPMIX Right' 1
+/usr/bin/amixer -q sset 'DAC LINEOUT Right' 2
+
+ajust_snd_params&
+
+/usr/bin/amixer -q sset 'ADC MIC Group 1 Left' 'Work'
+
+/usr/bin/amixer -q cset numid=11,iface=MIXER,name='ADC Main MICBIAS' 1
+/usr/bin/amixer -q cset numid=10,iface=MIXER,name='ADC MICBIAS Voltage' 5
+/usr/bin/amixer -q cset numid=12,iface=MIXER,name='ADC MICBIAS1' off
+/usr/bin/amixer -q cset numid=13,iface=MIXER,name='ADC MICBIAS2' on
+
+exit 0

+ 112 - 0
etc/scripts/auto_privisioning.sh

@@ -0,0 +1,112 @@
+#!/bin/bash
+
+CONFIGDIR="/oem/.record"
+SYSTEMCONF="/etc/speaker.conf"
+FIRMWARECONF="${CONFIGDIR}/firmware_url"
+
+action="$1"
+address="$2"
+type="$3"
+
+[ -z "${action}" ] && echo "Usage:$0 dhcp|static" && exit 1
+
+[ ! -d ${CONFIGDIR} ] && mkdir -p ${CONFIGDIR}
+if [ ! -f ${FIRMWARECONF} ];then
+    touch ${FIRMWARECONF}
+    cat << END > ${FIRMWARECONF}
+[firmware]
+url=test
+END
+fi
+
+[ ! -d ${CONFIGDIR} ] && mkdir -p ${CONFIGDIR}
+
+get_mac() {
+    real_model="`/etc/scripts/getmodel.sh`"
+    if [ "foo${real_model}" = "fooX10" -o "foo${real_model}" = "fooX10_V2" ];then
+        interface="br0"
+    else
+        interface="eth0"
+    fi
+    echo "`ifconfig ${interface} | grep HWaddr | awk '{print $5}' | tr -d ':' | tr -d ' '`"
+}
+
+handle_conf() {
+    /etc/scripts/conf_handle.sh export_${format}
+    res="`/etc/scripts/import_compare.sh ${CONFIGDIR}/new.json /tmp/conf`"
+    if [ ! -z "${res}" ];then
+        cp ${CONFIGDIR}/new.json /tmp/conf
+        res="`/etc/scripts/conf_handle.sh import`"
+        if [ -z "${res}" ];then
+            rm -rf ${CONFIGDIR}/new.json
+            echo "Auto privisioning Successfully"
+            if [ "foopnp" != "foo${type}" ];then
+                /etc/scripts/shell_action.sh showReboot
+                sleep 1
+                /sbin/reboot
+            fi
+        else
+            echo "Import configuration failed"
+            rm -rf ${CONFIGDIR}/new.json
+            exit 1
+        fi
+    else
+        rm -rf ${CONFIGDIR}/new.json
+        echo "Configuration same as local, dont need apply"
+        exit 0
+    fi
+}
+
+mac="`get_mac`"
+model="`sysconf ${SYSTEMCONF} get system oem_model`"
+[ -z "${model}" ] && model="`sysconf ${SYSTEMCONF} get system model`"
+softwareVersion="`sysconf ${SYSTEMCONF} get system firmware`"
+[ -z "${mac}" ] && echo "Please check network interface" && exit 1
+format="`sysconf ${SYSTEMCONF} get auto_privisioning format`"
+[ -z "${format}" ] && echo "Please check auto privisioning format" && exit 1
+if [ "foo${action}" = "foodhcp" ];then
+    [ -z "${address}" ] && echo "Not found http url or tftp server" && exit 1
+    result=$(echo ${address} | grep "://")
+    if [ -z ${result} ];then
+        mode="tftp"
+    else
+        mode="http"
+        final_char="${address: -1}"
+        if [ "foo${final_char}" = "foo/" ];then
+            address="${address%?}"
+        fi
+    fi
+else
+    mode="`sysconf ${SYSTEMCONF} get auto_privisioning mode`"
+    address="`sysconf ${SYSTEMCONF} get auto_privisioning address`"
+    [ -z "${address}" -o -z "${mode}" ] && echo "Need http url and mode" && exit 1
+    final_char="${address: -1}"
+    if [ "foo${final_char}" = "foo/" ];then
+        address="${address%?}"
+    fi
+fi
+
+if [ "foo${mode}" = "footftp" ];then
+    #get config file from tftp server
+    tftp -g -l ${CONFIGDIR}/new.json -r ${mac}.${format} ${address}
+    retcode="$?"
+    [ "foo${retcode}" = "foo1" ] && echo "Failed download file form tftp server" && exit 1
+    handle_conf
+elif [ "foo${mode}" = "foohttp" ];then
+    #get config file from http server
+    #"Zycoo-X10 v_s1.2.5 68692E290C5D"
+    user_agent="Zycoo-${model} ${softwareVersion} ${mac}"
+    if [ "foopnp" = "foo${type}" ];then
+        retcode="`/usr/bin/curl -o ${CONFIGDIR}/new.json -k --user-agent "${user_agent}" --connect-timeout 3 -w %{http_code} ${address}`"
+    else
+        retcode="`/usr/bin/curl -o ${CONFIGDIR}/new.json -k --user-agent "${user_agent}" --connect-timeout 3 -w %{http_code} ${address}/${mac}.${format}`"
+    fi
+    if [ "foo${retcode}" = "foo200" ];then
+        handle_conf
+    else
+        rm -rf ${CONFIGDIR}/new.json
+        exit 1
+    fi
+fi
+
+exit 0

Filskillnaden har hållts tillbaka eftersom den är för stor
+ 2271 - 0
etc/scripts/conf_handle.sh


+ 47 - 0
etc/scripts/config_store.sh

@@ -0,0 +1,47 @@
+#!/bin/bash
+#
+# store config settings
+#
+
+CONF="/etc/speaker.conf"
+NET_CONF="/tmp/interfaces"
+
+[ ! -f "/etc/speaker.conf" ] && exit 1
+net_type=`sysconf ${CONF} get system ip_assign`
+
+if [ "${net_type}" = "dhcp" ]; then
+    cat << END > ${NET_CONF}
+# interfaces(5) file used by ifup(8) and ifdown(8)
+# Include files from /etc/network/interfaces.d:
+auto lo
+iface lo inet loopback
+
+auto eth0
+iface eth0 inet dhcp
+    udhcpc_opts -R -n -O tftp
+END
+echo -n > /tmp/resolv.conf
+
+elif [ "${net_type}" = "static" ]; then
+    ip=`sysconf ${CONF} get system ipaddr`
+    mask=`sysconf ${CONF} get system netmask`
+    gateway=`sysconf ${CONF} get system gateway`
+    cat << END > ${NET_CONF}
+# interfaces(5) file used by ifup(8) and ifdown(8)
+# Include files from /etc/network/interfaces.d:
+auto lo
+iface lo inet loopback
+
+auto eth0
+iface eth0 inet static
+address ${ip}
+netmask ${mask}
+gateway ${gateway}
+END
+dns1=`sysconf ${CONF} get system dns1`
+dns2=`sysconf ${CONF} get system dns2`
+echo -n > /tmp/resolv.conf
+[ ! -z "${dns1}" ] && echo "nameserver ${dns1}" >> /tmp/resolv.conf
+[ ! -z "${dns2}" ] && echo "nameserver ${dns2}" >> /tmp/resolv.conf
+
+fi

+ 13 - 0
etc/scripts/dhcp_auto_privisioning.sh

@@ -0,0 +1,13 @@
+#!/bin/bash
+
+tftpserver="$1"
+
+[ -z ${tftpserver} ] && echo "Usage:$0 tftpserver" && exit 1
+
+/etc/scripts/auto_privisioning.sh dhcp ${tftpserver}
+retcode="$?"
+if [ "foo${retcode}" != "foo0" ];then
+    /etc/scripts/auto_privisioning.sh static
+fi
+
+exit 0

+ 21 - 0
etc/scripts/factoryReset_check.sh

@@ -0,0 +1,21 @@
+#!/bin/sh
+
+while [ 1 ]
+do
+    # factory reset or no
+    reset=`cat /sys/class/gpio/gpio143/value`
+    if [ "${reset}" = 0 ];then
+        sleep 3
+    fi
+    reset=`cat /sys/class/gpio/gpio143/value`
+    if [ "${reset}" = 0 ];then
+        /etc/scripts/play_rebooting.sh
+        /etc/scripts/shell_action.sh rebootIpc
+        /etc/scripts/shell_action.sh showReboot
+        sleep 1
+        rm -f /oem/.userdata && /sbin/reboot
+        exit
+
+    fi
+    sleep 1
+done

+ 16 - 0
etc/scripts/getmodel.sh

@@ -0,0 +1,16 @@
+#!/bin/bash
+
+SN="`/usr/bin/vendor_storage -r VENDOR_SN_ID | awk '{print $2}'`"
+SN_MODEL="`echo ${SN:0:4}`"
+# erro,using default model
+[ -z "${SN_MODEL}" ] && exit 0
+
+# SQ10-B
+if [ "${SN_MODEL}" = "ZSQB" ];then
+    echo -n "SQ10-B_V2"
+# SQ10-T
+elif [ "${SN_MODEL}" = "ZSQT" ];then
+    echo -n "SQ10-T_V2"
+fi
+
+exit 0

+ 54 - 0
etc/scripts/getsubmask.sh

@@ -0,0 +1,54 @@
+#!/bin/sh
+
+action="$1"
+
+case "${action}" in
+	primarydns)
+		dns1="`cat /etc/resolv.conf  | grep nameserver | sed -n '1p' | awk '{print $2}'`"
+		[ -z "${dns1}" ] && dns1="None"
+		echo -n "${dns1}"
+	;;
+
+	alternativedns)
+                dns2="`cat /etc/resolv.conf  | grep nameserver | sed -n '2p' | awk '{print $2}'`"
+                [ -z "${dns2}" ] && dns2="None"
+		echo -n "${dns2}"
+        ;;
+
+	uptime)
+                uptime="`cat /proc/uptime | awk '{print $1}' | tr -d ' ' | cut -d '.' -f1`"
+                [ -z "${uptime}" ] && uptime=0
+		echo -n "${uptime}"
+        ;;
+
+	camera_model)
+		MODEL="`curl --connect-timeout 0.5 -X GET "http://10.231.132.139/cgi-bin/web.cgi?action=get&cmd=language" 2>/dev/null | cut -d: -f1`"
+		if [ "abc_${MODEL}" = "abc_{\"language\"" ];then
+			echo -n "1"
+		else
+			echo -n "0"
+		fi
+	;;
+
+	get_ip)
+		device_model="`/etc/scripts/getmodel.sh`"
+		if [ "foo${device_model}" == "fooX10" ];then
+			ip="`ifconfig br0 | grep 'inet addr' | awk '{print $2}' | tr -d ' ' | cut -d ':' -f2`"
+		else
+			ip="`ifconfig eth0 | grep 'inet addr' | awk '{print $2}' | tr -d ' ' | cut -d ':' -f2`"
+		fi
+
+		echo -n "${ip}"
+	;;
+
+	*)
+		model="`sysconf /etc/speaker.conf get system model`"
+		if [ "foo${model}" = "fooX10" ];then
+			submask="`/sbin/ifconfig br0 | grep Mask | awk '{print $4}' | cut -d ':' -f2`"
+		else
+			submask="`/sbin/ifconfig eth0 | grep Mask | awk '{print $4}' | cut -d ':' -f2`"
+		fi
+		echo -n "${submask}"
+esac
+
+exit 0

+ 30 - 0
etc/scripts/gpio_init.sh

@@ -0,0 +1,30 @@
+#!/bin/bash
+
+if [ ! -L /sys/class/gpio/gpio72 ];then
+        echo -e "gpio72 used for system led.\n"
+        echo 72 > /sys/class/gpio/export
+        echo out > /sys/class/gpio/gpio72/direction
+        echo 0 > /sys/class/gpio/gpio72/value
+fi
+
+if [ ! -L /sys/class/gpio/gpio73 ];then
+        echo -e "GPIO73 used for Reset button\n"
+        echo 73 > /sys/class/gpio/export
+        echo in > /sys/class/gpio/gpio73/direction
+        echo both > /sys/class/gpio/gpio73/edge
+fi
+
+if [ ! -L /sys/class/gpio/gpio111 ];then
+        echo -e "GPIO111 used for input detect\n"
+        echo 111 > /sys/class/gpio/export
+        echo in > /sys/class/gpio/gpio111/direction
+        echo both > /sys/class/gpio/gpio111/edge
+fi
+
+if [ ! -L /sys/class/gpio/gpio112 ];then
+        echo -e "GPIO112 used for Relay Control.\n"
+        echo 112 > /sys/class/gpio/export
+        echo out > /sys/class/gpio/gpio112/direction
+        echo 0 > /sys/class/gpio/gpio112/value
+fi
+

+ 22 - 0
etc/scripts/httpd.sh

@@ -0,0 +1,22 @@
+#!/bin/sh
+
+case "$1" in
+  start)
+    printf "Starting WEB UI: "
+    [ ! -d /userdata/upgrade ] && mkdir -p /userdata/upgrade && sync
+    /www/speaker-cgi -configPath /etc/ -embedStatic -uploadPath /userdata/upgrade > /dev/null &
+    [ $? = 0 ] && echo "OK" || echo "FAIL"
+    ;;
+  stop)
+    printf "Stopping WEB UI: "
+    killall speaker-cgi
+    [ $? = 0 ] && echo "OK" || echo "FAIL"
+    ;;
+  restart|reload)
+    "$0" stop
+    "$0" start
+    ;;
+  *)
+    echo "Usage: $0 {start|stop|restart}"
+    exit 1
+esac

+ 107 - 0
etc/scripts/import_compare.sh

@@ -0,0 +1,107 @@
+#!/usr/bin/python
+
+import ruamel.yaml
+import sys
+import json
+
+def list_all_dict(dstDict, srcDict):
+    if isinstance(dstDict,dict):
+        for x in range(len(dstDict)):
+            temp_key = list(dstDict.keys())[x]
+            temp_value = dstDict[temp_key]
+            if isinstance(temp_value, dict):
+                if temp_key in srcDict:
+                    list_all_dict(temp_value, srcDict[temp_key])
+                else:
+                    res = {}
+                    res.setdefault("key", temp_key)
+                    res.setdefault("error", "not recognize")
+                    print(output_str(res))
+                    sys.exit(0)
+            else:
+                if temp_value == srcDict[temp_key]:
+                    continue
+                else:
+                    res = {}
+                    res.setdefault("key", temp_key)
+                    res.setdefault("error", "not equal")
+                    print(output_str(res))
+                    sys.exit(0)
+
+def output_str(res):
+    return json.dumps(res)
+
+def loadConf(remoteConfig, lacalConfig):
+    try:
+        with open(remoteConfig, 'r') as f:
+            remoteDict = json.loads(f.read())
+    except FileNotFoundError:
+        res = {}
+        res.setdefault("file", remoteConfig)
+        res.setdefault("check", "file_not_found")
+        print(output_str(res))
+        sys.exit(0)
+    except:
+        try:
+            with open(remoteConfig, 'rb') as f:
+                yaml=ruamel.yaml.YAML(typ='safe')
+                remoteDict = yaml.load(f)
+        except:
+            res = {}
+            res.setdefault("file", remoteConfig)
+            res.setdefault("check", "file_format_error")
+            print(output_str(res))
+            sys.exit(0)
+    
+    if type(remoteDict) != dict:
+        res = {}
+        res.setdefault("file", remoteConfig)
+        res.setdefault("check", "file_format_error")
+        print(output_str(res))
+        sys.exit(0) 
+
+    try:
+        with open(lacalConfig, 'r') as f:
+            localDict = json.loads(f.read())
+    except FileNotFoundError:
+        res = {}
+        res.setdefault("file", localConfig)
+        res.setdefault("check", "file_not_found")
+        print(output_str(res))
+        sys.exit(0)
+    except:
+        try:
+            with open(localConfig, 'rb') as f:
+                yaml=ruamel.yaml.YAML(typ='safe')
+                localDict = yaml.load(f)
+        except:
+            res = {}
+            res.setdefault("file", localConfig)
+            res.setdefault("check", "file_format_error")
+            print(output_str(res))
+            sys.exit(0)
+    
+    if type(localDict) != dict:
+        res = {}
+        res.setdefault("file", localConfig)
+        res.setdefault("check", "file_format_error")
+        print(output_str(res))
+        sys.exit(0)
+    
+    list_all_dict(remoteDict, localDict)
+    sys.exit(0)
+    
+    
+    
+
+if __name__ == "__main__":
+    if len(sys.argv) == 3:
+        remoteConfig=sys.argv[1]
+        localConfig=sys.argv[2]
+    else:
+        res = {}
+        res.setdefault("check", "Usage: %s remoteConfig localConfig" % (sys.argv[0]))
+        print(output_str(res))
+        sys.exit(0)
+    
+    loadConf(remoteConfig, localConfig)

+ 59 - 0
etc/scripts/keep_tcpdump.sh

@@ -0,0 +1,59 @@
+#!/bin/sh
+
+start()
+{
+        MODEL="`/etc/scripts/getmodel.sh`"
+        if [ "foo${MODEL}" = "fooX10" ];then
+                interface="br0"
+        else
+                interface="eth0"
+        fi
+        while [ 1 ]
+        do
+                /usr/sbin/tcpdump -i ${interface} -w /tmp/tcpdump.pcap > /dev/null 2>&1 &
+                touch /tmp/.tcpdump
+                sleep 600
+                /bin/rm -rf /tmp/.tcpdump
+                /bin/rm -rf /tmp/tcpdump.pcap
+                killall tcpdump > /dev/null 2>&1
+                break
+        done
+}
+
+stop()
+{
+        # stop tcpdump
+        /bin/rm -rf /tmp/.tcpdump
+        killall tcpdump > /dev/null 2>&1
+}
+
+restart()
+{
+        stop
+        sleep 2
+        start&
+}
+
+reload()
+{
+        stop
+        sleep 2
+        start&
+}
+
+case "$1" in
+  start)
+        start
+        ;;
+  stop)
+        stop
+        ;;
+  restart|reload)
+        restart
+        ;;
+  *)
+        echo "Usage: $0 {start|stop|restart}"
+        exit 1
+esac
+
+exit $?

+ 30 - 0
etc/scripts/merge_conf.sh

@@ -0,0 +1,30 @@
+#!/usr/bin/python3
+from configparser import RawConfigParser
+
+def merge_configs(a_conf_file, b_conf_file):
+    # 读取 a.conf 文件
+    a_conf = RawConfigParser()
+    a_conf.read(a_conf_file, encoding='utf-8')
+
+    # 读取 b.conf 文件
+    b_conf = RawConfigParser()
+    b_conf.read(b_conf_file, encoding='utf-8')
+
+    # 合并配置项到 a.conf
+    for section in b_conf.sections():
+        if not a_conf.has_section(section):
+            a_conf.add_section(section)
+
+        for option in b_conf.options(section):
+            # 只有在 a.conf 中不存在该项时才进行合并
+            if (not a_conf.has_option(section, option)) or (option == "firmware"):
+                value = b_conf.get(section, option)
+                a_conf.set(section, option, value)
+            
+    # 将合并后的配置写入输出文件
+    with open(a_conf_file, 'w') as f:
+        a_conf.write(f, space_around_delimiters=False)
+    
+if __name__ == "__main__":
+    merge_configs("/etc/speaker.conf", "/etc/speaker_update.conf")
+    merge_configs("/oem/etc/volctrl.conf", "/etc/volctrl_update.conf")

+ 36 - 0
etc/scripts/monitor_ptp.sh

@@ -0,0 +1,36 @@
+#!/bin/bash
+
+# 设置阈值(百分比,不带%号)
+THRESHOLD=10
+
+# 启动 ptpd2 的命令(请根据实际路径修改)
+# ART_CMD="/usr/sbin/ptpd2"
+
+# 检查周期(秒)
+INTERVAL=10
+
+while true; do
+    # 获取 ptpd2 的 PID
+    PID=$(ps | grep ptpd2 | grep -v "grep" | awk '{print $1}')
+
+    if [ -n "$PID" ]; then
+        # 获取 ptpd2 的实时 CPU 使用率(百分比)
+        CPU=$(top -b -n1 | grep ptpd2 |grep -v "grep" | awk '{print $8}')
+        CPU_INT=${CPU%.*}  # 去掉小数部分用于比较
+
+        if [[ "$CPU_INT" =~ ^[0-9]+$ ]] && (( CPU_INT > THRESHOLD )); then
+            echo "[`date`] ptpd2 CPU 使用率 ${CPU}% 超过阈值 ${THRESHOLD}%,正在重启..."
+
+            kill -9 ${PID}
+            # sleep 1
+            # $START_CMD &
+            echo "[`date`] ptpd2 已重启"
+        fi
+    # else
+    #     echo "[`date`] ptpd2 未运行,尝试启动..."
+    #     $START_CMD &
+    #     echo "[`date`] ptpd2 启动完成"
+    fi
+
+    sleep $INTERVAL
+done

BIN
etc/scripts/onvif-discover


+ 116 - 0
etc/scripts/onvif_upgrade.sh

@@ -0,0 +1,116 @@
+#!/bin/sh
+
+IMGPATH="/userdata/upgrade/fireware.img"
+STATUSDIR="/oem/.onvif_upgrade"
+STATUSPATH="${STATUSDIR}/status"
+[ ! -d "${STATUSDIR}" ] && mkdir -p ${STATUSDIR}
+
+get_mac() {
+    real_model="`/etc/scripts/getmodel.sh`"
+    if [ "foo${real_model}" = "fooX10" -o "foo${real_model}" = "fooX10_V2" ];then
+        interface="br0"
+    else
+        interface="eth0"
+    fi
+    echo "`ifconfig ${interface} | grep HWaddr | awk '{print $5}' | tr -d ':' | tr -d ' '`"
+}
+
+action="$1"
+
+[ -z "${action}" ] && exit 1
+
+case "${action}" in
+	upgrade)
+		echo -n "UpgradePre" > ${STATUSPATH}
+		sync
+		[ -z "$2" -o -z "$3" ] && exit 1
+		/etc/scripts/upgrade.sh pre
+		fireware="$2"
+		reset_default="$3"
+		echo -n "Downloading" > ${STATUSPATH}
+		#"Zycoo-X10 v_s1.2.5 68692E290C5D"
+		model="`sysconf ${SYSTEMCONF} get system oem_model`"
+		[ -z "${model}" ] && model="`sysconf ${SYSTEMCONF} get system model`"
+		softwareVersion="`sysconf ${SYSTEMCONF} get system firmware`"
+		mac="`get_mac`"
+		user_agent="Zycoo-${model} ${softwareVersion} ${mac}"
+		retcode="`/usr/bin/curl -o ${IMGPATH} -k --user-agent "${user_agent}" --connect-timeout 10 -w %{http_code} ${fireware}`"
+		if [ "foo${retcode}" != "foo200" ];then
+			echo -n "downloadError" > ${STATUSPATH}
+			rm -rf ${IMGPATH}
+			sync
+			exit 1
+		fi
+		echo -n "Verifying" > ${STATUSPATH}
+		sync
+
+		model="`/etc/scripts/getmodel.sh`"
+		[ -z ${model} ] && exit 1
+		/bin/rk_parser ${IMGPATH} ${model}
+		recode_check="$?"
+		if [ "foo${recode_check}" != "foo0" ];then
+			echo -n "VerifyFailed" > ${STATUSPATH}
+			rm -rf ${IMGPATH}
+			sync
+			exit 1
+		fi
+		sync
+
+		/etc/scripts/shell_action.sh showReboot
+		updatetime="`sysconf /etc/speaker.conf get upgrade date`"
+
+		if [ ! -f /userdata/updatetime.txt ];then
+			touch /userdata/updatetime.txt
+			cat << END > /userdata/updatetime.txt
+[upgrade]
+date=2019-12-02
+END
+        	fi
+
+		sysconf /userdata/updatetime.txt set upgrade date ${updatetime}
+		echo -n "Upgrading" > ${STATUSPATH}
+		touch ${STATUSDIR}/upgraded
+		touch ${STATUSDIR}/mqtt_upgraded
+		sync
+
+		sleep 4
+
+		if [ "foo${reset_default}" = "foono" ];then
+			rm -rf /oem/.upgrade
+			# /usr/bin/recoverySystem ota ${IMGPATH}
+			updateEngine --image_url=${IMGPATH} --misc=update --savepath=${IMGPATH}  --reboot
+			recode="$?"
+			if [ "${recode}" = 255 ];then
+				echo -n "UpgradeFailed" > ${STATUSPATH}
+				touch /oem/.upgrade
+				rm -rf ${STATUSDIR}/upgraded
+				rm -rf ${STATUSDIR}/mqtt_upgraded
+				rm -rf ${IMGPATH}
+				sync
+				exit 1
+			fi
+		else
+			rm -rf /oem/.userdata
+			# /usr/bin/recoverySystem ota ${IMGPATH}
+			updateEngine --image_url=${IMGPATH} --misc=update --savepath=${IMGPATH}  --reboot
+			recode="$?"
+			if [ "${recode}" = 255 ];then
+				echo -n "UpgradeFailed" > ${STATUSPATH}
+				touch /oem/.userdata
+				rm -rf ${STATUSDIR}/upgraded
+				rm -rf ${STATUSDIR}/mqtt_upgraded
+				rm -rf ${IMGPATH}
+				sync
+				exit 1
+			fi
+		fi
+		sync
+	;;
+
+	getStatus)
+		cat ${STATUSPATH}
+		exit 0
+	;;
+esac
+
+exit 0

BIN
etc/scripts/onvifserver


BIN
etc/scripts/output_control


+ 13 - 0
etc/scripts/pa_mute.sh

@@ -0,0 +1,13 @@
+#!/bin/sh
+
+if [ $# == 1 ];then
+	if [ $1 == 0 ];then
+		echo 1 > /sys/class/gpio/gpio5/value
+		echo "set normal."
+	else
+		echo 0 > /sys/class/gpio/gpio5/value
+		echo "set mute."
+	fi
+else
+	echo "usage is $0 1 or 0"
+fi

BIN
etc/scripts/play_ip


+ 31 - 0
etc/scripts/play_rebooting.sh

@@ -0,0 +1,31 @@
+#!/bin/sh
+
+/etc/scripts/shell_action.sh showReboot
+
+REBOOT=$1
+get_lan()
+{
+    LAN=`sysconf /etc/speaker.conf get system language`
+}
+
+get_lan
+
+/usr/bin/amixer -q sset 'Master',0 29
+
+/etc/scripts/pa_mute.sh 0
+
+if [ "u_${LAN}" = "u_cn" ];then
+    if [ "$REBOOT" == "1" ];then
+        mpg123 -r 48000 /home/new-speaker/target/share/sounds/cn/reboot_zh.mp3
+    else
+        mpg123 -r 48000 /home/new-speaker/target/share/sounds/cn/zh.mp3
+    fi
+else
+    if [ "$REBOOT" == "1" ];then
+        mpg123 -r 48000 /home/new-speaker/target/share/sounds/en/reboot_en.mp3
+    else
+        mpg123 -r 48000 /home/new-speaker/target/share/sounds/en/en.mp3
+    fi
+fi
+
+/etc/scripts/pa_mute.sh 1

+ 34 - 0
etc/scripts/product_model.sh

@@ -0,0 +1,34 @@
+#!/bin/sh
+#
+#  Tpye select
+#
+
+tmp_hard_verssion="`/usr/bin/vendor_storage -r VENDOR_WIFI_MAC_ID | awk -F" " '{print $2}'`"
+tmp1_hard_version=${tmp_hard_verssion: -2}
+hard_version="Ver${tmp1_hard_version:0:1}.${tmp1_hard_version:1:1}"
+sysconf /etc/speaker.conf set system hard_version ${hard_version}
+
+SN="`/usr/bin/vendor_storage -r VENDOR_SN_ID | awk '{print $2}'`"
+SN_MODEL="`echo ${SN:0:4}`"
+# erro,using default model
+[ -z "${SN_MODEL}" ] && exit 0
+
+# SQ10-B
+if [ "${SN_MODEL}" = "ZSQB" ];then
+    model=SQ10-B
+    ui_model=SQ10-B
+# SQ10-T
+elif [ "${SN_MODEL}" = "ZSQT" ];then
+    model=SQ10-T
+    ui_model=SQ10-T
+fi
+
+sysconf /etc/speaker.conf set system model ${model}
+sysconf /etc/speaker.conf set system ui_model ${ui_model}
+
+location="`sysconf /etc/speaker.conf get system location`"
+[ "${location}" = "**" ] && sysconf /etc/speaker.conf set system location ${model}
+
+sync
+
+exit 0

BIN
etc/scripts/rtspserver


BIN
etc/scripts/serial_ctrl


BIN
etc/scripts/service_process


+ 26 - 0
etc/scripts/set_lan.sh

@@ -0,0 +1,26 @@
+#!/bin/sh
+if [ $# == 1 ];then
+	language=$1
+	if [ ! -f /oem/.flag/.language ];then
+		touch /oem/.flag/.language
+		cat << END > /oem/.flag/.language
+[system]
+language=en
+END
+	fi
+
+	if [ ${language} = "cn" ];then
+		sysconf /etc/speaker.conf set system language cn
+		sysconf /oem/.flag/.language set system language cn
+	elif [ ${language} = "en" ];then
+		sysconf /etc/speaker.conf set system language en
+		sysconf /oem/.flag/.language set system language en
+	else
+		echo "usage:$0 cn|en"
+	fi
+
+else
+	echo "usage:$0 cn|en"
+fi
+
+exit 0

+ 170 - 0
etc/scripts/set_volume.sh

@@ -0,0 +1,170 @@
+#!/bin/sh
+#
+# initial audio set.
+#
+
+MODEL=`sysconf /etc/speaker.conf get system model`
+[ "${MODEL}" = "SH30" -o "${MODEL}" = "SW15" -o "${MODEL}" = "SC15" ] && DEV_TYPE="Speaker"
+[ "${MODEL}" = "IV03" -o "${MODEL}" = "IA03" ] && DEV_TYPE="Intercom"
+
+case $1 in
+    set)
+        volume_out=$2
+    ;;
+    resume)
+        /etc/scripts/pa_mute.sh 1
+        volctrl_path="/oem/etc/volctrl.conf"
+        volume_out=`sysconf ${volctrl_path} get volume volume_out`
+    ;;
+    *)
+        /etc/scripts/pa_mute.sh 1
+        volctrl_path="/oem/etc/volctrl.conf"
+        volume_out=`sysconf ${volctrl_path} get volume volume_out`
+    ;;
+esac
+
+# Set output volume
+if [ "foo_${DEV_TYPE}" = "foo_Intercom" ];then
+    case ${volume_out} in
+        9)
+            value_out=99
+            ;;
+        8)
+            value_out=96
+            ;;
+        7)
+            value_out=93
+            ;;
+        6)
+            value_out=90
+            ;;
+        5)
+            value_out=86
+            ;;
+        4)
+            value_out=82
+            ;;
+        3)
+            value_out=78
+            ;;
+        2)
+            value_out=75
+            ;;
+        1)
+            value_out=71
+            ;;
+        0)
+            value_out=0
+            ;;
+    esac
+else # Speaker
+
+    if [ "foo_${MODEL}" = "foo_SC15" -o "foo_${MODEL}" = "foo_SW15" ];then
+
+        case ${volume_out} in
+            9)
+                value_out=91
+                ;;
+            8)
+                value_out=86
+                ;;
+            7)
+                value_out=79
+                ;;
+            6)
+                value_out=73
+                ;;
+            5)
+                value_out=67
+                ;;
+            4)
+                value_out=58
+                ;;
+            3)
+                value_out=47
+                ;;
+            2)
+                value_out=35
+                ;;
+            1)
+                value_out=19
+                ;;
+            0)
+                value_out=0
+                ;;
+        esac
+
+    elif [ "foo_${MODEL}" = "foo_SL50" ];then
+
+        case ${volume_out} in
+            9)
+                value_out="98,95"
+                ;;
+            8)
+                value_out="95,91"
+                ;;
+            7)
+                value_out="89,85"
+                ;;
+            6)
+                value_out="83,78"
+                ;;
+            5)
+                value_out="76,71"
+                ;;
+            4)
+                value_out="68,62"
+                ;;
+            3)
+                value_out="62,56"
+                ;;
+            2)
+                value_out="53,45"
+                ;;
+            1)
+                value_out="41,33"
+                ;;
+            0)
+                value_out=0
+                ;;
+        esac
+
+    else # SH30
+
+        case ${volume_out} in
+            9)
+                value_out=99
+                ;;
+            8)
+                value_out=95
+                ;;
+            7)
+                value_out=90
+                ;;
+            6)
+                value_out=86
+                ;;
+            5)
+                value_out=82
+                ;;
+            4)
+                value_out=78
+                ;;
+            3)
+                value_out=74
+                ;;
+            2)
+                value_out=70
+                ;;
+            1)
+                value_out=43
+                ;;
+            0)
+                value_out=0
+                ;;
+        esac
+    fi
+fi
+/usr/bin/amixer -q sset 'Master',0 ${value_out}
+
+exit 0

+ 13 - 0
etc/scripts/set_webpid.sh

@@ -0,0 +1,13 @@
+#!/bin/sh
+
+pid="`ps -e | grep speaker-cgi | grep -v grep | awk -F' ' '{print $1}'`"
+
+if [ "foo${pid}" != "foo" ];then
+    while [ 1 ]
+    do
+        echo "-100" > /proc/${pid}/oom_score_adj
+        usleep 200000
+    done
+fi
+
+exit 0

+ 40 - 0
etc/scripts/settime.sh

@@ -0,0 +1,40 @@
+#!/bin/bash
+CONF="/etc/speaker.conf"
+
+reboot="$1"
+
+action="$2"
+
+if [ "foo${reboot}" = "footrue" ];then
+	if [ "foo${action}" = "fooset_ntp" ];then
+		/etc/scripts/shell_action.sh showReboot
+		sleep 1
+		/sbin/reboot
+	fi
+fi
+
+/etc/init.d/S49ntp stop
+
+case ${action} in
+	set_ntp)
+		/etc/init.d/S49ntp start
+	;;
+	set_manual)
+		if [ ! -z "$3" ];then
+			manual_time="$3"
+			/bin/date -s "${manual_time}" && /sbin/hwclock -w -u
+		fi
+	;;
+esac
+
+/usr/bin/killall clock.sh > /dev/null 2>&1
+/etc/scripts/clock.sh > /dev/null 2>&1 &
+
+
+if [ "foo${reboot}" = "footrue" ];then
+	/etc/scripts/shell_action.sh showReboot
+	sleep 1
+	/sbin/reboot
+fi
+
+exit 0

+ 440 - 0
etc/scripts/shell_action.sh

@@ -0,0 +1,440 @@
+#!/bin/bash
+
+SYSCONFCMD="/usr/bin/sysconf"
+SYSCONF="/etc/speaker.conf"
+VOLCONF="/oem/etc/volctrl.conf"
+
+action="$1"
+
+[ -z "${action}" ] && exit 0
+
+case ${action} in
+    set_cronreboot)
+        CRON_DIR="/oem/etc/cron/crontabs"
+        CRON_CONF="${CRON_DIR}/root"
+
+        if [ ! -f "${CRON_CONF}" ];then
+            if [ ! -d "${CRON_DIR}" ];then
+                mkdir -p ${CRON_DIR}
+            fi
+            touch ${CRON_CONF}
+            chmod 0600 ${CRON_CONF}
+        fi
+
+        CRON_STAT="`ps|grep crond|grep -v grep`"
+        if [ -z "${CRON_STAT}" ];then
+            /usr/sbin/crond -c ${CRON_DIR}
+            sed -i '/check_log_size/d' ${CRON_CONF}
+            echo "0 2 * * * /etc/scripts/shell_action.sh check_log_size" > ${CRON_CONF}
+        fi
+
+        enable="`${SYSCONFCMD} ${SYSCONF} get restart-timer enable`"
+        if [ "foo${enable}" == "foono" ];then
+            sed -i '/reboot/d' ${CRON_CONF}
+            exit 0
+        fi
+
+        month="*"
+        week="`${SYSCONFCMD} ${SYSCONF} get restart-timer week`"
+        day="`${SYSCONFCMD} ${SYSCONF} get restart-timer day`"
+        hour="`${SYSCONFCMD} ${SYSCONF} get restart-timer hour`"
+        minutes="`${SYSCONFCMD} ${SYSCONF} get restart-timer minutes`"
+        sed -i '/reboot/d' ${CRON_CONF}
+        echo "${minutes} ${hour} ${day} ${month} ${week} /sbin/reboot" >> ${CRON_CONF}
+        exit 0
+    ;;
+
+    getdeviceInfo)
+        if /sbin/ifconfig br0 > /dev/null 2>&1;then
+            dev="br0"
+        else
+            dev="eth0"
+        fi
+
+		model="`${SYSCONFCMD} ${SYSCONF} get system model`"
+		hardVersion="`${SYSCONFCMD} ${SYSCONF} get system hard_version`"
+		ip="`/sbin/ifconfig ${dev} | grep 'inet addr' | awk '{print $2}' | cut -d ':' -f2 | tr -d ' '`"
+		ipMode="`${SYSCONFCMD} ${SYSCONF} get system ip_assign`"
+		mac="`/sbin/ifconfig ${dev} | grep 'HWaddr' | awk '{print $5}' | tr -d ' '`"
+		softwareVersion="`${SYSCONFCMD} ${SYSCONF} get system firmware`"
+		submask="`/sbin/ifconfig ${dev} | grep 'inet addr' | awk '{print $4}' | cut -d ':' -f2 | tr -d ' '`"
+        onvif_enable="`${SYSCONFCMD} ${SYSCONF} get onvif enable`"
+        account_port1="`${SYSCONFCMD} ${SYSCONF} get account_info_1 port`"
+        account_port2="`${SYSCONFCMD} ${SYSCONF} get account_info_2 port`"
+        remark="`${SYSCONFCMD} ${SYSCONF} get system location`"
+        multicast="`${SYSCONFCMD} ${SYSCONF} get multicast_player enable`"
+		echo -n "${hardVersion}|${ip}|${ipMode}|${mac}|${softwareVersion}|${model}|${submask}|${onvif_enable}|${account_port1}|${account_port2}|${remark}|${multicast}"
+	;;
+	getconfigInfo)
+        model="`${SYSCONFCMD} ${SYSCONF} get system model`"
+        masterExten="`${SYSCONFCMD} ${SYSCONF} get account_info_1 username`"
+        masterActivate="`${SYSCONFCMD} ${SYSCONF} get account_info_1 enable`"
+        masterServer="`${SYSCONFCMD} ${SYSCONF} get account_info_1 server`"
+        masterDomain="`${SYSCONFCMD} ${SYSCONF} get account_info_1 domain`"
+        [ -z "${masterDomain}" ] && masterDomain=${masterServer}
+        micVolume="`${SYSCONFCMD} ${VOLCONF} get volume volume_in`"
+        speakerVolume="`${SYSCONFCMD} ${VOLCONF} get volume volume_out`"
+
+        if [ "foo${masterActivate}" = "fooyes" ];then
+            search_str="baresip-reg-status-${masterExten}-${masterDomain}"
+            masterRegisterStatus="`/usr/sbin/redis-cli get ${search_str} | cut -d ',' -f2 | cut -d ':' -f2 | tr -d '}' | tr -d '\"'`"
+        else
+            masterRegisterStatus="unregister"
+        fi
+
+        echo -n "${masterExten}|${masterServer}|${masterRegisterStatus}|${speakerVolume}|${micVolume}"
+	;;
+
+	getStatus)
+		STATUSDIR="/oem/.onvif_upgrade"
+		STATUSPATH="${STATUSDIR}/status"
+		[ ! -d "${STATUSDIR}" ] && mkdir -p ${STATUSDIR} && echo -n "UpgradePre" > ${STATUSPATH}
+		cat ${STATUSPATH}
+		exit 0
+	;;
+
+	addRoute)
+		dstIp="$2"	
+		[ -z "${dstIp}" ] && exit 0
+
+        if /sbin/ifconfig br0 > /dev/null 2>&1;then
+            dev="br0"
+        else
+            dev="eth0"
+        fi
+
+		if ! /sbin/route -n | grep "${dstIp}" > /dev/null;then
+			/sbin/route add -net ${dstIp} netmask 255.255.255.255 dev ${dev}
+		fi
+		exit 0
+	;;
+
+	delRoute)
+		dstIp="$2"	
+		[ -z "${dstIp}" ] && exit 0
+
+        if /sbin/ifconfig br0 > /dev/null 2>&1;then
+            dev="br0"
+        else
+            dev="eth0"
+        fi
+
+		if /sbin/route -n | grep "${dstIp}" > /dev/null;then
+			/sbin/route del -net ${dstIp} netmask 255.255.255.255 dev ${dev}
+		fi
+		exit 0
+	;;
+
+    rebootIpc)
+        /usr/bin/curl --connect-timeout 1 -X GET "http://10.231.132.139/cgi-bin/web.cgi?action=reboot&cmd=system&username=admin&password=33e97a6101dce4c3ad589754e79b14adacc52d45"
+        exit 0
+    ;;
+
+    rebootIpcAndReboot)
+        $0 showReboot
+        $0 rebootIpc
+        sleep 1
+        /sbin/reboot
+        exit 0
+    ;;
+
+    setOnvifVol)
+        volume=${2}
+        /usr/sbin/redis-cli PUBLISH volume-value-channel "{\"onvif_volume\": ${volume}}"
+        ${SYSCONFCMD} ${VOLCONF} set volume onvif_volume ${volume}
+    ;;
+
+    startSyncTimeToIPAC)
+        $0 stopSyncTime
+        if [ ! -z "$2" ];then
+            delay=$2
+        else
+            delay=""
+        fi
+        server="`${SYSCONFCMD} ${SYSCONF} get account_info_1 server`"
+        model="`${SYSCONFCMD} ${SYSCONF} get system model`"
+        if [ "foo${model}" = "fooX10" ];then
+            interface="br0"
+        else
+            interface="eth0"
+        fi
+        if [ ! -z ${delay} ];then
+            /usr/sbin/ptpd2 -i ${interface} -s -U -g --ptpengine:log_delayreq_interval=1 --delay-override ${delay} -u ${server}
+        else
+            /usr/sbin/ptpd2 -i ${interface} -s -U -g --ptpengine:log_delayreq_interval=1 -u ${server}
+        fi
+
+        exit 0
+    ;;
+
+    startSyncTimeToPtpServer)
+        $0 stopSyncTime
+        enable="`${SYSCONFCMD} ${SYSCONF} get ptp enable`"
+        if [ "foo${enable}" = "fooyes" ];then
+            if [ ! -z "$2" ];then
+                delay=$2
+            else
+                delay=""
+            fi
+
+            server="`${SYSCONFCMD} ${SYSCONF} get ptp server`"
+            model="`${SYSCONFCMD} ${SYSCONF} get system model`"
+            if [ "foo${model}" = "fooX10" ];then
+                interface="br0"
+            else
+                interface="eth0"
+            fi
+            if [ ! -z ${delay} ];then
+                /usr/sbin/ptpd2 -i ${interface} -s -U -g --ptpengine:log_delayreq_interval=1 --delay-override ${delay} -u ${server}
+            else
+                /usr/sbin/ptpd2 -i ${interface} -s -U -g --ptpengine:log_delayreq_interval=1 -u ${server}
+            fi
+        fi
+
+        exit 0
+    ;;
+
+    stopSyncTime)
+        pid="`cat /var/run/ptpd2.lock | tr -d ' '`"
+        if [ ! -z "${pid}" ];then
+            /bin/kill -9  ${pid} > /dev/null 2>&1
+        fi
+        exit 0
+    ;;
+
+    set_sshd)
+        /etc/init.d/S50sshd restart
+    ;;
+
+    ai)
+        case $2 in
+            start)
+                enAIAgent="`${SYSCONFCMD} ${SYSCONF} get ai_settings enable`"
+                if [ "${enAIAgent}" = "yes" ];then
+                    tmp_hard_verssion="`/usr/bin/vendor_storage -r VENDOR_WIFI_MAC_ID | awk -F" " '{print $2}'`"
+                    hard_version=${tmp_hard_verssion: -2}
+                    if [ "${hard_version}" = "32" ];then
+                        echo 1 > /sys/class/gpio/gpio143/value
+                    else
+                        echo 1 > /sys/class/gpio/gpio134/value
+                    fi
+                    /etc/scripts/serial_ctrl &
+                fi
+            ;;
+            stop)
+                killall serial_ctrl > /dev/null 2>&1
+                tmp_hard_verssion="`/usr/bin/vendor_storage -r VENDOR_WIFI_MAC_ID | awk -F" " '{print $2}'`"
+                hard_version=${tmp_hard_verssion: -2}
+                if [ "${hard_version}" = "32" ];then
+                    echo 0 > /sys/class/gpio/gpio143/value
+                else
+                    echo 0 > /sys/class/gpio/gpio134/value
+                fi
+            ;;
+            restart)
+                $0 ai stop
+                $0 ai start
+            ;;
+        esac
+
+    ;;
+
+    set_onvif)
+        generate_config() {
+            if /sbin/ifconfig br0 > /dev/null 2>&1;then
+                dev="br0"
+            else
+                dev="eth0"
+            fi
+
+            model="`${SYSCONFCMD} ${SYSCONF} get system model`"
+            hardVersion="`${SYSCONFCMD} ${SYSCONF} get system hard_version`"
+            ip="`/sbin/ifconfig ${dev} | grep 'inet addr' | awk '{print $2}' | cut -d ':' -f2 | tr -d ' '`"
+            mac="`/sbin/ifconfig ${dev} | grep HWaddr | awk '{printf $5}' | sed 's/:/-/g'`"
+            softwareVersion="`${SYSCONFCMD} ${SYSCONF} get system firmware`"
+            Manufacturer="ZYCOO"
+            username="`${SYSCONFCMD} ${SYSCONF} get onvif username`"
+            password="`${SYSCONFCMD} ${SYSCONF} get onvif password`"
+            enMIC="`${SYSCONFCMD} ${SYSCONF} get onvif enable_mic`"
+            mode="`${SYSCONFCMD} ${SYSCONF} get onvif mode`"
+            SerialNumber="`/usr/bin/vendor_storage -r VENDOR_SN_ID | cut -d ":" -f2 | tr -d "\n" | tr -d " "`"
+            uuid="`cat /tmp/uuid`"
+            Mode="`${SYSCONFCMD} ${SYSCONF} get onvif relay_mode`"
+            DelayTime="`${SYSCONFCMD} ${SYSCONF} get onvif relay_delaytime`"
+            Type="`${SYSCONFCMD} ${SYSCONF} get onvif relay_type`"
+            case ${mode} in
+                1)
+                    quality=4
+                    fps=15
+                    bitrate=96
+                    auth=1
+                ;;
+                2|8)
+                    quality=5
+                    fps=30
+                    bitrate=160
+                    auth=1
+                ;;
+                10)
+                    quality=3
+                    fps=5
+                    bitrate=64
+                    auth=2
+                ;;
+                *)
+                    quality=3
+                    fps=5
+                    bitrate=64
+                    auth=1
+                ;;
+            esac
+
+            config="/oem/etc/config.xml"
+            [ ! -f ${config} ] && touch ${config}
+            cat << END > ${config}
+<?xml version="1.0" encoding="utf-8"?>
+<config>
+	<server_ip>${ip}</server_ip>
+	<server_port>8000</server_port>
+	<need_auth>${auth}</need_auth>
+	<auth_user>${username}</auth_user>
+	<auth_pass>${password}</auth_pass>
+	<discoverable>1</discoverable>
+	<merge_source>1</merge_source>
+	<information>
+		<Manufacturer>${Manufacturer}</Manufacturer>
+		<Model>${model}</Model>
+		<FirmwareVersion>${softwareVersion}</FirmwareVersion>
+		<SerialNumber>${SerialNumber}</SerialNumber>
+		<HardwareId>${hardVersion}</HardwareId>
+		<UUId>${uuid}</UUId>
+	</information>
+	<video_source_config>
+		<x min="0" max="100" />
+		<y min="0" max="100" />
+		<width min="320" max="1280" />
+		<height min="240" max="720" />
+	</video_source_config>
+	<profile>
+		<video_source>
+			<width>640</width>
+			<height>480</height>
+		</video_source>
+		<video_encoder>
+			<width>640</width>
+			<height>480</height>
+			<quality>${quality}</quality>
+			<session_timeout>10</session_timeout>
+			<framerate>${fps}</framerate>
+			<encoding_interval>1</encoding_interval>
+			<bitrate_limit>${bitrate}</bitrate_limit>
+			<encoding>H264</encoding>
+			<h264>
+				<gov_length>20</gov_length>
+				<h264_profile>Main</h264_profile>
+			</h264>
+		</video_encoder>
+		<audio_output></audio_output>
+		<audio_decoder>
+			<sample_rate>8</sample_rate>
+			<decoding>PCMU</decoding>
+		</audio_decoder>
+END
+if [ "foo${enMIC}" = "fooyes" ];then
+        cat << END >> ${config}
+		<audio_source></audio_source>
+		<audio_encoder>
+			<session_timeout>10</session_timeout>
+			<sample_rate>8</sample_rate>
+			<bitrate>64</bitrate>
+			<encoding>PCMU</encoding>
+		</audio_encoder>
+END
+fi
+        cat << END >> ${config}
+		<relay_output>
+			<mode>${Mode}</mode>
+			<delaytime>${DelayTime}</delaytime>
+			<idlestate>closed</idlestate>
+			<tpye>${Type}</tpye>
+		</relay_output>
+		<stream_uri>rtsp://${ip}:554/MainStream</stream_uri>
+	</profile>
+	<scope_fixed>onvif://www.onvif.org/Profile/Streaming</scope_fixed>
+	<scope_fixed>onvif://www.onvif.org/location/country/china</scope_fixed>
+	<scope_fixed>onvif://www.onvif.org/type/video_encoder</scope_fixed>
+	<scope_fixed>onvif://www.onvif.org/name/ZYCOO-IP-SPEAKER</scope_fixed>
+	<scope_fixed>onvif://www.onvif.org/hardware/${model}</scope_fixed>
+	<scope_config>onvif://www.onvif.org/acc/uuid/${uuid}</scope_config>
+	<scope_config>onvif://www.onvif.org/acc/mac/${mac}</scope_config>
+	<event>
+		<renew_interval>60</renew_interval>
+		<simulate_enable>0</simulate_enable>
+		<simulate_interval>10</simulate_interval>
+	</event>
+</config>
+END
+            sync
+        }
+
+        #生成配置文件
+        generate_config
+        enable="`${SYSCONFCMD} ${SYSCONF} get onvif enable`"
+        if [ "foo${enable}" = "fooyes" ];then
+            killall onvifserver > /dev/null 2>&1
+            killall rtspserver > /dev/null 2>&1
+            /etc/scripts/rtspserver > /dev/null 2>&1 &
+            sleep 1
+            /etc/scripts/onvifserver > /dev/null 2>&1 &
+        else
+            killall onvifserver > /dev/null 2>&1
+            killall rtspserver > /dev/null 2>&1
+        fi
+        exit 0
+    ;;
+
+    check_log_size)
+        cdr_log_file="/userdata/cdr.csv"
+        operation_log_file="/userdata/system.csv"
+        max_line=20000
+        remain_line=10000
+        total_lines=$(wc -l < "$cdr_log_file")
+        end_delelte_line=$((total_lines - remain_line))
+        if ((total_lines > max_line)); then
+            sed -i '1,'"$end_delelte_line"'d' "$cdr_log_file"
+        fi
+
+        total_lines=$(wc -l < "$operation_log_file")
+        end_delelte_line=$((total_lines - remain_line))
+        if ((total_lines > max_line)); then
+            redis-cli LPUSH writelog-channel "log_clean"
+            sed -i '1,'"$end_delelte_line"'d' "$operation_log_file"
+        fi
+    ;;
+
+    set_python_priority)
+        sleep 3
+        pid="`ps | grep ispeaker | grep -v grep | awk -F' ' '{print $1}'`"
+
+        if [ "foo${pid}" != "foo" ];then
+            loop=5
+            while [ $loop -gt 0 ]
+            do
+                echo "-1000" > /proc/${pid}/oom_score_adj
+                loop="`expr $loop - 1`"
+                usleep 200000
+            done
+        fi
+
+        exit 0
+    ;;
+
+    showReboot)
+        /usr/bin/curl --connect-timeout 2 http://127.0.0.1/api/show-start > /dev/null 2>&1 &
+        exit 0
+    ;;
+
+    *)
+        exit 0
+    ;;
+esac

BIN
etc/scripts/sipconf


+ 41 - 0
etc/scripts/sipphone.sh

@@ -0,0 +1,41 @@
+#!/bin/sh
+
+SPK_CONF="/etc/speaker.conf"
+SPHONE_CONF="/tmp/accounts"
+
+case "$1" in
+
+	start )
+		# config file abnormal
+		[ ! -f "${SPK_CONF}" ] && printf "Configration file not exist.\n" && exit 0
+
+        # prepare sip account conf
+        /etc/scripts/sipconf
+		[ ! -f "${SPHONE_CONF}" ] && printf "Configration file not exist.\n" && exit 0
+
+        #clear redis database
+        redis-cli FLUSHALL
+
+        # start baresip
+        if [ -n "`baresip -4 -d|egrep 'Illegal instruction|segment fault' 2>/dev/null`" ];then
+            /sbin/reboot
+            exit;
+        fi
+
+        # start baresip service
+        bareservice > /dev/null 2>&1 &
+
+		;;
+
+	stop )
+        redis-cli lpush control-channel '{"cmd":"quit","data":""}'
+		killall baresip > /dev/null 2>&1
+        killall bareservice > /dev/null 2>&1
+        #clear redis database
+        redis-cli FLUSHALL
+		;;
+
+	restart | reload )
+
+		/etc/scripts/sipphone.sh stop; sleep 1 ; /etc/scripts/sipphone.sh start
+esac

+ 19 - 0
etc/scripts/system_led.sh

@@ -0,0 +1,19 @@
+#!/bin/sh
+
+
+if [ ! -L /sys/class/gpio/gpio72 ];then
+	echo -e "create sys_led device\n"
+	echo 72 > /sys/class/gpio/export
+	echo out > /sys/class/gpio/gpio72/direction
+else
+	echo -e "sys_led device exist\n"
+fi
+
+while [ 1 ]
+do
+	sleep 1
+	echo 0 > /sys/class/gpio/gpio72/value
+	sleep 1
+	echo 1 > /sys/class/gpio/gpio72/value
+done
+

+ 43 - 0
etc/scripts/tcpdump.sh

@@ -0,0 +1,43 @@
+#!/bin/sh
+
+start()
+{
+	/etc/scripts/keep_tcpdump.sh start > /dev/null 2>&1 &
+}
+
+stop()
+{
+      /usr/bin/killall keep_tcpdump.sh > /dev/null 2>&1
+      /etc/scripts/keep_tcpdump.sh stop
+}
+
+restart()
+{
+        stop
+        sleep 2
+        start&
+}
+
+reload()
+{
+        stop
+        sleep 2
+        start&
+}
+
+case "$1" in
+  start)
+        start
+        ;;
+  stop)
+        stop
+        ;;
+  restart|reload)
+        restart
+        ;;
+  *)
+        echo "Usage: $0 {start|stop|restart}"
+        exit 1
+esac
+
+exit $?

+ 35 - 0
etc/scripts/trouble_shooting.sh

@@ -0,0 +1,35 @@
+#!/bin/sh
+
+type=$1
+action=$2
+para1=$3
+para2=$4
+
+case "$action" in
+start)
+        case "$type" in
+                tcpdump)
+                        /bin/rm -f /www/tcpdump.pcap
+                        /usr/sbin/tcpdump -w /www/tcpdump.pcap -i eth0 &
+                        /etc/scripts/watch_tool.sh &
+                        ;;
+                ping)
+                        /bin/ping "$para1" -c "$para2" 2> /www/ping.log| tee > /www/ping.log &
+                        ;;
+        esac
+        ;;
+stop)
+        case "$type" in
+                tcpdump)
+                        killall tcpdump
+                        ;;
+                ping)
+                        killall ping
+                        ;;
+        esac
+        ;;
+*)
+        echo "$0 mode = *"
+        ;;
+esac
+exit

+ 102 - 0
etc/scripts/upgrade.sh

@@ -0,0 +1,102 @@
+#!/bin/bash
+
+para="$1"
+
+case ${para} in
+    pre)
+        cd /userdata
+        rm -rf /userdata/*
+	    sync
+
+        [ ! -d /userdata/upgrade ] && mkdir -p /userdata/upgrade
+		[ ! -d /userdata/recovery ] && mkdir -p /userdata/recovery
+		[ ! -d /userdata/lost+found ] && mkdir -p /userdata/lost+found
+		[ ! -f /userdata/ispeaker.log ] && touch /userdata/ispeaker.log
+		[ ! -f /userdata/tmp_state.conf ] && touch /userdata/tmp_state.conf
+		[ ! -f /userdata/.pppoe_status ] && touch /userdata/.pppoe_status
+        cat << END > /userdata/tmp_state.conf
+[intercom]
+onekey_state=idle
+END
+
+        model="`sysconf /etc/speaker.conf get system ui_model`"
+		[ ! -d /userdata/cfg/eq_bin ] && mkdir -p /userdata/cfg/eq_bin
+		if [ ! -z ${model} ];then
+			if [ "foo${model}" = "fooSW15" -o "foo${model}" = "fooSW16" ];then
+				cp /oem/cfg/eq_bin/SW15.bin /userdata/cfg/eq_bin/Para_48000Hz_2ch.bin
+			elif [ "foo${model}" = "fooSC15" -o "foo${model}" = "fooSW16" ];then
+				cp /oem/cfg/eq_bin/SC15.bin /userdata/cfg/eq_bin/Para_48000Hz_2ch.bin
+			elif [ "foo${model}" = "fooSH30" ];then
+				cp /oem/cfg/eq_bin/SH30.bin /userdata/cfg/eq_bin/Para_48000Hz_2ch.bin
+			elif [ "foo${model}" = "fooSL50" ];then
+				cp /oem/cfg/eq_bin/SL50.bin /userdata/cfg/eq_bin/Para_48000Hz_2ch.bin
+			elif [ "foo${model}" = "fooSL30" ];then
+				cp /oem/cfg/eq_bin/SL30.bin /userdata/cfg/eq_bin/Para_48000Hz_2ch.bin
+			elif [ "foo${model}" = "fooSC10" ];then
+				cp /oem/cfg/eq_bin/SC10.bin /userdata/cfg/eq_bin/Para_48000Hz_2ch.bin
+            elif [ "foo${model}" = "fooSH10" ];then
+				cp /oem/cfg/eq_bin/SH30.bin /userdata/cfg/eq_bin/Para_48000Hz_2ch.bin
+			else
+				rm -rf /userdata/cfg/eq_bin/*
+			fi
+		else
+			rm -rf /userdata/cfg/eq_bin/*
+		fi
+        sync
+    ;;
+    *)
+        sync
+        [ ! -f ${para} ] && exit 1
+        model="`/etc/scripts/getmodel.sh`"
+        [ -z ${model} ] && exit 1
+        /bin/rk_parser ${para} ${model}
+        recode_check="$?"
+        if [ "foo${recode_check}" != "foo0" ];then
+            rm -rf ${para}
+            sync
+            exit 1
+        fi
+        sync
+
+        /etc/scripts/shell_action.sh showReboot
+        reset_default="`sysconf /etc/speaker.conf get upgrade reset_default`"
+        updatetime="`sysconf /etc/speaker.conf get upgrade date`"
+
+        if [ ! -f /userdata/updatetime.txt ];then
+            touch /userdata/updatetime.txt
+            cat << END > /userdata/updatetime.txt
+[upgrade]
+date=2019-12-02
+END
+        fi
+
+        sysconf /userdata/updatetime.txt set upgrade date ${updatetime}
+
+        if [ "foo${reset_default}" = "foono" ];then
+            rm -rf /oem/.upgrade
+            #/usr/bin/recoverySystem ota ${para}
+            updateEngine --image_url=${para} --misc=update --savepath=${para}  --reboot
+            recode="$?"
+            if [ "${recode}" = 255 ];then
+                touch /oem/.upgrade
+                rm -rf ${para}
+                sync
+                exit 1
+            fi
+        else
+            rm -rf /oem/.userdata
+            #/usr/bin/recoverySystem ota ${para}
+            updateEngine --image_url=${para} --misc=update --savepath=${para}  --reboot
+            recode="$?"
+            if [ "${recode}" = 255 ];then
+                touch /oem/.userdata
+                rm -rf ${para}
+                sync
+                exit 1
+            fi
+        fi
+esac
+
+sync
+
+exit 0

+ 43 - 0
etc/scripts/watch.sh

@@ -0,0 +1,43 @@
+#!/bin/sh
+
+start()
+{
+	/etc/scripts/watch_process.sh start > /dev/null 2>&1 &
+}
+
+stop()
+{
+      /usr/bin/killall watch_process.sh > /dev/null 2>&1
+      /etc/scripts/watch_process.sh stop
+}
+
+restart()
+{
+        stop
+        sleep 2
+        start&
+}
+
+reload()
+{
+        stop
+        sleep 2
+        start&
+}
+
+case "$1" in
+  start)
+        start
+        ;;
+  stop)
+        stop
+        ;;
+  restart|reload)
+        restart
+        ;;
+  *)
+        echo "Usage: $0 {start|stop|restart}"
+        exit 1
+esac
+
+exit $?

+ 196 - 0
etc/scripts/watch_process.sh

@@ -0,0 +1,196 @@
+#!/bin/bash
+wd_c=0
+free_c=0
+time_wait_c=0
+start()
+{
+        while [ 1 ]
+        do
+                HTTPD_STAT="`ps|grep speaker-cgi|grep -v grep`"
+                if [ -z "${HTTPD_STAT}" ];then
+                        killall speaker-cgi > /dev/null 2>&1
+                        sleep 1
+                        /etc/scripts/httpd.sh start
+                        wd_c=`expr $wd_c + 1`
+                fi
+
+                APIAGENT_STAT="`ps|grep api_agent|grep -v grep`"
+                if [ -z "${APIAGENT_STAT}" ];then
+                        /etc/scripts/api_agent &
+                fi
+
+                AICTRL_STAT="`ps|grep serial_ctrl|grep -v grep`"
+                if [ -z "${AICTRL_STAT}" ];then
+                        HWVer="`sysconf /etc/speaker.conf get system hard_version`"
+                        if [ ${HWVer:3:1} -ge 3 ];then
+                                /etc/scripts/shell_action.sh ai start
+                        fi
+                fi
+
+                REDIS_STAT="`ps|grep 'redis-server'|grep -v grep`"
+                if [ -z "${REDIS_STAT}" ];then
+                        /usr/sbin/redis-server /etc/redis.conf > /dev/null 2>&1 &
+                        wd_c=`expr $wd_c + 1`
+                fi
+
+                OUTPUTCTRL_STAT="`ps|grep output_control|grep -v grep`"
+                if [ -z "${OUTPUTCTRL_STAT}" ];then
+                        /etc/scripts/output_control &
+                fi
+
+                PROCESS_STAT="`ps|grep service_process|grep -v grep`"
+                if [ -z "${PROCESS_STAT}" ];then
+                        /etc/scripts/service_process &
+                fi
+
+                ISPEAKER_STAT="`ps|grep -w "python3 /app/ispeaker-service/ispeaker" |grep -v grep`"
+                if [ -z "${ISPEAKER_STAT}" ];then
+                        ISPEAKER_ENABLE="`sysconf /etc/speaker.conf get system broadcast_service`"
+                        SIP_ENABLE="`sysconf /etc/speaker.conf get account_info_1 enable`"
+                        MULTICAST_ENABLE="`sysconf /etc/speaker.conf get multicast_player enable`"
+                        if [ "foo${ISPEAKER_ENABLE}" = "fooyes" -a "foo${SIP_ENABLE}" = "fooyes" ] || [ "foo${MULTICAST_ENABLE}" = "fooyes" ];then
+                                if [ "foo${ISPEAKER_ENABLE}" = "fooyes" -a "foo${SIP_ENABLE}" = "fooyes" ];then
+                                        killall ptpd2 > /dev/null 2>&1
+                                        /etc/scripts/shell_action.sh startSyncTimeToIPAC
+                                else
+                                        killall ptpd2 > /dev/null 2>&1
+                                fi
+                                killall ispeaker > /dev/null 2>&1
+                                # sleep 1
+                                /etc/scripts/ispeaker start
+                                wd_c=`expr $wd_c + 1`
+                        fi
+                fi
+
+                WAIT_STAT=$(netstat -apn | grep 1883 | awk '{print $6}' | tr -d ' ')
+                if ! echo "$WAIT_STAT" | grep -q "ESTABLISHED" && echo "$WAIT_STAT" | grep -Eq "TIME_WAIT|CLOSE_WAIT|SYN_SENT|FIN_WAIT1"; then
+                        time_wait_c=`expr $time_wait_c + 1`
+                        if [ $time_wait_c -gt 3 ];then
+                                ISPEAKER_ENABLE="`sysconf /etc/speaker.conf get system broadcast_service`"
+                                SIP_ENABLE="`sysconf /etc/speaker.conf get account_info_1 enable`"
+                                if [ "foo${ISPEAKER_ENABLE}" = "fooyes" -a "foo${SIP_ENABLE}" = "fooyes" ];then
+                                        killall ispeaker > /dev/null 2>&1
+                                        sleep 1
+                                        /etc/scripts/ispeaker start
+                                        sleep 3
+                                        time_wait_c=0
+                                fi
+                        fi
+                else
+                        time_wait_c=0 
+                fi
+
+                PTP_STAT="`ps|grep -w ptpd2|grep -v grep`"
+                if [ -z "${PTP_STAT}" ];then
+                        PTP_ENABLE="`sysconf /etc/speaker.conf get ptp enable`"
+                        if [ "foo${PTP_ENABLE}" = "fooyes" ];then
+                                ISPEAKER_ENABLE="`sysconf /etc/speaker.conf get system broadcast_service`"
+                                SIP_ENABLE="`sysconf /etc/speaker.conf get account_info_1 enable`"
+                                if [ "foo${ISPEAKER_ENABLE}" = "foono" -o "foo${SIP_ENABLE}" = "foono" ];then
+                                        killall ptpd2 > /dev/null 2>&1
+                                        /etc/scripts/shell_action.sh startSyncTimeToPtpServer 
+                                fi
+                        else
+                                ISPEAKER_ENABLE="`sysconf /etc/speaker.conf get system broadcast_service`"
+                                SIP_ENABLE="`sysconf /etc/speaker.conf get account_info_1 enable`"
+                                if [ "foo${ISPEAKER_ENABLE}" = "fooyes" -a "foo${SIP_ENABLE}" = "fooyes" ];then
+                                        killall ptpd2 > /dev/null 2>&1
+                                        /etc/scripts/shell_action.sh startSyncTimeToIPAC
+                                fi
+                        fi
+                fi
+
+                ONVIFSERVER_STAT="`ps|grep -w onvifserver|grep -v grep`"
+                RTSPSERVER_STAT="`ps|grep -w rtspserver|grep -v grep`"
+                if [ -z "${ONVIFSERVER_STAT}" -o -z "${RTSPSERVER_STAT}" ];then
+                        ONVIF_ENABLE="`sysconf /etc/speaker.conf get onvif enable`"
+                        if [ "foo${ONVIF_ENABLE}" = "fooyes" ];then
+                                /etc/scripts/shell_action.sh set_onvif
+                        fi
+                fi
+
+                SIPPHONE_STAT="`ps|grep baresip|grep -v grep`"
+                SIPSEV_STAT="`ps|grep 'bareservice'|grep -v grep`"
+                if [ -z "${SIPPHONE_STAT}" -o -z "${SIPSEV_STAT}" ];then
+                        killall baresip > /dev/null 2>&1
+                        killall bareservice > /dev/null 2>&1
+                        # sleep 1
+                        /etc/scripts/sipphone.sh start
+                        wd_c=`expr $wd_c + 1`
+                fi
+
+                ONVIF_STAT="`ps|grep 'onvif-discover'|grep -v grep`"
+                if [ -z "${ONVIF_STAT}" ];then
+                        /etc/scripts/onvif-discover > /dev/null 2>&1 &
+                fi
+
+                EQ_STAT="`ps|grep 'eq_drc_process'|grep -v grep`"
+                if [ -z "${EQ_STAT}" ];then
+                        /usr/bin/eq_drc_process > /dev/null 2>&1 &
+                fi
+
+                SPEAKER_CONF_ERROR_STAT="`grep "\['" /oem/etc/speaker.conf`"
+                if [ ! -z "${SPEAKER_CONF_ERROR_STAT}" ];then
+                        sed -i "s/\['//g" /oem/etc/speaker.conf
+                        sed -i "s/'\]//g" /oem/etc/speaker.conf
+                        sed -i "s/', '//g" /oem/etc/speaker.conf
+                        sync
+                fi
+
+                VOLUME_CONF_ERROR_STAT="`grep "\['" /oem/etc/volctrl.conf`"
+                if [ ! -z "${VOLUME_CONF_ERROR_STAT}" ];then
+                        sed -i "s/\['//g" /oem/etc/volctrl.conf
+                        sed -i "s/'\]//g" /oem/etc/volctrl.conf
+                        sed -i "s/', '//g" /oem/etc/volctrl.conf
+                        sync
+                fi
+
+                [ $wd_c -gt 10 ] && /sbin/reboot
+
+                sleep 15
+        done
+}
+
+stop()
+{
+        # stop sipphone
+        /etc/scripts/sipphone.sh stop
+        # stop ispeaker
+        killall ispeaker > /dev/null 2>&1
+        killall service_process > /dev/null 2>&1
+        killall api_agent > /dev/null 2>&1
+        killall ptpd2 > /dev/null 2>&1
+        killall onvifserver > /dev/null 2>&1
+        killall rtspserver > /dev/null 2>&1
+}
+
+restart()
+{
+        stop
+        sleep 2
+        start&
+}
+
+reload()
+{
+        stop
+        sleep 2
+        start&
+}
+
+case "$1" in
+  start)
+        start
+        ;;
+  stop)
+        stop
+        ;;
+  restart|reload)
+        restart
+        ;;
+  *)
+        echo "Usage: $0 {start|stop|restart}"
+        exit 1
+esac
+
+exit $?

+ 14 - 0
etc/scripts/watch_tool.sh

@@ -0,0 +1,14 @@
+#!/bin/sh
+
+t=0
+while [ 1 ]
+do
+        sleep 1
+        t=`expr $t + 1`
+        if [ "`ps -e |grep tcpdump`" ] && [ $t -lt 600 ] ;then
+                continue
+        else
+                killall tcpdump 2>/dev/null
+                exit
+        fi
+done

+ 42 - 0
etc/scripts/webpid.sh

@@ -0,0 +1,42 @@
+#!/bin/sh
+
+start()
+{
+	/etc/scripts/set_webpid.sh > /dev/null 2>&1 &
+}
+
+stop()
+{
+      /usr/bin/killall set_webpid.sh > /dev/null 2>&1
+}
+
+restart()
+{
+        stop
+        sleep 2
+        start&
+}
+
+reload()
+{
+        stop
+        sleep 2
+        start&
+}
+
+case "$1" in
+  start)
+        start
+        ;;
+  stop)
+        stop
+        ;;
+  restart|reload)
+        restart
+        ;;
+  *)
+        echo "Usage: $0 {start|stop|restart}"
+        exit 1
+esac
+
+exit $?

Filskillnaden har hållts tillbaka eftersom den är för stor
+ 759 - 0
oem/etc/schedule.conf


+ 288 - 0
oem/etc/speaker.conf

@@ -0,0 +1,288 @@
+[system]
+firmware=s2.1.2.010
+hard_version=h1.0.1
+model=X10
+ui_model=X10
+language=cn
+broadcast_service=no
+route=local
+ip_assign=dhcp
+ipaddr=192.168.1.101
+netmask=255.255.255.0
+gateway=192.168.1.1
+dns1=114.114.114.114
+dns2=8.8.8.8
+enable_ntp=yes
+ntpserver=pool.ntp.org
+timezone=CST-8
+tzname=Asia/Chongqing
+location=**
+access_type=1
+music_auto_resume=no
+sshd=no
+
+[account_info_1]
+server=
+port=5060
+username=
+authuser=
+domain=
+passwd=
+enable=no
+reg_expires=180
+transport=udp
+autoanswer=yes
+sip_autoanswer=yes
+ringfile=ring.wav
+nat_mode=disabled
+stun_server=
+stun_port=3478
+nat_username=
+nat_password=
+keepalive=yes
+keepalive_interval=30
+
+[account_info_2]
+server=
+port=5060
+username=
+authuser=
+domain=
+passwd=
+enable=no
+reg_expires=180
+transport=udp
+autoanswer=yes
+sip_autoanswer=yes
+ringfile=ring.wav
+nat_mode=disabled
+stun_server=
+stun_port=3478
+nat_username=
+nat_password=
+keepalive=yes
+keepalive_interval=30
+
+[account_info_3]
+server=
+port=5060
+username=
+authuser=
+domain=
+passwd=
+enable=no
+reg_expires=180
+transport=udp
+autoanswer=yes
+sip_autoanswer=yes
+ringfile=ring.wav
+nat_mode=disabled
+stun_server=
+stun_port=3478
+nat_username=
+nat_password=
+keepalive=yes
+keepalive_interval=30
+
+[account_info_p2p]
+username=
+enable=no
+auth=no
+transport=udp
+autoanswer=yes
+sip_autoanswer=yes
+ringfile=ring.wav
+
+[sip_advance]
+localport=5060
+rtpstartport=10000
+rtpendport=20000
+rtptimeout=60
+jbufftype=adaptive
+echocancel=yes
+anr=yes
+agc=yes
+agc_max_gain=30
+agc_gate_threshold=-85
+cng=no
+
+[sip_function]
+answer_local_beep=no
+answer_local_beep_file=s_beep.wav
+answer_local_beep_volume=90
+answer_remote_beep=no
+answer_remote_beep_file=s_beep.wav
+answer_remote_beep_volume=90
+hangup_beep=no
+hangup_beep_file=e_beep.wav
+hangup_beep_volume=90
+second_call=hangup
+
+[ptp]
+enable=no
+server=
+
+[codec]
+g722=yes
+alaw=yes
+ulaw=yes
+opus=no
+
+[intercom]
+onekey_1_num=
+onekey_1_line=auto
+onekey_2_num=
+onekey_2_line=auto
+repress_1_cancel=no
+repress_2_cancel=no
+key_1_action=call
+key_2_action=call
+http_1_url=http://api.com/test1
+http_2_url=http://api.com/test2
+audio_1_file=alarm_tone1.wav
+audio_2_file=alarm_tone2.wav
+audio_1_repeat=3
+audio_2_repeat=3
+trigger_1_screen=no
+trigger_1_id=
+screen_1_duration=5
+trigger_2_screen=no
+trigger_2_id=
+screen_2_duration=5
+
+[relay_ctrl]
+dtmf=no
+dtmf_code=1*
+call_state=no
+state_info=incoming
+type=On
+mode=delay
+duration=5
+play_music=Disabled
+alarm=Disabled
+
+[led_ctrl]
+call_state=no
+state_info=incoming
+type=On
+mode=delay
+duration=5
+dtmf=no
+dtmf_code=2*
+play_music=Disabled
+alarm=Disabled
+
+[screen_ctrl]
+dtmf=no
+dtmf_code=2*
+play_music=Disabled
+alarm=Disabled
+call_state=no
+state_info=outgoing
+type=
+mode=delay
+duration=5
+
+[multicast_player]
+enable=no
+network_caching=30
+address1=rtp://@239.168.12.1:2000
+name1=Background-Music
+gpio1=Disabled
+screen1=Disabled
+address2=
+name2=
+gpio2=Disabled
+screen2=Disabled
+address3=
+name3=
+gpio3=Disabled
+screen3=Disabled
+address4=
+name4=
+gpio4=Disabled
+screen4=Disabled
+address5=
+name5=
+gpio5=Disabled
+screen5=Disabled
+address6=
+name6=
+gpio6=Disabled
+screen6=Disabled
+address7=
+name7=
+gpio7=Disabled
+screen7=Disabled
+address8=
+name8=
+gpio8=Disabled
+screen8=Disabled
+address9=
+name9=
+gpio9=Disabled
+screen9=Disabled
+
+[audio_collection]
+enable=no
+server=
+username=
+password=
+name=
+
+[call_action_url]
+incoming_enable=no
+incoming_url=
+outgoing_enable=no
+outgoing_url=
+answered_enable=no
+answered_url=
+hangup_enable=no
+hangup_url=
+
+[relay_action_url]
+on_enable=no
+on_url=
+off_enable=no
+off_url=
+
+[api]
+auth_enable=yes
+call_enable=no
+relay_enable=no
+player_enable=no
+screen_enable=no
+
+[secret]
+ui_username=admin
+ui_password=admin
+
+[auto_privisioning]
+mode=tftp
+address=10.10.1.5
+format=json
+
+[upgrade]
+reset_default=no
+date=2021-05-24
+
+[restart-timer]
+enable=no
+type=day
+day=1
+week=0
+hour=2
+minutes=0
+
+[onvif]
+enable=no
+username=admin
+password=admin
+relay_mode=Monostable
+relay_delaytime=3
+relay_type=On
+enable_mic=no
+
+[chromium_url]
+url=https://www.galaxynext.us/
+

+ 23 - 0
oem/etc/volctrl.conf

@@ -0,0 +1,23 @@
+[volume]
+volume_in=7
+volume_out=7
+hard_volume_control=on
+key_beep=no
+always_play_ip=no
+sip_volume=80
+onvif_volume=80
+broadcast_volume=80
+multicast_1_volume=80
+multicast_2_volume=80
+multicast_3_volume=80
+multicast_4_volume=80
+multicast_5_volume=80
+multicast_6_volume=80
+multicast_7_volume=80
+multicast_8_volume=80
+multicast_9_volume=80
+enable_threshold=no
+volume_threshold=-15
+
+[priority]
+value={"mebers":[{"priority": 1, "name": "SIP"},{"priority": 2, "name": "ONVIF"},{"priority": 3, "name": "MULTICAST"},{"priority": 4, "name": "BROADCAST"},{"priority": 5,"name":"SCHEDULER-AUDIO"}]}

BIN
usr/bin/bareservice


BIN
usr/bin/baresip


BIN
usr/bin/sysconf


BIN
usr/lib/aarch64-linux-gnu/libaec_bf_process.so


BIN
usr/lib/aarch64-linux-gnu/libbaresip.so


BIN
usr/lib/aarch64-linux-gnu/libbaresip.so.14


BIN
usr/lib/aarch64-linux-gnu/libbaresip.so.14.10.1


BIN
usr/lib/aarch64-linux-gnu/libcrypto.so.1.1


BIN
usr/lib/aarch64-linux-gnu/libdeflate.so.0


BIN
usr/lib/aarch64-linux-gnu/libhiredis.so


BIN
usr/lib/aarch64-linux-gnu/libhiredis.so.0.14


BIN
usr/lib/aarch64-linux-gnu/libjbig.so.0


BIN
usr/lib/aarch64-linux-gnu/libjpeg.so.8


+ 0 - 0
usr/lib/aarch64-linux-gnu/liblzma.so.5


Vissa filer visades inte eftersom för många filer har ändrats