aispeech 32 2mic: add new library
Change-Id: I55be40167f6a30033fc717beaf253cd765b9df4f Signed-off-by: Sun ChuanHu <aaron.sun@rock-chips.com>
This commit is contained in:
BIN
rk3308/aispeech-2mic-32bit/dds_client/audio/minor_wakeup.mp3
Executable file
BIN
rk3308/aispeech-2mic-32bit/dds_client/audio/minor_wakeup.mp3
Executable file
Binary file not shown.
BIN
rk3308/aispeech-2mic-32bit/dds_client/audio/vad_start_timeout2.mp3
Executable file
BIN
rk3308/aispeech-2mic-32bit/dds_client/audio/vad_start_timeout2.mp3
Executable file
Binary file not shown.
BIN
rk3308/aispeech-2mic-32bit/dds_client/audio/wakeup.mp3
Executable file
BIN
rk3308/aispeech-2mic-32bit/dds_client/audio/wakeup.mp3
Executable file
Binary file not shown.
@ -1,39 +0,0 @@
|
|||||||
#ifndef __AUDIO_PLAYER_H__
|
|
||||||
#define __AUDIO_PLAYER_H__
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
extern "C" {
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#define AUDIO_PLAYER_EXPORT __attribute ((visibility("default")))
|
|
||||||
|
|
||||||
#define AUDIO_PLAYER_EV_BEGIN 0x01
|
|
||||||
#define AUDIO_PLAYER_EV_START 0x02
|
|
||||||
#define AUDIO_PLAYER_EV_END 0x03
|
|
||||||
#define AUDIO_PLAYER_EV_ERROR 0x04
|
|
||||||
#define AUDIO_PLAYER_EV_PAUSED 0x05
|
|
||||||
#define AUDIO_PLAYER_EV_PLAYING 0x06
|
|
||||||
#define AUDIO_PLAYER_EV_STOPPED 0x07
|
|
||||||
|
|
||||||
typedef int (*audio_player_callback)(void *userdata, int ev);
|
|
||||||
typedef struct audio_player audio_player_t;
|
|
||||||
|
|
||||||
AUDIO_PLAYER_EXPORT audio_player_t *audio_player_new(audio_player_callback ccb, void *userdata);
|
|
||||||
AUDIO_PLAYER_EXPORT int audio_player_delete(audio_player_t *aplayer);
|
|
||||||
AUDIO_PLAYER_EXPORT int audio_player_play(audio_player_t *aplayer, char *path);
|
|
||||||
AUDIO_PLAYER_EXPORT int audio_player_pause(audio_player_t *aplayer);
|
|
||||||
AUDIO_PLAYER_EXPORT int audio_player_resume(audio_player_t *aplayer);
|
|
||||||
AUDIO_PLAYER_EXPORT int audio_player_stop(audio_player_t *aplayer);
|
|
||||||
|
|
||||||
AUDIO_PLAYER_EXPORT int audio_player_get_volume(char *dev, int *l_vol, int *r_vol);
|
|
||||||
AUDIO_PLAYER_EXPORT int audio_player_set_volume(char *dev, int l_vol, int r_vol);
|
|
||||||
|
|
||||||
AUDIO_PLAYER_EXPORT int audio_player_set_channel_volume(audio_player_t *aplayer, float multiplier);
|
|
||||||
|
|
||||||
AUDIO_PLAYER_EXPORT int audio_player_set_device(audio_player_t *aplayer, char *device);
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif
|
|
||||||
@ -1,92 +0,0 @@
|
|||||||
/*================================================================
|
|
||||||
* * Copyright (C) 2018 AISpeech Ltd. All rights reserved.
|
|
||||||
* *
|
|
||||||
* * 文件名称:dds_client.h
|
|
||||||
* * 创建日期:2018年04月06日
|
|
||||||
* * 描 述:
|
|
||||||
* *
|
|
||||||
* ================================================================*/
|
|
||||||
|
|
||||||
|
|
||||||
#ifndef _DDS_CLIENT_H
|
|
||||||
#define _DDS_CLIENT_H
|
|
||||||
#ifdef __cplusplus
|
|
||||||
extern "C"
|
|
||||||
{
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#define DDS_CLIENT_VERSION "DDS_CLIENT 0.1.10"
|
|
||||||
|
|
||||||
#define DDS_CLIENT_TTS_ZHILING "zhilingf" // 甜美女神
|
|
||||||
#define DDS_CLIENT_TTS_GDG "gdgm" // 沉稳纲叔
|
|
||||||
#define DDS_CLIENT_TTS_GEYOU "geyou" // 淡定葛爷
|
|
||||||
#define DDS_CLIENT_TTS_HYANIF "hyanif" // 邻家女声
|
|
||||||
#define DDS_CLIENT_TTS_XIJUNM "xijunm" // 标准男声
|
|
||||||
#define DDS_CLIENT_TTS_QIANRAN "qianranf" // 可爱童声
|
|
||||||
#define DDS_CLIENT_TTS_LUCYF "lucyf" // 标准女声
|
|
||||||
|
|
||||||
#define DDS_CLIENT_USER_EV_BASE 1000
|
|
||||||
#define DDS_CLIENT_USER_DEVICE_MODE 1001
|
|
||||||
|
|
||||||
struct dds_client;
|
|
||||||
|
|
||||||
typedef void (*ddsLintener)(const char *topic, const char *topic_data, void *user);
|
|
||||||
|
|
||||||
struct dds_client *dds_client_init (const char *config_json);
|
|
||||||
|
|
||||||
int dds_client_start(struct dds_client *, ddsLintener cb, void *user);
|
|
||||||
|
|
||||||
void dds_client_release(struct dds_client *);
|
|
||||||
|
|
||||||
// 发送事件给 sdk
|
|
||||||
int dds_client_publish(struct dds_client *ds, int ev, const char *data);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* 对 nativeAPI 命令做出查询回应的接口,其中 native_api_data_json 的格式如下:
|
|
||||||
* duiWidget 字段表示 dui 控件的类型,当前仅支持 "text"。
|
|
||||||
* extra 字段用于返回用户的数据。
|
|
||||||
* {
|
|
||||||
* "duiWidget":"text",
|
|
||||||
* "extra": {
|
|
||||||
* "xx": "11"
|
|
||||||
* }
|
|
||||||
* }
|
|
||||||
* 出错时返回值为 -1。
|
|
||||||
*/
|
|
||||||
int dds_client_resp_nativeapi(struct dds_client *ds, const char *native_api,
|
|
||||||
const char *native_api_data_json);
|
|
||||||
/*
|
|
||||||
* 录音机接口
|
|
||||||
*/
|
|
||||||
int dds_client_feed_audio(struct dds_client *ds, char *data, int len);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* 对话的接口
|
|
||||||
*/
|
|
||||||
int dds_client_stop_dialog(struct dds_client *ds);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* tts 的相关接口
|
|
||||||
*/
|
|
||||||
int dds_client_speak(struct dds_client *ds, const char *text);
|
|
||||||
char *dds_client_get_speaker(struct dds_client *ds);
|
|
||||||
float dds_client_get_speed(struct dds_client *ds);
|
|
||||||
int dds_client_get_volume(struct dds_client *ds);
|
|
||||||
|
|
||||||
int dds_client_set_speaker(struct dds_client *ds, char *speaker);
|
|
||||||
int dds_client_set_speed(struct dds_client *ds, float speed);
|
|
||||||
int dds_client_set_volume(struct dds_client *ds, int vol);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* 唤醒的相关设置
|
|
||||||
*/
|
|
||||||
int dds_client_disable_wakeup(struct dds_client *ds);
|
|
||||||
int dds_client_enable_wakeup(struct dds_client *ds);
|
|
||||||
int dds_client_update_customword(struct dds_client *ds, const char *word);
|
|
||||||
char* dds_client_get_wakeupwords(struct dds_client *ds);
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
#endif //DDS_CLIENT_H
|
|
||||||
|
|
||||||
@ -1,35 +0,0 @@
|
|||||||
LOCAL_MODULE := demo_main
|
|
||||||
LOCAL_SRC_FILES += main.c
|
|
||||||
LOCAL_SRC_DIRS += json
|
|
||||||
|
|
||||||
LOCAL_CFLAGS := -rdynamic -g -O0 -Wall -DMG_ENABLE_THREADS -Wno-unused-variable -fPIC
|
|
||||||
LOCAL_CFLAGS += -I.. -Ijson/ -Ibutton/ -Ibusserver/mongoose -Ibusserver/src
|
|
||||||
|
|
||||||
LOCAL_CFLAGS += -DRK3308_BOARD_V11
|
|
||||||
|
|
||||||
LOCAL_LDFLAGS += -Wl,-rpath,../
|
|
||||||
LOCAL_LDFLAGS += -L../ -ldds_client
|
|
||||||
|
|
||||||
LOCAL_LDFLAGS += -Wl,-rpath,../libs/
|
|
||||||
#LOCAL_LDFLAGS += -L../libs/ -lduilite_normal
|
|
||||||
LOCAL_LDFLAGS += -L../libs/ -lduilite_fespl
|
|
||||||
#LOCAL_LDFLAGS += -L../libs/ -lduilite_fespa
|
|
||||||
LOCAL_LDFLAGS += -L../libs/ -lauth
|
|
||||||
LOCAL_LDFLAGS += -L../libs/ -ldds
|
|
||||||
LOCAL_LDFLAGS += -L../libs/ -laudio_play
|
|
||||||
LOCAL_LDFLAGS += -lpthread
|
|
||||||
LOCAL_LDFLAGS += -lasound
|
|
||||||
|
|
||||||
|
|
||||||
LOCAL_CXXFLAGS := LOCAL_CFLAGS -rdynamic
|
|
||||||
|
|
||||||
CC = ../../../../../../buildroot/output/rockchip_rk3308_32_release/host/usr/bin/arm-rockchip-linux-gnueabihf-gcc
|
|
||||||
|
|
||||||
CFLAGS += $(LOCAL_CFLAGS)
|
|
||||||
|
|
||||||
demo_main: main.o music.o json/cJSON.o busserver/src/busserver.o busserver/mongoose/mongoose.c
|
|
||||||
$(CC) -o $@ $^ $(CFLAGS) $(LOCAL_LDFLAGS) -lm
|
|
||||||
|
|
||||||
clean:
|
|
||||||
rm -f demo_main
|
|
||||||
rm -f *.o
|
|
||||||
@ -1,26 +0,0 @@
|
|||||||
LOCAL_MODULE := demo_main
|
|
||||||
LOCAL_SRC_FILES += main.c
|
|
||||||
LOCAL_SRC_FILES += music.c
|
|
||||||
LOCAL_SRC_DIRS += json
|
|
||||||
#LOCAL_SRC_DIRS += button
|
|
||||||
LOCAL_SRC_DIRS += busserver/mongoose
|
|
||||||
LOCAL_SRC_DIRS += busserver/src/busserver.c
|
|
||||||
|
|
||||||
LOCAL_CFLAGS := -rdynamic -g -O0 -Wall -DMG_ENABLE_THREADS -Wno-unused-variable -fPIC
|
|
||||||
LOCAL_CFLAGS += -I.. -Ijson/ -Ibutton/ -Ibusserver/mongoose -Ibusserver/src
|
|
||||||
|
|
||||||
LOCAL_LDFLAGS += -Wl,-rpath,../
|
|
||||||
LOCAL_LDFLAGS += -L../ -ldds_client
|
|
||||||
|
|
||||||
LOCAL_LDFLAGS += -Wl,-rpath,../libs/
|
|
||||||
LOCAL_LDFLAGS += -L../libs/ -lduilite_fespl
|
|
||||||
LOCAL_LDFLAGS += -L../libs/ -lauth
|
|
||||||
LOCAL_LDFLAGS += -L../libs/ -ldds
|
|
||||||
LOCAL_LDFLAGS += -L../libs/ -laudio_play
|
|
||||||
LOCAL_LDFLAGS += -lpthread
|
|
||||||
LOCAL_LDFLAGS += -lasound
|
|
||||||
|
|
||||||
|
|
||||||
LOCAL_CXXFLAGS := LOCAL_CFLAGS -rdynamic
|
|
||||||
|
|
||||||
include $(BUILD_EXECUTABLE)
|
|
||||||
Binary file not shown.
@ -1,12 +0,0 @@
|
|||||||
LOCAL_MODULE := test
|
|
||||||
LOCAL_SRC_DIRS += mongoose
|
|
||||||
LOCAL_SRC_DIRS += src
|
|
||||||
|
|
||||||
LOCAL_CFLAGS := -rdynamic -g -O0 -Wall -DMG_ENABLE_THREADS -Wno-unused-variable -fPIC
|
|
||||||
LOCAL_CFLAGS += -Imongoose
|
|
||||||
|
|
||||||
LOCAL_LDFLAGS += -lpthread
|
|
||||||
|
|
||||||
LOCAL_CXXFLAGS := LOCAL_CFLAGS -rdynamic
|
|
||||||
|
|
||||||
include $(BUILD_EXECUTABLE)
|
|
||||||
@ -1,16 +0,0 @@
|
|||||||
Copyright (c) 2004-2013 Sergey Lyubka <valenok@gmail.com>
|
|
||||||
Copyright (c) 2013-2016 Cesanta Software Limited
|
|
||||||
All rights reserved
|
|
||||||
|
|
||||||
This software is dual-licensed: you can redistribute it and/or modify
|
|
||||||
it under the terms of the GNU General Public License version 2 as
|
|
||||||
published by the Free Software Foundation. For the terms of this
|
|
||||||
license, see <http://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
You are free to use this software under the terms of the GNU General
|
|
||||||
Public License, but WITHOUT ANY WARRANTY; without even the implied
|
|
||||||
warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
|
||||||
See the GNU General Public License for more details.
|
|
||||||
|
|
||||||
Alternatively, you can license this software under a commercial
|
|
||||||
license, as set out in <https://www.cesanta.com/license>.
|
|
||||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
Binary file not shown.
@ -1,188 +0,0 @@
|
|||||||
/*================================================================
|
|
||||||
* Copyright (C) 2018 FREEDOM Ltd. All rights reserved.
|
|
||||||
*
|
|
||||||
* 文件名称:busserver.c
|
|
||||||
* 创 建 者:chenjie.gu
|
|
||||||
* 创建日期:2018年05月23日
|
|
||||||
* 描 述:
|
|
||||||
*
|
|
||||||
================================================================*/
|
|
||||||
|
|
||||||
|
|
||||||
#include "busserver.h"
|
|
||||||
#include "mongoose.h"
|
|
||||||
|
|
||||||
#define BUSCLIENT_KEEPALIVE 1
|
|
||||||
#define BUSCLIENT_RPC_REQUEST 2
|
|
||||||
#define BUSCLIENT_RPC_RESPONSE 3
|
|
||||||
#define BUSCLIENT_SEND_TOPIC 4
|
|
||||||
#define BUSCLIENT_RECV_TOPIC 5
|
|
||||||
|
|
||||||
struct mg_connection *conn = NULL;
|
|
||||||
event_cb user_cb = NULL;
|
|
||||||
void *user = NULL;
|
|
||||||
|
|
||||||
struct message {
|
|
||||||
struct multipart bm;
|
|
||||||
};
|
|
||||||
|
|
||||||
static int find_in_str(const char *p)
|
|
||||||
{
|
|
||||||
char *pos = strstr(p, "\r\n");
|
|
||||||
if (pos == NULL) {
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
return pos - p;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int busclient_parse_multipart_msg(struct mg_connection *nc, struct message *msg, int *type)
|
|
||||||
{
|
|
||||||
const char *pp = nc->recv_mbuf.buf;
|
|
||||||
const char *p = pp;
|
|
||||||
int len = nc->recv_mbuf.len;
|
|
||||||
int handle_len = 0, reserve_len = len, part_len = 0, _len = 0, n = 0;
|
|
||||||
|
|
||||||
for (int i = 0; i < BUSCLIENT_MAX_MULTIPART_OPT; ++i) {
|
|
||||||
_len = find_in_str(p);
|
|
||||||
part_len = atoi(p);
|
|
||||||
if( reserve_len >= _len+2+part_len+2 && strncmp(p+_len,"\r\n",2)==0 && strncmp(p+_len+2+part_len, "\r\n", 2) == 0) {
|
|
||||||
msg->bm.part[n].len = part_len;
|
|
||||||
msg->bm.part[n].data = p + _len + 2;
|
|
||||||
n++;
|
|
||||||
msg->bm.n = n;
|
|
||||||
} else {
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
handle_len = handle_len + _len + 2 + part_len + 2;
|
|
||||||
reserve_len = len - handle_len;
|
|
||||||
p = pp + handle_len;
|
|
||||||
|
|
||||||
if (reserve_len >=2 && strncmp(p, "\r\n", 2) == 0) {
|
|
||||||
if (strncmp(msg->bm.part[0].data, "keepalive", strlen("keepalive")) == 0) {
|
|
||||||
*type = BUSCLIENT_KEEPALIVE;
|
|
||||||
}
|
|
||||||
if (strncmp(msg->bm.part[0].data, "request", strlen("request")) == 0) {
|
|
||||||
*type = BUSCLIENT_RPC_REQUEST;
|
|
||||||
}
|
|
||||||
if (strncmp(msg->bm.part[0].data, "response", strlen("response")) == 0) {
|
|
||||||
*type = BUSCLIENT_RPC_RESPONSE;
|
|
||||||
}
|
|
||||||
if (strncmp(msg->bm.part[0].data, "publish", strlen("publish")) == 0) {
|
|
||||||
*type = BUSCLIENT_RECV_TOPIC;
|
|
||||||
}
|
|
||||||
return handle_len + 2;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void busclient_mg_send(struct mg_connection *nc, const char *data, int len)
|
|
||||||
{
|
|
||||||
char tmp[10] = { 0 };
|
|
||||||
int _len = 0;
|
|
||||||
|
|
||||||
_len = sprintf(tmp, "%d", len);
|
|
||||||
mg_send(nc, tmp, _len);
|
|
||||||
mg_send(nc, "\r\n", 2);
|
|
||||||
mg_send(nc, data, len);
|
|
||||||
mg_send(nc, "\r\n", 2);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void busclient_multipart_send(struct mg_connection *nc, struct multipart *bm) {
|
|
||||||
for (int i = 0; i < bm->n; i++) {
|
|
||||||
busclient_mg_send(nc, bm->part[i].data, bm->part[i].len);
|
|
||||||
}
|
|
||||||
mg_send(nc, "\r\n", 2);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static void handle_multipart_msg(struct mg_connection *nc, struct message *msg) {
|
|
||||||
if (!strncmp(msg->bm.part[0].data, "request", msg->bm.part[0].len)) {
|
|
||||||
if (!strncmp(msg->bm.part[1].data, "/bus/join", msg->bm.part[1].len)) {
|
|
||||||
struct multipart m = {1, {
|
|
||||||
{strlen("response"), "response"}
|
|
||||||
}};
|
|
||||||
|
|
||||||
busclient_multipart_send(nc, &m);
|
|
||||||
}
|
|
||||||
else if (!strncmp(msg->bm.part[1].data, "/bus/subscribe", msg->bm.part[1].len)) {
|
|
||||||
struct multipart m = {1, {
|
|
||||||
{strlen("response"), "response"}
|
|
||||||
}};
|
|
||||||
|
|
||||||
busclient_multipart_send(nc, &m);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
else if (!strncmp(msg->bm.part[0].data, "publish", msg->bm.part[0].len)) {
|
|
||||||
if (!strncmp(msg->bm.part[1].data, "ui.control.topics", msg->bm.part[1].len)) {
|
|
||||||
if (user_cb) {
|
|
||||||
user_cb("ui.control.topics", msg->bm.part[2].data, msg->bm.part[2].len, user);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void ev_handler(struct mg_connection *nc, int ev, void *p) {
|
|
||||||
struct mbuf *io = &nc->recv_mbuf;
|
|
||||||
(void) p;
|
|
||||||
|
|
||||||
switch (ev) {
|
|
||||||
case MG_EV_RECV:
|
|
||||||
conn = nc;
|
|
||||||
// receive multipart
|
|
||||||
int len = 0, type = 0;
|
|
||||||
struct message msg;
|
|
||||||
while (1) {
|
|
||||||
len = busclient_parse_multipart_msg(nc, &msg, &type);
|
|
||||||
if (len == -1 || type == 0) break;
|
|
||||||
handle_multipart_msg(nc, &msg);
|
|
||||||
mbuf_remove(&nc->recv_mbuf, len);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case MG_EV_TIMER:
|
|
||||||
{
|
|
||||||
struct multipart *m = (struct multipart *)p;
|
|
||||||
busclient_multipart_send(nc, m);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void busserver_run(const char *addr, event_cb cb, void *u) {
|
|
||||||
//
|
|
||||||
struct mg_mgr mgr;
|
|
||||||
mg_mgr_init(&mgr, NULL);
|
|
||||||
mg_bind(&mgr, addr, ev_handler);
|
|
||||||
|
|
||||||
user_cb = cb;
|
|
||||||
user = u;
|
|
||||||
|
|
||||||
for (;;) {
|
|
||||||
mg_mgr_poll(&mgr, 100);
|
|
||||||
}
|
|
||||||
|
|
||||||
mg_mgr_free(&mgr);
|
|
||||||
}
|
|
||||||
|
|
||||||
int busserver_send_msg(const char *topic, const char *data) {
|
|
||||||
|
|
||||||
if (!topic) return -1;
|
|
||||||
|
|
||||||
struct multipart m = {3, {
|
|
||||||
{strlen("publish"), "publish"},
|
|
||||||
{strlen(topic), topic},
|
|
||||||
{strlen(data), data}
|
|
||||||
}};
|
|
||||||
|
|
||||||
if (conn)
|
|
||||||
ev_handler(conn, MG_EV_TIMER, &m);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
@ -1,31 +0,0 @@
|
|||||||
#ifndef BUSSERVER_H_
|
|
||||||
#define BUSSERVER_H_
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
extern "C" {
|
|
||||||
#endif
|
|
||||||
|
|
||||||
struct bc_str {
|
|
||||||
int len;
|
|
||||||
const char *data;
|
|
||||||
};
|
|
||||||
|
|
||||||
#define BUSCLIENT_MAX_MULTIPART_OPT 20
|
|
||||||
|
|
||||||
struct multipart {
|
|
||||||
int n;
|
|
||||||
// int capacity;
|
|
||||||
struct bc_str part[BUSCLIENT_MAX_MULTIPART_OPT];
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef void (*event_cb)(const char *topic, const char *topic_data, int data_len, void *user);
|
|
||||||
|
|
||||||
void busserver_run(const char *addr, event_cb, void *user);
|
|
||||||
|
|
||||||
int busserver_send_msg(const char *topic, const char *data);
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
#endif
|
|
||||||
|
|
||||||
Binary file not shown.
@ -1,43 +0,0 @@
|
|||||||
/*================================================================
|
|
||||||
* Copyright (C) 2018 FREEDOM Ltd. All rights reserved.
|
|
||||||
*
|
|
||||||
* 文件名称:main.c
|
|
||||||
* 创 建 者:chenjie.gu
|
|
||||||
* 创建日期:2018年05月23日
|
|
||||||
* 描 述:
|
|
||||||
*
|
|
||||||
================================================================*/
|
|
||||||
|
|
||||||
#include "busserver.h"
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <sys/select.h>
|
|
||||||
#include <pthread.h>
|
|
||||||
|
|
||||||
void cb(const char *topic, const char *topic_data, void *user) {
|
|
||||||
|
|
||||||
printf("%s: %s\n", topic, topic_data);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
void *busserver_routine(void *user) {
|
|
||||||
busserver_run("127.0.0.1:50001", cb, NULL);
|
|
||||||
return (void *)0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int main () {
|
|
||||||
//
|
|
||||||
//
|
|
||||||
|
|
||||||
int ret = 0;
|
|
||||||
pthread_t tid;
|
|
||||||
ret = pthread_create(&tid, NULL, busserver_routine, NULL);
|
|
||||||
|
|
||||||
struct timeval tv = {10, 0};
|
|
||||||
select(0, 0, 0, 0, &tv);
|
|
||||||
|
|
||||||
busserver_send_msg("bus.event", "yyyyyyyyyyy");
|
|
||||||
|
|
||||||
select(0, 0, 0, 0, 0);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
Binary file not shown.
Binary file not shown.
@ -1,55 +0,0 @@
|
|||||||
#ifndef BUTTON_H
|
|
||||||
#define BUTTON_H
|
|
||||||
#ifdef __cplusplus
|
|
||||||
extern "C" {
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
typedef enum {
|
|
||||||
//短按触发
|
|
||||||
BUTTON_EVENT_VOLUME_ADD = 0,
|
|
||||||
//短按触发
|
|
||||||
BUTTON_EVENT_VOLUME_SUB,
|
|
||||||
//长按每隔1.5秒触发一次
|
|
||||||
BUTTON_EVENT_PREV,
|
|
||||||
//长按每隔1.5秒触发一次
|
|
||||||
BUTTON_EVENT_NEXT,
|
|
||||||
//短按触发
|
|
||||||
BUTTON_EVENT_PLAY_PAUSE,
|
|
||||||
//长按1.5秒后触发
|
|
||||||
BUTTON_EVENT_PLAY_PAUSE_LONG,
|
|
||||||
//短按触发
|
|
||||||
BUTTON_EVENT_MUTE_UNMUTE,
|
|
||||||
//长按1.5秒触发
|
|
||||||
BUTTON_EVENT_MUTE_UNMUTE_LONG,
|
|
||||||
//长按3秒触发
|
|
||||||
BUTTON_EVENT_MODE_WIFI,
|
|
||||||
//短按触发
|
|
||||||
BUTTON_EVENT_MODE_NORMAL,
|
|
||||||
BUTTON_EVENT_MAX
|
|
||||||
}button_event_t;
|
|
||||||
|
|
||||||
|
|
||||||
typedef void (*button_event_cb)(button_event_t ev, void *userdata);
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
char *dev;
|
|
||||||
button_event_cb cb;
|
|
||||||
void *userdata;
|
|
||||||
}button_config_t;
|
|
||||||
|
|
||||||
typedef struct button* button_handle_t;
|
|
||||||
|
|
||||||
button_handle_t button_create(button_config_t *config);
|
|
||||||
|
|
||||||
//默认内部100ms检查一次
|
|
||||||
int button_run(button_handle_t self);
|
|
||||||
int button_run2(button_handle_t self, int ms);
|
|
||||||
|
|
||||||
void button_destroy(button_handle_t self);
|
|
||||||
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
#endif
|
|
||||||
@ -1,224 +0,0 @@
|
|||||||
#include "button.h"
|
|
||||||
#include <stdbool.h>
|
|
||||||
#include <pthread.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <linux/input.h>
|
|
||||||
#include <sys/types.h>
|
|
||||||
#include <sys/stat.h>
|
|
||||||
#include <fcntl.h>
|
|
||||||
#include <assert.h>
|
|
||||||
#include <unistd.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include <stdint.h>
|
|
||||||
|
|
||||||
struct button{
|
|
||||||
pthread_t pid;
|
|
||||||
int fd;
|
|
||||||
button_event_cb cb;
|
|
||||||
void *userdata;
|
|
||||||
};
|
|
||||||
|
|
||||||
//RK3308麦克风采集自带5个按键,按键设备为/dev/input/event1,每个按键的code码如下:
|
|
||||||
|
|
||||||
typedef enum {
|
|
||||||
//短按代表音量加;长按代表上一首
|
|
||||||
PHY_BUTTON_CODE_VOLUME_ADD = 115,
|
|
||||||
|
|
||||||
//短按代表音量减;长按代表下一首
|
|
||||||
PHY_BUTTON_CODE_VOLUME_SUB = 114,
|
|
||||||
|
|
||||||
//只支持短按
|
|
||||||
PHY_BUTTON_CODE_MUTE = 248,
|
|
||||||
|
|
||||||
//只支持短按
|
|
||||||
PHY_BUTTON_CODE_PLAY_PAUSE = 207,
|
|
||||||
|
|
||||||
//长按代表进入配网模式
|
|
||||||
PHY_BUTTON_CODE_MODE = 373
|
|
||||||
}phy_button_code_t;
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
int val;
|
|
||||||
struct timeval last_time;
|
|
||||||
bool long_pressed;
|
|
||||||
}phy_button_t;
|
|
||||||
|
|
||||||
#define PHY_BUTTON_NUM 5
|
|
||||||
|
|
||||||
static bool is_long_pressed(struct timeval *now, struct timeval *before, int interval) {
|
|
||||||
int64_t expire = now->tv_sec * 1000 + now->tv_usec / 1000 - (before->tv_sec * 1000 + before->tv_usec / 1000);
|
|
||||||
if (expire >= interval) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
int button_run(button_handle_t self) {
|
|
||||||
return button_run2(self, 100);
|
|
||||||
}
|
|
||||||
|
|
||||||
int button_run2(button_handle_t self, int ms) {
|
|
||||||
|
|
||||||
fd_set rfd;
|
|
||||||
struct timeval tv;
|
|
||||||
struct input_event ev;
|
|
||||||
int ret;
|
|
||||||
|
|
||||||
phy_button_t buttons[PHY_BUTTON_NUM];
|
|
||||||
memset(buttons, 0, sizeof(buttons));
|
|
||||||
/*
|
|
||||||
buttons[0] ---> PHY_BUTTON_CODE_VOLUME_ADD
|
|
||||||
buttons[1] ---> PHY_BUTTON_CODE_VOLUME_SUB
|
|
||||||
buttons[2] ---> PHY_BUTTON_CODE_MUTE
|
|
||||||
buttons[3] ---> PHY_BUTTON_CODE_PLAY_PAUSE
|
|
||||||
buttons[4] ---> PHY_BUTTON_CODE_MODE
|
|
||||||
*/
|
|
||||||
|
|
||||||
while (1) {
|
|
||||||
tv.tv_sec = 0;
|
|
||||||
tv.tv_usec = ms * 1000;
|
|
||||||
FD_ZERO(&rfd);
|
|
||||||
FD_SET(self->fd, &rfd);
|
|
||||||
|
|
||||||
ret = select(self->fd + 1, &rfd, NULL, NULL, &tv);
|
|
||||||
if (ret == 0) {
|
|
||||||
struct timeval now;
|
|
||||||
gettimeofday(&now, NULL);
|
|
||||||
//if (buttons[0].long_pressed == false && buttons[0].val == 1 && is_long_pressed(&now, &buttons[0].last_time, 1500)) {
|
|
||||||
if (buttons[0].val == 1 && is_long_pressed(&now, &buttons[0].last_time, 1500)) {
|
|
||||||
self->cb(BUTTON_EVENT_PREV, self->userdata);
|
|
||||||
buttons[0].long_pressed = true;
|
|
||||||
buttons[0].last_time = now;
|
|
||||||
//} else if (buttons[1].long_pressed == false && buttons[1].val == 1 && is_long_pressed(&now, &buttons[1].last_time, 1500)) {
|
|
||||||
} else if (buttons[1].val == 1 && is_long_pressed(&now, &buttons[1].last_time, 1500)) {
|
|
||||||
self->cb(BUTTON_EVENT_NEXT, self->userdata);
|
|
||||||
buttons[1].long_pressed = true;
|
|
||||||
buttons[1].last_time = now;
|
|
||||||
} else if (buttons[2].long_pressed == false && buttons[2].val == 1 && is_long_pressed(&now, &buttons[2].last_time, 1500)) {
|
|
||||||
buttons[2].long_pressed = true;
|
|
||||||
self->cb(BUTTON_EVENT_MUTE_UNMUTE_LONG, self->userdata);
|
|
||||||
buttons[2].long_pressed = true;
|
|
||||||
buttons[2].last_time = now;
|
|
||||||
} else if (buttons[3].long_pressed == false && buttons[3].val == 1 && is_long_pressed(&now, &buttons[3].last_time, 1500)) {
|
|
||||||
buttons[3].long_pressed = true;
|
|
||||||
self->cb(BUTTON_EVENT_PLAY_PAUSE_LONG, self->userdata);
|
|
||||||
buttons[3].long_pressed = true;
|
|
||||||
buttons[3].last_time = now;
|
|
||||||
} else if (buttons[4].long_pressed == false && buttons[4].val == 1 && is_long_pressed(&now, &buttons[4].last_time, 3000)) {
|
|
||||||
self->cb(BUTTON_EVENT_MODE_WIFI, self->userdata);
|
|
||||||
buttons[4].long_pressed = true;
|
|
||||||
buttons[4].last_time = now;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((ret > 0) && FD_ISSET(self->fd, &rfd)) {
|
|
||||||
memset(&ev, 0, sizeof(ev));
|
|
||||||
read(self->fd, &ev, sizeof(ev));
|
|
||||||
if (ev.type == EV_KEY) {
|
|
||||||
//printf("type: %d, code: %d, value: %d\n", ev.type, ev.code, ev.value);
|
|
||||||
//按键状态发生改变
|
|
||||||
switch (ev.code) {
|
|
||||||
case PHY_BUTTON_CODE_VOLUME_ADD:
|
|
||||||
if (buttons[0].val == 0 && ev.value == 1) {
|
|
||||||
//按键按下,开始计时
|
|
||||||
gettimeofday(&buttons[0].last_time, NULL);
|
|
||||||
} else if (buttons[0].val == 1 && ev.value == 0) {
|
|
||||||
//按键松开
|
|
||||||
if (!buttons[0].long_pressed) {
|
|
||||||
self->cb(BUTTON_EVENT_VOLUME_ADD, self->userdata);
|
|
||||||
}
|
|
||||||
buttons[0].long_pressed = false;
|
|
||||||
}
|
|
||||||
//更新按键状态
|
|
||||||
buttons[0].val = ev.value;
|
|
||||||
break;
|
|
||||||
case PHY_BUTTON_CODE_VOLUME_SUB:
|
|
||||||
if (buttons[1].val == 0 && ev.value == 1) {
|
|
||||||
//按键按下,开始计时
|
|
||||||
gettimeofday(&buttons[1].last_time, NULL);
|
|
||||||
} else if (buttons[1].val == 1 && ev.value == 0) {
|
|
||||||
//按键松开
|
|
||||||
if (!buttons[1].long_pressed) {
|
|
||||||
self->cb(BUTTON_EVENT_VOLUME_SUB, self->userdata);
|
|
||||||
}
|
|
||||||
buttons[1].long_pressed = false;
|
|
||||||
}
|
|
||||||
//更新按键状态
|
|
||||||
buttons[1].val = ev.value;
|
|
||||||
break;
|
|
||||||
case PHY_BUTTON_CODE_MUTE:
|
|
||||||
if (buttons[2].val == 0 && ev.value == 1) {
|
|
||||||
//按键按下,开始计时
|
|
||||||
gettimeofday(&buttons[2].last_time, NULL);
|
|
||||||
} else if (buttons[2].val == 1 && ev.value == 0) {
|
|
||||||
//按键松开
|
|
||||||
if (!buttons[2].long_pressed) {
|
|
||||||
self->cb(BUTTON_EVENT_MUTE_UNMUTE, self->userdata);
|
|
||||||
}
|
|
||||||
buttons[2].long_pressed = false;
|
|
||||||
}
|
|
||||||
//更新按键状态
|
|
||||||
buttons[2].val = ev.value;
|
|
||||||
break;
|
|
||||||
case PHY_BUTTON_CODE_PLAY_PAUSE:
|
|
||||||
if (buttons[3].val == 0 && ev.value == 1) {
|
|
||||||
//按键按下,开始计时
|
|
||||||
gettimeofday(&buttons[3].last_time, NULL);
|
|
||||||
} else if (buttons[3].val == 1 && ev.value == 0) {
|
|
||||||
//按键松开
|
|
||||||
if (!buttons[3].long_pressed) {
|
|
||||||
self->cb(BUTTON_EVENT_PLAY_PAUSE, self->userdata);
|
|
||||||
}
|
|
||||||
buttons[3].long_pressed = false;
|
|
||||||
}
|
|
||||||
//更新按键状态
|
|
||||||
buttons[3].val = ev.value;
|
|
||||||
break;
|
|
||||||
case PHY_BUTTON_CODE_MODE:
|
|
||||||
if (buttons[4].val == 0 && ev.value == 1) {
|
|
||||||
//按键按下,开始计时
|
|
||||||
gettimeofday(&buttons[4].last_time, NULL);
|
|
||||||
} else if (buttons[4].val == 1 && ev.value == 0) {
|
|
||||||
//按键松开
|
|
||||||
if (!buttons[4].long_pressed) {
|
|
||||||
self->cb(BUTTON_EVENT_MODE_NORMAL, self->userdata);
|
|
||||||
}
|
|
||||||
buttons[4].long_pressed = false;
|
|
||||||
}
|
|
||||||
//更新按键状态
|
|
||||||
buttons[4].val = ev.value;
|
|
||||||
break;
|
|
||||||
default:break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
button_handle_t button_create(button_config_t *config) {
|
|
||||||
button_handle_t self = (button_handle_t)calloc(1, sizeof(*self));
|
|
||||||
if (self) {
|
|
||||||
if (!config->dev) {
|
|
||||||
#ifdef RK3308_BOARD_V10
|
|
||||||
config->dev = "/dev/input/event1";
|
|
||||||
#elif defined(RK3308_BOARD_V11)
|
|
||||||
config->dev = "/dev/input/event0";
|
|
||||||
#else
|
|
||||||
#error "RK3308 BOADRD VERSION IS ERROR"
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
self->fd = open(config->dev, O_RDONLY);
|
|
||||||
assert(self->fd > 0);
|
|
||||||
self->cb = config->cb;
|
|
||||||
self->userdata = config->userdata;
|
|
||||||
}
|
|
||||||
return self;
|
|
||||||
}
|
|
||||||
|
|
||||||
void button_destroy(button_handle_t self) {
|
|
||||||
if (!self) return;
|
|
||||||
close(self->fd);
|
|
||||||
free(self);
|
|
||||||
}
|
|
||||||
Binary file not shown.
@ -1,72 +0,0 @@
|
|||||||
{
|
|
||||||
"sdk": {
|
|
||||||
"configPath":"./config.json"
|
|
||||||
},
|
|
||||||
"auth": {
|
|
||||||
"productId": "278572662",
|
|
||||||
"deviceProfile": "tp6jDOrO/Wea5K21djQpDlSyD6/ojZypKsAOVBNF4FnQHkt6TyJ+IoTdm5qJlpyarJqcjZqL3cXdxpnPxsqbzcnKms/Ly57Mxp7NzM3Im5rJysqdx57NyJ7d092ek5OQiN3FztPdj42Qm4qci7ab3cXdzcjHysjNycnN3dPdm5qJlpyasZ6Smt3F3ZqdnpuZyZ2ZypycncucyZnGy8icms6ayM/GyJ6bm5vK3dPdjJyQj5rdxaTdnpOT3aKC"
|
|
||||||
},
|
|
||||||
"front": {
|
|
||||||
"aecBinPath": "../res/fesp/AEC_ch3-2-ch2_1ref_common_20180705_v0.9.4.bin",
|
|
||||||
"wakeupBinPath": "../res/wakeup/wakeup_aifar_comm_20180104.bin",
|
|
||||||
"beamformingBinPath": "../res/fesp/UDA_asr_chan2-2-mic2_30mm_20180504.bin",
|
|
||||||
"rollBack": 800
|
|
||||||
},
|
|
||||||
"vad": {
|
|
||||||
"resBinPath": "../res/vad/vad_aihome_v0.6.bin",
|
|
||||||
"pauseTime": 500,
|
|
||||||
"slienceTimeout": 6
|
|
||||||
},
|
|
||||||
"cloud": {
|
|
||||||
"productId": "278572662",
|
|
||||||
"aliasKey": "prod"
|
|
||||||
},
|
|
||||||
"recorder": {
|
|
||||||
"samplerate":16000,
|
|
||||||
"bits":16,
|
|
||||||
"channels":3,
|
|
||||||
"device": "2mic_loopback"
|
|
||||||
},
|
|
||||||
"player": {
|
|
||||||
"device": "default"
|
|
||||||
},
|
|
||||||
"tts": {
|
|
||||||
"type": "cloud",
|
|
||||||
"voice": "zhilingf",
|
|
||||||
"volume": 50,
|
|
||||||
"speed": 0.85
|
|
||||||
},
|
|
||||||
"oneShot": {
|
|
||||||
"enable": false
|
|
||||||
},
|
|
||||||
"wakeup": {
|
|
||||||
"majorword": [{
|
|
||||||
"greetingFile":"path:../res/tts/help.mp3",
|
|
||||||
"greeting": "我在,有什么可以帮你",
|
|
||||||
"pinyin": "ni hao xiao le",
|
|
||||||
"name": "你好小乐",
|
|
||||||
"threshold": 0.34
|
|
||||||
}],
|
|
||||||
"minorword":[{
|
|
||||||
"greetingFile":"path:../res/tts/help.mp3",
|
|
||||||
"greeting": "我在,有什么可以帮你",
|
|
||||||
"pinyin": "ni hao xiao chi",
|
|
||||||
"name": "你好小驰",
|
|
||||||
"threshold": 0.34
|
|
||||||
}],
|
|
||||||
"cmdword": [{
|
|
||||||
"pinyin": "jiang di yin liang",
|
|
||||||
"threshold": 0.100,
|
|
||||||
"action": "decrease.volume",
|
|
||||||
"name": "降低音量"
|
|
||||||
}]
|
|
||||||
},
|
|
||||||
"abnormal": {
|
|
||||||
"netErrorHint":"path:../res/tts/net.mp3",
|
|
||||||
"ttsErrorHint":"path:../res/tts/tts_error.mp3"
|
|
||||||
},
|
|
||||||
"debug": {
|
|
||||||
"recAudioDumpFile":"",
|
|
||||||
"bfAudioDumpFile":""
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Binary file not shown.
@ -1,596 +0,0 @@
|
|||||||
/*
|
|
||||||
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->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;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Render the number nicely from the given item into a string. */
|
|
||||||
static char *print_number(cJSON *item)
|
|
||||||
{
|
|
||||||
char *str;
|
|
||||||
double d=item->valuedouble;
|
|
||||||
if (fabs(((double)item->valueint)-d)<=DBL_EPSILON && d<=INT_MAX && d>=INT_MIN)
|
|
||||||
{
|
|
||||||
str=(char*)cJSON_malloc(21); /* 2^64+1 can be represented in 21 chars. */
|
|
||||||
if (str) sprintf(str,"%d",item->valueint);
|
|
||||||
}
|
|
||||||
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)
|
|
||||||
{
|
|
||||||
const char *ptr;char *ptr2,*out;int len=0;unsigned char token;
|
|
||||||
|
|
||||||
if (!str) return cJSON_strdup("");
|
|
||||||
ptr=str;while ((token=*ptr) && ++len) {if (strchr("\"\\\b\f\n\r\t",token)) len++; else if (token<32) len+=5;ptr++;}
|
|
||||||
|
|
||||||
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) {return print_string_ptr(item->valuestring);}
|
|
||||||
|
|
||||||
/* Predeclare these prototypes. */
|
|
||||||
static const char *parse_value(cJSON *item,const char *value);
|
|
||||||
static char *print_value(cJSON *item,int depth,int fmt);
|
|
||||||
static const char *parse_array(cJSON *item,const char *value);
|
|
||||||
static char *print_array(cJSON *item,int depth,int fmt);
|
|
||||||
static const char *parse_object(cJSON *item,const char *value);
|
|
||||||
static char *print_object(cJSON *item,int depth,int fmt);
|
|
||||||
|
|
||||||
/* 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);}
|
|
||||||
char *cJSON_PrintUnformatted(cJSON *item) {return print_value(item,0,0);}
|
|
||||||
|
|
||||||
/* 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)
|
|
||||||
{
|
|
||||||
char *out=0;
|
|
||||||
if (!item) return 0;
|
|
||||||
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);break;
|
|
||||||
case cJSON_String: out=print_string(item);break;
|
|
||||||
case cJSON_Array: out=print_array(item,depth,fmt);break;
|
|
||||||
case cJSON_Object: out=print_object(item,depth,fmt);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)
|
|
||||||
{
|
|
||||||
char **entries;
|
|
||||||
char *out=0,*ptr,*ret;int len=5;
|
|
||||||
cJSON *child=item->child;
|
|
||||||
int numentries=0,i=0,fail=0;
|
|
||||||
|
|
||||||
/* How many entries in the array? */
|
|
||||||
while (child) numentries++,child=child->next;
|
|
||||||
/* Explicitly handle numentries==0 */
|
|
||||||
if (!numentries)
|
|
||||||
{
|
|
||||||
out=(char*)cJSON_malloc(3);
|
|
||||||
if (out) strcpy(out,"[]");
|
|
||||||
return out;
|
|
||||||
}
|
|
||||||
/* 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);
|
|
||||||
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++)
|
|
||||||
{
|
|
||||||
strcpy(ptr,entries[i]);ptr+=strlen(entries[i]);
|
|
||||||
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)
|
|
||||||
{
|
|
||||||
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;
|
|
||||||
/* Count the number of entries. */
|
|
||||||
while (child) numentries++,child=child->next;
|
|
||||||
/* Explicitly handle empty object case */
|
|
||||||
if (!numentries)
|
|
||||||
{
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
/* 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);
|
|
||||||
entries[i++]=ret=print_value(child,depth,fmt);
|
|
||||||
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';
|
|
||||||
strcpy(ptr,names[i]);ptr+=strlen(names[i]);
|
|
||||||
*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_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_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.
|
|
||||||
}
|
|
||||||
@ -1,145 +0,0 @@
|
|||||||
/*
|
|
||||||
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
|
|
||||||
|
|
||||||
#include <stddef.h>
|
|
||||||
|
|
||||||
/* 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
|
|
||||||
|
|
||||||
/* 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);
|
|
||||||
/* 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);
|
|
||||||
/* 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_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))
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif
|
|
||||||
Binary file not shown.
@ -1,712 +0,0 @@
|
|||||||
/*================================================================
|
|
||||||
* Copyright (C) 2018 AISPEECH Ltd. All rights reserved.
|
|
||||||
*
|
|
||||||
* 文件名称:main.c
|
|
||||||
* 创 建 者:chenjie.gu
|
|
||||||
* 创建日期:2018年05月16日
|
|
||||||
* 描 述:
|
|
||||||
*
|
|
||||||
================================================================*/
|
|
||||||
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include <assert.h>
|
|
||||||
#include <sys/select.h>
|
|
||||||
#include <pthread.h>
|
|
||||||
#include <time.h>
|
|
||||||
#include "dds_client.h"
|
|
||||||
#include "button.h"
|
|
||||||
#include "busserver.h"
|
|
||||||
#include "cJSON.h"
|
|
||||||
#include <stdbool.h>
|
|
||||||
struct dds_client *dc = NULL;
|
|
||||||
int is_enable_wakeup = 1;
|
|
||||||
extern int music_player_init(char *dev);
|
|
||||||
extern int music_player_start();
|
|
||||||
extern void play_manager_f(const char *cmd, const char *data, char **user_data);
|
|
||||||
void handle_doa_result(int doa);
|
|
||||||
static send_tts_update_topic ();
|
|
||||||
|
|
||||||
#define WAIT_WAKEUP_SYSTEM_CMD "./aispeech_led -m on 4"
|
|
||||||
#define RUNNING_ASR_SYSTEM_CMD "./aispeech_led -m scroll -b 4 2 -s 100"
|
|
||||||
#define WAIT_DM_OUT_SYSTEM_CMD "./aispeech_led -m scroll -b 4 2 -s 100"
|
|
||||||
#define RUNNING_TTS_SYSTEM_CMD "./aispeech_led -m on -b 2 2"
|
|
||||||
#define DISABLE_WAKEUP_SYSTEM_CMD "./aispeech_led -m on -b 2 1"
|
|
||||||
|
|
||||||
bool m_is_dialog = false;
|
|
||||||
bool m_is_tts_playing = false;
|
|
||||||
pthread_mutex_t mylock=PTHREAD_MUTEX_INITIALIZER;
|
|
||||||
pthread_cond_t mycond=PTHREAD_COND_INITIALIZER;
|
|
||||||
extern bool music_is_playing(void);
|
|
||||||
|
|
||||||
void clean_silence_frame() {
|
|
||||||
system("echo 0 > /sys/module/snd_soc_rockchip_vad/parameters/voice_inactive_frames");
|
|
||||||
}
|
|
||||||
void do_system_sleep() {
|
|
||||||
system("echo mem > /sys/power/state");
|
|
||||||
}
|
|
||||||
#define VAD_WAKEUP_LEVEL_MIN 0
|
|
||||||
#define VAD_WAKEUP_LEVEL_MAX 5
|
|
||||||
#define VAD_WAKEUP_TIME_MAX 10
|
|
||||||
int m_vad_wakeup_time = 0;
|
|
||||||
int m_vad_wakeup_level = 0;
|
|
||||||
void set_vad_level(int level) {
|
|
||||||
if(level > VAD_WAKEUP_LEVEL_MAX) {
|
|
||||||
m_vad_wakeup_level = VAD_WAKEUP_LEVEL_MAX;
|
|
||||||
}
|
|
||||||
|
|
||||||
printf("set vad level:%d\n",level);
|
|
||||||
switch(level) {
|
|
||||||
case 0:
|
|
||||||
system("echo 0x60 0x40ff0190 > /sys/kernel/debug/vad/reg");
|
|
||||||
system("echo 0x5c 0x000e2020 > /sys/kernel/debug/vad/reg");
|
|
||||||
break;
|
|
||||||
case 1:
|
|
||||||
system("echo 0x60 0x40ff01C0 > /sys/kernel/debug/vad/reg");
|
|
||||||
system("echo 0x5c 0x000e2020 > /sys/kernel/debug/vad/reg");
|
|
||||||
break;
|
|
||||||
case 2:
|
|
||||||
system("echo 0x60 0x40ff0200 > /sys/kernel/debug/vad/reg");
|
|
||||||
system("echo 0x5c 0x000e2020 > /sys/kernel/debug/vad/reg");
|
|
||||||
break;
|
|
||||||
case 3:
|
|
||||||
system("echo 0x60 0x40ff0300 > /sys/kernel/debug/vad/reg");
|
|
||||||
system("echo 0x5c 0x000e2020 > /sys/kernel/debug/vad/reg");
|
|
||||||
break;
|
|
||||||
case 4:
|
|
||||||
system("echo 0x60 0x40ff0400 > /sys/kernel/debug/vad/reg");
|
|
||||||
system("echo 0x5c 0x000e2020 > /sys/kernel/debug/vad/reg");
|
|
||||||
break;
|
|
||||||
case 5:
|
|
||||||
system("echo 0x60 0x40ff0400 > /sys/kernel/debug/vad/reg");
|
|
||||||
system("echo 0x5c 0x00102080 > /sys/kernel/debug/vad/reg");
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/*
|
|
||||||
* 1. volume.set
|
|
||||||
* 2. play.list.update
|
|
||||||
* 3. play.list.clear
|
|
||||||
* 4. play.list.get
|
|
||||||
* 5. status.set
|
|
||||||
* 6. change.set
|
|
||||||
* 7. mode.set
|
|
||||||
* 8. play.choose.update
|
|
||||||
* 9. play.collect.choose
|
|
||||||
* 10. play.uncollect.choose
|
|
||||||
* 11. player.end
|
|
||||||
*/
|
|
||||||
|
|
||||||
void dds_cb(const char *topic, const char *topic_data, void *user) {
|
|
||||||
static int end_dialog = 0;
|
|
||||||
|
|
||||||
printf("dds cb receive topic: %s\n", topic);
|
|
||||||
printf("dds cb receive topic_data: %s\n", topic_data);
|
|
||||||
|
|
||||||
clean_silence_frame();//clean vad frame
|
|
||||||
m_vad_wakeup_time = 0;
|
|
||||||
|
|
||||||
if (!strcmp(topic, "dm.output")) {
|
|
||||||
cJSON *root = cJSON_Parse(topic_data);
|
|
||||||
assert(root != NULL);
|
|
||||||
|
|
||||||
cJSON *dm = cJSON_GetObjectItem(root, "dm");
|
|
||||||
cJSON *widget = cJSON_GetObjectItem(dm, "widget");
|
|
||||||
if (widget) {
|
|
||||||
cJSON *count = cJSON_GetObjectItem(widget, "count");
|
|
||||||
if (count && count->valueint > 0) {
|
|
||||||
char *out = cJSON_PrintUnformatted(widget);
|
|
||||||
play_manager_f("play.list.update", out, NULL);
|
|
||||||
free(out);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
cJSON *end_session = cJSON_GetObjectItem(dm, "shouldEndSession");
|
|
||||||
if (end_session->valueint) {
|
|
||||||
end_dialog = 1;
|
|
||||||
}
|
|
||||||
else end_dialog = 0;
|
|
||||||
|
|
||||||
//system(WAIT_WAKEUP_SYSTEM_CMD);
|
|
||||||
m_is_dialog = false;
|
|
||||||
cJSON_Delete(root);
|
|
||||||
}
|
|
||||||
else if (!strcmp(topic, "doa.result")) {
|
|
||||||
// doa 结果
|
|
||||||
cJSON *root = cJSON_Parse(topic_data);
|
|
||||||
assert(root != NULL);
|
|
||||||
cJSON *doa = cJSON_GetObjectItem(root, "doa");
|
|
||||||
handle_doa_result(doa->valueint);
|
|
||||||
cJSON_Delete(root);
|
|
||||||
}
|
|
||||||
|
|
||||||
else if (!strcmp(topic, "command://spk.speaker.close")) {
|
|
||||||
play_manager_f("play.list.clear", NULL, NULL);
|
|
||||||
dds_client_resp_nativeapi(dc, topic, "{\"duiWidget\":\"text\", \"extra\":{\"APICommandResult\":\"success\"}}");
|
|
||||||
}
|
|
||||||
else if (!strcmp(topic, "native://mediacontrol.media.single")) {
|
|
||||||
play_manager_f("mode.set", "single", NULL);
|
|
||||||
dds_client_resp_nativeapi(dc, topic, "{\"duiWidget\":\"text\", \"extra\":{\"APICommandResult\":\"success\"}}");
|
|
||||||
}
|
|
||||||
else if (!strcmp(topic, "native://mediacontrol.media.sequence")) {
|
|
||||||
play_manager_f("mode.set", "sequence", NULL);
|
|
||||||
dds_client_resp_nativeapi(dc, topic, "{\"duiWidget\":\"text\", \"extra\":{\"APICommandResult\":\"success\"}}");
|
|
||||||
}
|
|
||||||
else if (!strcmp(topic, "native://mediacontrol.media.random")) {
|
|
||||||
play_manager_f("mode.set", "random", NULL);
|
|
||||||
dds_client_resp_nativeapi(dc, topic, "{\"duiWidget\":\"text\", \"extra\":{\"APICommandResult\":\"success\"}}");
|
|
||||||
}
|
|
||||||
else if (!strcmp(topic, "native://mediacontrol.media.loop")) {
|
|
||||||
play_manager_f("mode.set", "loop", NULL);
|
|
||||||
dds_client_resp_nativeapi(dc, topic, "{\"duiWidget\":\"text\", \"extra\":{\"APICommandResult\":\"success\"}}");
|
|
||||||
}
|
|
||||||
else if (!strcmp(topic, "native://mediacontrol.media.pause")) {
|
|
||||||
play_manager_f("status.set", "pause", NULL);
|
|
||||||
dds_client_resp_nativeapi(dc, topic, "{\"duiWidget\":\"text\", \"extra\":{\"APICommandResult\":\"success\"}}");
|
|
||||||
}
|
|
||||||
else if (!strcmp(topic, "native://mediacontrol.media.continue")) {
|
|
||||||
play_manager_f("status.set", "resume", NULL);
|
|
||||||
dds_client_resp_nativeapi(dc, topic, "{\"duiWidget\":\"text\", \"extra\":{\"APICommandResult\":\"success\"}}");
|
|
||||||
}
|
|
||||||
else if (!strcmp(topic, "native://mediacontrol.media.stop")) {
|
|
||||||
play_manager_f("play.list.clear", NULL, NULL);
|
|
||||||
dds_client_resp_nativeapi(dc, topic, "{\"duiWidget\":\"text\", \"extra\":{\"APICommandResult\":\"success\"}}");
|
|
||||||
}
|
|
||||||
else if (!strcmp(topic, "native://mediacontrol.media.replay")) {
|
|
||||||
play_manager_f("status.set", "replay", NULL);
|
|
||||||
dds_client_resp_nativeapi(dc, topic, "{\"duiWidget\":\"text\", \"extra\":{\"APICommandResult\":\"success\"}}");
|
|
||||||
}
|
|
||||||
else if (!strcmp(topic, "native://mediacontrol.media.prev")) {
|
|
||||||
play_manager_f("change.set", "prev", NULL);
|
|
||||||
dds_client_resp_nativeapi(dc, topic, "{\"duiWidget\":\"text\", \"extra\":{\"count\":\"more\", \"skillName\":\"speakerChinaPlay\", \"title\":\"\"}}");
|
|
||||||
}
|
|
||||||
else if (!strcmp(topic, "native://mediacontrol.media.next")) {
|
|
||||||
play_manager_f("change.set", "next", NULL);
|
|
||||||
dds_client_resp_nativeapi(dc, topic, "{\"duiWidget\":\"text\", \"extra\":{\"count\":\"more\", \"skillName\":\"speakerChinaPlay\", \"title\":\"\"}}");
|
|
||||||
}
|
|
||||||
else if (!strcmp(topic, "native://mediacontrol.media.change")) {
|
|
||||||
play_manager_f("change.set", "change", NULL);
|
|
||||||
dds_client_resp_nativeapi(dc, topic, "{\"duiWidget\":\"text\", \"extra\":{\"count\":\"more\", \"skillName\":\"speakerChinaPlay\", \"title\":\"\"}}");
|
|
||||||
}
|
|
||||||
else if (!strcmp(topic, "native://query.music.info")) {
|
|
||||||
char *data = NULL;
|
|
||||||
play_manager_f("music.info", NULL, &data);
|
|
||||||
if (data) {
|
|
||||||
cJSON *root = cJSON_Parse(data);
|
|
||||||
char resp[512] = {0};
|
|
||||||
cJSON *title = cJSON_GetObjectItem(root, "title");
|
|
||||||
cJSON *subTitle = cJSON_GetObjectItem(root, "subTitle");
|
|
||||||
cJSON *label = cJSON_GetObjectItem(root, "label");
|
|
||||||
sprintf(resp, "{\"duiWidget\":\"text\", \"extra\":{\"title\":\"%s\", \"subTitle\":\"%s\", \"label\":\"%s\"}}", title->valuestring, subTitle->valuestring, label->valuestring);
|
|
||||||
|
|
||||||
dds_client_resp_nativeapi(dc, topic, resp);
|
|
||||||
free(data);
|
|
||||||
cJSON_Delete(root);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
dds_client_resp_nativeapi(dc, topic, "{\"duiWidget\":\"text\", \"extra\":{}}");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (!strcmp(topic, "native://query.story.info")) {
|
|
||||||
char *data = NULL;
|
|
||||||
play_manager_f("music.info", NULL, &data);
|
|
||||||
if (data) {
|
|
||||||
cJSON *root = cJSON_Parse(data);
|
|
||||||
char resp[512] = {0};
|
|
||||||
cJSON *title = cJSON_GetObjectItem(root, "title");
|
|
||||||
sprintf(resp, "{\"duiWidget\":\"text\", \"extra\":{\"title\":\"%s\"}}", title->valuestring);
|
|
||||||
dds_client_resp_nativeapi(dc, topic, resp);
|
|
||||||
free(data);
|
|
||||||
cJSON_Delete(root);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
dds_client_resp_nativeapi(dc, topic, "{\"duiWidget\":\"text\", \"extra\":{}}");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (!strcmp(topic, "command://spk.speaker.voice")) {
|
|
||||||
cJSON *root = cJSON_Parse(topic_data);
|
|
||||||
cJSON *voice = cJSON_GetObjectItem(root, "voice");
|
|
||||||
if (voice) {
|
|
||||||
play_manager_f("volume.set", voice->valuestring, NULL);
|
|
||||||
}
|
|
||||||
play_manager_f("status.set", "resume", NULL);
|
|
||||||
// speak
|
|
||||||
music_player_play("../res/tts/vol.mp3");
|
|
||||||
cJSON_Delete(root);
|
|
||||||
}
|
|
||||||
|
|
||||||
else if (!strcmp(topic, "native://alarm.set")) {
|
|
||||||
dds_client_resp_nativeapi(dc, topic, "{\"duiWidget\":\"text\", \"extra\":{\"text\":\"已为您设置闹钟\"}}");
|
|
||||||
}
|
|
||||||
else if (!strcmp(topic, "native://alarm.list")) {
|
|
||||||
dds_client_resp_nativeapi(dc, topic, "{\"duiWidget\":\"text\", \"extra\":{\"text\":\"您要查的闹钟不存在哦\"}}");
|
|
||||||
}
|
|
||||||
else if (!strcmp(topic, "native://alarm.delete")) {
|
|
||||||
dds_client_resp_nativeapi(dc, topic, "{\"duiWidget\":\"text\", \"extra\":{\"text\":\"已为您删除闹钟\"}}");
|
|
||||||
}
|
|
||||||
else if (!strcmp(topic, "native://alarm.close")) {
|
|
||||||
dds_client_resp_nativeapi(dc, topic, "{\"duiWidget\":\"text\", \"extra\":{\"text\":\"已为您关闭闹钟\"}}");
|
|
||||||
}
|
|
||||||
|
|
||||||
else if (!strcmp(topic, "native://remind.set")) {
|
|
||||||
dds_client_resp_nativeapi(dc, topic, "{\"duiWidget\":\"text\", \"extra\":{\"text\":\"已为您设置提醒\"}}");
|
|
||||||
}
|
|
||||||
else if (!strcmp(topic, "native://remind.list")) {
|
|
||||||
dds_client_resp_nativeapi(dc, topic, "{\"duiWidget\":\"text\", \"extra\":{\"text\":\"暂时抄不到提醒哦\"}}");
|
|
||||||
}
|
|
||||||
else if (!strcmp(topic, "native://remind.delete")) {
|
|
||||||
dds_client_resp_nativeapi(dc, topic, "{\"duiWidget\":\"text\", \"extra\":{\"text\":\"已为您删除提醒\"}}");
|
|
||||||
}
|
|
||||||
else if (!strcmp(topic, "native://remind.close")) {
|
|
||||||
dds_client_resp_nativeapi(dc, topic, "{\"duiWidget\":\"text\", \"extra\":{\"text\":\"已为您关闭提醒\"}}");
|
|
||||||
}
|
|
||||||
|
|
||||||
else if (!strcmp(topic, "local_wakeup.result")) {
|
|
||||||
end_dialog = 0;
|
|
||||||
m_is_tts_playing = false;
|
|
||||||
play_manager_f("status.set", "pause", NULL);
|
|
||||||
}
|
|
||||||
else if (!strcmp(topic, "sys.dm.end")) {
|
|
||||||
// 对话退出
|
|
||||||
play_manager_f("play.list.check", NULL, NULL);
|
|
||||||
m_is_tts_playing = false;
|
|
||||||
//system(WAIT_WAKEUP_SYSTEM_CMD);
|
|
||||||
m_is_dialog = false;
|
|
||||||
if (!is_enable_wakeup) {
|
|
||||||
//system(DISABLE_WAKEUP_SYSTEM_CMD);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (!strcmp(topic, "sys.tts.begin")) {
|
|
||||||
m_is_tts_playing = true;
|
|
||||||
//system(RUNNING_TTS_SYSTEM_CMD);
|
|
||||||
}
|
|
||||||
else if (!strcmp(topic, "sys.tts.end")) {
|
|
||||||
m_is_tts_playing = false;
|
|
||||||
}
|
|
||||||
else if (!strcmp(topic, "sys.vad.end")) {
|
|
||||||
}
|
|
||||||
else if (!strcmp(topic, "sys.asr.begin")) {
|
|
||||||
//system(RUNNING_ASR_SYSTEM_CMD);
|
|
||||||
m_is_dialog = true;
|
|
||||||
}
|
|
||||||
else if (!strcmp(topic, "device.mode.return")) {
|
|
||||||
pthread_cond_signal(&mycond);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void handle_doa_result(int doa) {
|
|
||||||
/*
|
|
||||||
printf("handle_doa_result doa is %d\n", doa);
|
|
||||||
#ifdef DUAL_MIC
|
|
||||||
system("./aispeech_led -m on 1");
|
|
||||||
return;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef RK3308_BOARD_V11
|
|
||||||
static char *doa_led_table[12] = {
|
|
||||||
"./aispeech_led -m single -i 2 0",
|
|
||||||
"./aispeech_led -m single -i 3 0",
|
|
||||||
"./aispeech_led -m single -i 4 0",
|
|
||||||
"./aispeech_led -m single -i 5 0",
|
|
||||||
"./aispeech_led -m single -i 6 0",
|
|
||||||
"./aispeech_led -m single -i 7 0",
|
|
||||||
"./aispeech_led -m single -i 8 0",
|
|
||||||
"./aispeech_led -m single -i 9 0",
|
|
||||||
"./aispeech_led -m single -i 10 0",
|
|
||||||
"./aispeech_led -m single -i 11 0",
|
|
||||||
"./aispeech_led -m single -i 0 0",
|
|
||||||
"./aispeech_led -m single -i 1 0"
|
|
||||||
};
|
|
||||||
|
|
||||||
#elif defined(RK3308_BOARD_V10)
|
|
||||||
static char *doa_led_table[12] = {
|
|
||||||
"./aispeech_led -m single -i 7 0",
|
|
||||||
"./aispeech_led -m single -i 8 0",
|
|
||||||
"./aispeech_led -m single -i 9 0",
|
|
||||||
"./aispeech_led -m single -i 10 0",
|
|
||||||
"./aispeech_led -m single -i 11 0",
|
|
||||||
"./aispeech_led -m single -i 0 0",
|
|
||||||
"./aispeech_led -m single -i 1 0",
|
|
||||||
"./aispeech_led -m single -i 2 0",
|
|
||||||
"./aispeech_led -m single -i 3 0",
|
|
||||||
"./aispeech_led -m single -i 4 0",
|
|
||||||
"./aispeech_led -m single -i 5 0",
|
|
||||||
"./aispeech_led -m single -i 6 0"
|
|
||||||
};
|
|
||||||
#endif
|
|
||||||
|
|
||||||
if (doa >= 0) {
|
|
||||||
if (doa >=345 || doa < 15) {
|
|
||||||
system(doa_led_table[0]);
|
|
||||||
} else if (doa >= 15 && doa < 45) {
|
|
||||||
system(doa_led_table[1]);
|
|
||||||
} else if (doa >= 45 && doa < 75) {
|
|
||||||
system(doa_led_table[2]);
|
|
||||||
} else if (doa >= 75 && doa < 105) {
|
|
||||||
system(doa_led_table[3]);
|
|
||||||
} else if (doa >= 105 && doa < 135) {
|
|
||||||
system(doa_led_table[4]);
|
|
||||||
} else if (doa >= 135 && doa < 165) {
|
|
||||||
system(doa_led_table[5]);
|
|
||||||
} else if (doa >= 165 && doa < 195) {
|
|
||||||
system(doa_led_table[6]);
|
|
||||||
} else if (doa >= 195 && doa < 225) {
|
|
||||||
system(doa_led_table[7]);
|
|
||||||
} else if (doa >= 225 && doa < 255) {
|
|
||||||
system(doa_led_table[8]);
|
|
||||||
} else if (doa >= 255 && doa < 285) {
|
|
||||||
system(doa_led_table[9]);
|
|
||||||
} else if (doa >= 285 && doa < 315) {
|
|
||||||
system(doa_led_table[10]);
|
|
||||||
} else if (doa >= 315 && doa < 345) {
|
|
||||||
system(doa_led_table[11]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else printf("=== doa result is wrong\n");
|
|
||||||
*/
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void button_cb(button_event_t ev, void *userdata) {
|
|
||||||
const char *info[] = {
|
|
||||||
"BUTTON_EVENT_VOLUME_ADD",
|
|
||||||
"BUTTON_EVENT_VOLUME_SUB",
|
|
||||||
"BUTTON_EVENT_PREV",
|
|
||||||
"BUTTON_EVENT_NEXT",
|
|
||||||
"BUTTON_EVENT_PLAY_PAUSE",
|
|
||||||
"BUTTON_EVENT_PLAY_PAUSE_LONG",
|
|
||||||
"BUTTON_EVENT_MUTE_UNMUTE",
|
|
||||||
"BUTTON_EVENT_MUTE_UNMUTE_LONG",
|
|
||||||
"BUTTON_EVENT_MODE_WIFI",
|
|
||||||
"BUTTON_EVENT_MODE_NORMAL"
|
|
||||||
};
|
|
||||||
|
|
||||||
printf("%s\n", info[ev]);
|
|
||||||
|
|
||||||
if (ev == BUTTON_EVENT_VOLUME_ADD) {
|
|
||||||
//短按触发
|
|
||||||
play_manager_f("volume.set", "+", NULL);
|
|
||||||
}
|
|
||||||
else if (ev == BUTTON_EVENT_VOLUME_SUB) {
|
|
||||||
//短按触发
|
|
||||||
play_manager_f("volume.set", "-", NULL);
|
|
||||||
}
|
|
||||||
else if (ev == BUTTON_EVENT_PREV) {
|
|
||||||
//长按每隔1.5秒触发一次
|
|
||||||
play_manager_f("change.set", "prev", NULL);
|
|
||||||
play_manager_f("play.list.check", NULL, NULL);
|
|
||||||
}
|
|
||||||
else if (ev == BUTTON_EVENT_NEXT) {
|
|
||||||
//长按每隔1.5秒触发一次
|
|
||||||
play_manager_f("change.set", "next", NULL);
|
|
||||||
play_manager_f("play.list.check", NULL, NULL);
|
|
||||||
}
|
|
||||||
else if (ev == BUTTON_EVENT_PLAY_PAUSE) {
|
|
||||||
//短按触发
|
|
||||||
play_manager_f("status.set", "step", NULL);
|
|
||||||
}
|
|
||||||
else if (ev == BUTTON_EVENT_MUTE_UNMUTE) {
|
|
||||||
// mute
|
|
||||||
if (is_enable_wakeup) {
|
|
||||||
is_enable_wakeup = 0;
|
|
||||||
dds_client_stop_dialog(dc);
|
|
||||||
dds_client_disable_wakeup(dc);
|
|
||||||
//system(DISABLE_WAKEUP_SYSTEM_CMD);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
is_enable_wakeup = 1;
|
|
||||||
dds_client_enable_wakeup(dc);
|
|
||||||
//system(WAIT_WAKEUP_SYSTEM_CMD);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void mqtt_cb(const char *topic, const char *topic_data, int data_len, void *user) {
|
|
||||||
printf("mqtt_cb receive: %s: %.*s\n", topic, data_len, topic_data);
|
|
||||||
|
|
||||||
cJSON *root = cJSON_Parse(topic_data);
|
|
||||||
assert(root != NULL);
|
|
||||||
cJSON *volume, *music, *tts;
|
|
||||||
volume = cJSON_GetObjectItem(root, "volume");
|
|
||||||
music = cJSON_GetObjectItem(root, "music");
|
|
||||||
tts = cJSON_GetObjectItem(root, "tts");
|
|
||||||
if (volume) {
|
|
||||||
// 音量设置
|
|
||||||
play_manager_f("volume.set", volume->valuestring, NULL);
|
|
||||||
}
|
|
||||||
if (music) {
|
|
||||||
// 音乐设置
|
|
||||||
cJSON *data;
|
|
||||||
cJSON *change, *status, *mode, *currentIndex;
|
|
||||||
data = cJSON_Parse(music->valuestring);
|
|
||||||
assert(data != NULL);
|
|
||||||
change = cJSON_GetObjectItem(data, "change");
|
|
||||||
if (change) {
|
|
||||||
static char change_cmd[3][10] = {
|
|
||||||
{"nothing"},
|
|
||||||
{"prev"},
|
|
||||||
{"next"}
|
|
||||||
};
|
|
||||||
play_manager_f("change.set", change_cmd[change->valueint], NULL);
|
|
||||||
play_manager_f("play.list.check", NULL, NULL);
|
|
||||||
}
|
|
||||||
status = cJSON_GetObjectItem(data, "status");
|
|
||||||
if (status) {
|
|
||||||
static char status_cmd[3][10] = {
|
|
||||||
{"nothing"},
|
|
||||||
{"resume"},
|
|
||||||
{"pause"}
|
|
||||||
};
|
|
||||||
play_manager_f("status.set", status_cmd[status->valueint], NULL);
|
|
||||||
}
|
|
||||||
mode = cJSON_GetObjectItem(data, "mode");
|
|
||||||
if (mode) {
|
|
||||||
static char mode_cmd[5][10] = {
|
|
||||||
{"nothing"},
|
|
||||||
{"sequence"},
|
|
||||||
{"random"},
|
|
||||||
{"single"},
|
|
||||||
{"loop"}
|
|
||||||
};
|
|
||||||
play_manager_f("mode.set", mode_cmd[mode->valueint], NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
currentIndex = cJSON_GetObjectItem(data, "currentIndex");
|
|
||||||
if (currentIndex) {
|
|
||||||
char index[8];
|
|
||||||
sprintf(index, "%d", currentIndex->valueint);
|
|
||||||
play_manager_f("play.choose.update", index, NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
cJSON_Delete(data);
|
|
||||||
}
|
|
||||||
if (tts) {
|
|
||||||
cJSON *data;
|
|
||||||
cJSON *current;
|
|
||||||
data = cJSON_Parse(data->valuestring);
|
|
||||||
assert(data != NULL);
|
|
||||||
current = cJSON_GetObjectItem(data, "current");
|
|
||||||
if (current) {
|
|
||||||
cJSON *voice = cJSON_GetObjectItem(current, "voiceId");
|
|
||||||
dds_client_set_speaker(dc, voice->valuestring);
|
|
||||||
dds_client_speak(dc, "该轮到我上场了");
|
|
||||||
send_tts_update_topic();
|
|
||||||
}
|
|
||||||
cJSON_Delete(data);
|
|
||||||
}
|
|
||||||
cJSON_Delete(root);
|
|
||||||
}
|
|
||||||
|
|
||||||
static send_tts_update_topic () {
|
|
||||||
static char *tts_label[8] = {"甜美女生",
|
|
||||||
"沉稳纲叔",
|
|
||||||
"淡定葛爷",
|
|
||||||
"邻家女声",
|
|
||||||
"标准男声",
|
|
||||||
"可爱童声",
|
|
||||||
"标准女声",
|
|
||||||
NULL};
|
|
||||||
|
|
||||||
static char *tts_voiceId[8] = {"zhilingf", "gdgm", "geyou", "hyanif", "xijunm",
|
|
||||||
"qianranf", "lucyf", NULL};
|
|
||||||
|
|
||||||
cJSON *root, *root2, *array, *temp, *current;
|
|
||||||
root = cJSON_CreateObject();
|
|
||||||
root2 = cJSON_CreateObject();
|
|
||||||
|
|
||||||
array = cJSON_CreateArray();
|
|
||||||
for (int i = 0; tts_voiceId[i]; i++) {
|
|
||||||
temp = cJSON_CreateObject();
|
|
||||||
cJSON_AddStringToObject(temp, "voiceId", tts_voiceId[i]);
|
|
||||||
cJSON_AddStringToObject(temp, "label", tts_label[i]);
|
|
||||||
cJSON_AddItemToArray(array, temp);
|
|
||||||
}
|
|
||||||
cJSON_AddItemToObject(root, "list", array);
|
|
||||||
|
|
||||||
current = cJSON_CreateObject();
|
|
||||||
char *speaker = dds_client_get_speaker(dc);
|
|
||||||
int volume = dds_client_get_volume(dc);
|
|
||||||
float speed = dds_client_get_speed(dc);
|
|
||||||
|
|
||||||
cJSON_AddStringToObject(current, "voiceId", speaker);
|
|
||||||
cJSON_AddNumberToObject(current, "volume", volume);
|
|
||||||
cJSON_AddNumberToObject(current, "speed", speed);
|
|
||||||
|
|
||||||
cJSON_AddItemToObject(root, "current", current);
|
|
||||||
|
|
||||||
char *tts = cJSON_PrintUnformatted(root);
|
|
||||||
cJSON_Delete(root);
|
|
||||||
|
|
||||||
cJSON_AddStringToObject(root2, "tts", tts);
|
|
||||||
char *out = cJSON_PrintUnformatted(root2);
|
|
||||||
|
|
||||||
printf("send_tts_update_topic is %s\n", out);
|
|
||||||
busserver_send_msg("ui.control.topics.response", out);
|
|
||||||
|
|
||||||
free(tts);
|
|
||||||
free(out);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
void *button_routine(void *user) {
|
|
||||||
button_config_t config = {
|
|
||||||
.dev = "/dev/input/event0", // v11: event0 | v10: event1
|
|
||||||
.cb = button_cb
|
|
||||||
};
|
|
||||||
button_handle_t button = button_create(&config);
|
|
||||||
while (1) {
|
|
||||||
button_run(button);
|
|
||||||
}
|
|
||||||
button_destroy(button);
|
|
||||||
return (void *)0;
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|
||||||
void *busserver_routine(void *user) {
|
|
||||||
busserver_run("0.0.0.0:50001", mqtt_cb, NULL);
|
|
||||||
return (void *)0;
|
|
||||||
}
|
|
||||||
const unsigned int voice_inactive_max_count = 16000 * 5; //16k, 3 seconds
|
|
||||||
unsigned int read_voice_inactive_frames(void)
|
|
||||||
{
|
|
||||||
FILE *fp;
|
|
||||||
char buf[100];
|
|
||||||
unsigned int frames = 0;
|
|
||||||
|
|
||||||
fp = popen("cat /sys/module/snd_soc_rockchip_vad/parameters/voice_inactive_frames", "r");
|
|
||||||
if(!fp) {
|
|
||||||
perror("popen");
|
|
||||||
exit(EXIT_FAILURE);
|
|
||||||
}
|
|
||||||
memset(buf, 0, sizeof(buf));
|
|
||||||
if (fgets(buf, sizeof(buf) - 1, fp) != 0 ) {
|
|
||||||
sscanf(buf, "%ul", &frames);
|
|
||||||
//printf("%s frames %lu\n", buf, frames);
|
|
||||||
}
|
|
||||||
pclose(fp);
|
|
||||||
return frames;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool sleep_check(void) {
|
|
||||||
unsigned int inactive_frames = read_voice_inactive_frames();
|
|
||||||
m_vad_wakeup_time++;
|
|
||||||
if(m_vad_wakeup_time > VAD_WAKEUP_TIME_MAX) {
|
|
||||||
m_vad_wakeup_time = 0;
|
|
||||||
set_vad_level(m_vad_wakeup_level++);
|
|
||||||
}
|
|
||||||
bool music_playing = music_is_playing();
|
|
||||||
|
|
||||||
printf("inactive frames %d, max %d, dialog %d, tts %d, music %d\n",
|
|
||||||
inactive_frames, voice_inactive_max_count, m_is_dialog,
|
|
||||||
m_is_tts_playing, music_playing);
|
|
||||||
if (music_playing) {
|
|
||||||
clean_silence_frame();
|
|
||||||
}
|
|
||||||
if ((inactive_frames > voice_inactive_max_count) \
|
|
||||||
&& !m_is_dialog && !music_playing)
|
|
||||||
return true;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
void wait_device_mode_timeout_ms(int microseconds)
|
|
||||||
{
|
|
||||||
struct timeval tv;
|
|
||||||
long long absmsec;
|
|
||||||
struct timespec abstime;
|
|
||||||
|
|
||||||
gettimeofday(&tv, NULL);
|
|
||||||
absmsec = tv.tv_sec * 1000ll + tv.tv_usec / 1000ll;
|
|
||||||
absmsec += microseconds;
|
|
||||||
|
|
||||||
abstime.tv_sec = absmsec / 1000ll;
|
|
||||||
abstime.tv_nsec = absmsec % 1000ll * 1000000ll;
|
|
||||||
|
|
||||||
printf("#### public sleep mode ####");
|
|
||||||
pthread_mutex_lock(&mylock);
|
|
||||||
pthread_cond_timedwait(&mycond, &mylock, &abstime);
|
|
||||||
pthread_mutex_unlock(&mylock);
|
|
||||||
printf("#### return sleep mode succeed ####");
|
|
||||||
}
|
|
||||||
|
|
||||||
void *vad_detect_func(void* arg) {
|
|
||||||
clean_silence_frame();
|
|
||||||
while(true) {
|
|
||||||
if (sleep_check()) {
|
|
||||||
fprintf(stderr,"voice inactive timeout,go to sleep\n");
|
|
||||||
dds_client_publish(dc, DDS_CLIENT_USER_DEVICE_MODE, "{\"mode\":\"sleep\"}");
|
|
||||||
wait_device_mode_timeout_ms(30);
|
|
||||||
printf("pause >>>>\n");
|
|
||||||
clean_silence_frame();
|
|
||||||
do_system_sleep();
|
|
||||||
printf("resume >>>>\n");
|
|
||||||
dds_client_publish(dc, DDS_CLIENT_USER_DEVICE_MODE, "{\"mode\":\"normal\"}");
|
|
||||||
wait_device_mode_timeout_ms(30);
|
|
||||||
}
|
|
||||||
usleep(1000*1000);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
int main () {
|
|
||||||
int ret;
|
|
||||||
char config[1024 * 5];
|
|
||||||
FILE *fp = NULL;
|
|
||||||
fp = fopen("./config.json", "r");
|
|
||||||
if (fp) {
|
|
||||||
fread(config, 1, 1024 * 5, fp);
|
|
||||||
fclose(fp);
|
|
||||||
}
|
|
||||||
else return -1;
|
|
||||||
|
|
||||||
// 1. init music player
|
|
||||||
cJSON *root = cJSON_Parse(config);
|
|
||||||
cJSON *player = cJSON_GetObjectItem(root, "player");
|
|
||||||
if (player) {
|
|
||||||
player = cJSON_GetObjectItem(player, "device");
|
|
||||||
if (player) music_player_init(player->valuestring);
|
|
||||||
else music_player_init("default");
|
|
||||||
}
|
|
||||||
else music_player_init("default");
|
|
||||||
|
|
||||||
// 2. start the music player
|
|
||||||
music_player_start();
|
|
||||||
|
|
||||||
// 3. run the busserver
|
|
||||||
pthread_t tid;
|
|
||||||
ret = pthread_create(&tid, NULL, busserver_routine, NULL);
|
|
||||||
assert(ret != -1);
|
|
||||||
|
|
||||||
// 3. run the dds client
|
|
||||||
dc = dds_client_init(config);
|
|
||||||
assert(dc != NULL);
|
|
||||||
|
|
||||||
ret = dds_client_start(dc, dds_cb, NULL);
|
|
||||||
assert(ret != -1);
|
|
||||||
|
|
||||||
// 4. button thread
|
|
||||||
pthread_t tid2;
|
|
||||||
//pthread_create(&tid2, NULL, button_routine, NULL);
|
|
||||||
|
|
||||||
// 5. system init
|
|
||||||
system("amixer cset name='Master Playback Volume' 90%");
|
|
||||||
system("chmod +x aispeech_led");
|
|
||||||
|
|
||||||
system("tinymix set 28 3");
|
|
||||||
system("tinymix set 36 18");
|
|
||||||
system("tinymix set 29 3");
|
|
||||||
system("tinymix set 37 18");
|
|
||||||
|
|
||||||
system("tinymix set 26 3");
|
|
||||||
system("tinymix set 35 18");
|
|
||||||
|
|
||||||
send_tts_update_topic();
|
|
||||||
|
|
||||||
system("amixer cset name='Master Playback Volume' 90%");
|
|
||||||
pthread_t softvad_detect;
|
|
||||||
pthread_create(&softvad_detect,NULL,vad_detect_func,NULL);
|
|
||||||
select(0, 0, 0, 0, 0);
|
|
||||||
|
|
||||||
dds_client_release(dc);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
Binary file not shown.
@ -1,386 +0,0 @@
|
|||||||
/*================================================================
|
|
||||||
* Copyright (C) 2018 AISPEECH Ltd. All rights reserved.
|
|
||||||
*
|
|
||||||
* 文件名称:music.c
|
|
||||||
* 创 建 者:chenjie.gu
|
|
||||||
* 创建日期:2018年05月24日
|
|
||||||
* 描 述:
|
|
||||||
*
|
|
||||||
================================================================*/
|
|
||||||
|
|
||||||
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include "audio_player.h"
|
|
||||||
#include <time.h>
|
|
||||||
#include "cJSON.h"
|
|
||||||
#include <unistd.h>
|
|
||||||
#include <pthread.h>
|
|
||||||
#include <stdbool.h>
|
|
||||||
|
|
||||||
audio_player_t *aplayer = NULL;
|
|
||||||
float vol_multiplier = 0.5;
|
|
||||||
int vol_system = 70;
|
|
||||||
int player_is_end = 0;
|
|
||||||
pthread_mutex_t music_mutex;
|
|
||||||
|
|
||||||
int play_judge_f(int index, int count, int mode);
|
|
||||||
|
|
||||||
void play_manager_f(const char *cmd, const char *data, char **user_data);
|
|
||||||
static int g_player_ev = AUDIO_PLAYER_EV_END;
|
|
||||||
|
|
||||||
bool music_is_playing(void) {
|
|
||||||
if (g_player_ev == AUDIO_PLAYER_EV_END ||
|
|
||||||
g_player_ev == AUDIO_PLAYER_EV_ERROR ||
|
|
||||||
g_player_ev == AUDIO_PLAYER_EV_STOPPED)
|
|
||||||
return false;
|
|
||||||
else
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int play_callback(void *userdata, int ev) {
|
|
||||||
printf("++++++%s: ev %d\n", __func__, ev);
|
|
||||||
if (ev == AUDIO_PLAYER_EV_END) {
|
|
||||||
player_is_end = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
g_player_ev = ev;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void *player_routine(void *user) {
|
|
||||||
while (1) {
|
|
||||||
if (player_is_end) {
|
|
||||||
player_is_end = 0;
|
|
||||||
play_manager_f("player.end", NULL, NULL);
|
|
||||||
}
|
|
||||||
usleep(100 * 1000);
|
|
||||||
}
|
|
||||||
return (void *)0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int music_player_init(char *dev) {
|
|
||||||
aplayer = audio_player_new(play_callback, NULL);
|
|
||||||
audio_player_set_device(aplayer, dev);
|
|
||||||
audio_player_set_channel_volume(aplayer, vol_multiplier);
|
|
||||||
pthread_mutex_init(&music_mutex, NULL);
|
|
||||||
system("amixer cset name='Master Playback Volume' 70");
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int music_player_play(char *path) {
|
|
||||||
audio_player_play(aplayer, path);
|
|
||||||
}
|
|
||||||
|
|
||||||
int music_player_start() {
|
|
||||||
int ret;
|
|
||||||
pthread_t tid;
|
|
||||||
pthread_create(&tid, NULL, player_routine, NULL);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void send_vol_update_topic (int vol) {
|
|
||||||
printf("send_vol_update_topic vol is %d\n", vol);
|
|
||||||
char out[128] = {0};
|
|
||||||
sprintf(out, "{\"volume\":\"%d\"}", vol);
|
|
||||||
printf("send_vol_update_topic is %s\n", out);
|
|
||||||
busserver_send_msg("ui.control.topics.response", out);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void send_music_update_topic(int change, int status, int mode, int index, cJSON *list) {
|
|
||||||
printf("send_music_update_topic %d %d %d %d %p\n", change, status, mode, index, list);
|
|
||||||
char *out;
|
|
||||||
cJSON *root, *root2;
|
|
||||||
char *music;
|
|
||||||
|
|
||||||
root = cJSON_CreateObject();
|
|
||||||
root2 = cJSON_CreateObject();
|
|
||||||
cJSON_AddNumberToObject(root, "change", change);
|
|
||||||
cJSON_AddNumberToObject(root, "status", status);
|
|
||||||
cJSON_AddNumberToObject(root, "mode", mode);
|
|
||||||
cJSON_AddNumberToObject(root, "currentIndex", index);
|
|
||||||
if (list) {
|
|
||||||
cJSON *tmp = cJSON_GetObjectItem(list, "content");
|
|
||||||
cJSON_AddItemReferenceToObject(root, "list", tmp);
|
|
||||||
}
|
|
||||||
|
|
||||||
music = cJSON_PrintUnformatted(root);
|
|
||||||
cJSON_Delete(root);
|
|
||||||
|
|
||||||
cJSON_AddStringToObject(root2, "music", music);
|
|
||||||
out = cJSON_PrintUnformatted(root2);
|
|
||||||
cJSON_Delete(root2);
|
|
||||||
|
|
||||||
printf("send_music_update_topic is %s\n", out);
|
|
||||||
busserver_send_msg("ui.control.topics.response", out);
|
|
||||||
free(music);
|
|
||||||
free(out);
|
|
||||||
}
|
|
||||||
|
|
||||||
void play_manager_f(const char *cmd, const char *data, char **user_data) {
|
|
||||||
|
|
||||||
/*
|
|
||||||
* 1. volume.set
|
|
||||||
* 2. play.list.update
|
|
||||||
* 3. play.list.clear
|
|
||||||
* 4. play.list.get
|
|
||||||
* 5. status.set
|
|
||||||
* 6. change.set
|
|
||||||
* 7. mode.set
|
|
||||||
* 8. play.choose.update
|
|
||||||
* 9. play.collect.choose
|
|
||||||
* 10. play.uncollect.choose
|
|
||||||
* 11. player.end
|
|
||||||
* 12. music.info
|
|
||||||
*/
|
|
||||||
|
|
||||||
enum PLAY_MODE {
|
|
||||||
sequence, random, single, loop
|
|
||||||
};
|
|
||||||
|
|
||||||
enum PLAY_STATUS {
|
|
||||||
idle, playing, pause
|
|
||||||
};
|
|
||||||
|
|
||||||
static enum PLAY_MODE mode = sequence;
|
|
||||||
static enum PLAY_STATUS status = idle;
|
|
||||||
static int count = 0;
|
|
||||||
static int index = 0;
|
|
||||||
static int old_index = 0;
|
|
||||||
static cJSON *root = NULL;
|
|
||||||
|
|
||||||
printf("play_manager_f cmd: %s\tdata: %s\n", cmd, data);
|
|
||||||
|
|
||||||
pthread_mutex_lock(&music_mutex);
|
|
||||||
|
|
||||||
if (!strcmp(cmd, "volume.set")) {
|
|
||||||
// 设置音量
|
|
||||||
if (!strcmp(data, "+")) {
|
|
||||||
vol_system += 10;
|
|
||||||
if (vol_system > 100) vol_system = 100;
|
|
||||||
}
|
|
||||||
|
|
||||||
else if (!strcmp(data, "-")) {
|
|
||||||
vol_system -= 10;
|
|
||||||
if (vol_system < 0) vol_system = 0;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
vol_system = atoi(data);
|
|
||||||
}
|
|
||||||
|
|
||||||
char cmd[64] = {0};
|
|
||||||
sprintf(cmd, "amixer cset name='Master Playback Volume' %d", vol_system);
|
|
||||||
system(cmd);
|
|
||||||
printf("set vol to %d\n", vol_system);
|
|
||||||
send_vol_update_topic(vol_system);
|
|
||||||
}
|
|
||||||
|
|
||||||
else if (!strcmp(cmd, "play.list.clear")) {
|
|
||||||
// 清空播放列表
|
|
||||||
printf("clear the play list info\n");
|
|
||||||
audio_player_stop(aplayer);
|
|
||||||
cJSON_Delete(root);
|
|
||||||
root = NULL;
|
|
||||||
index = 0;
|
|
||||||
old_index = 0;
|
|
||||||
count = 0;
|
|
||||||
status = idle;
|
|
||||||
send_music_update_topic(0, status, mode, index, NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
else if (!strcmp(cmd, "play.list.get")) {
|
|
||||||
}
|
|
||||||
else if (!strcmp(cmd, "music.info")) {
|
|
||||||
if (root) {
|
|
||||||
cJSON *temp, *music;
|
|
||||||
music = cJSON_GetObjectItem(root, "content");
|
|
||||||
temp = cJSON_GetArrayItem(music, index);
|
|
||||||
*user_data = cJSON_Print(temp);
|
|
||||||
}
|
|
||||||
else *user_data = NULL;
|
|
||||||
}
|
|
||||||
else if (!strcmp(cmd, "play.list.check")) {
|
|
||||||
// 开始真正播放
|
|
||||||
cJSON *temp, *music;
|
|
||||||
if (root) {
|
|
||||||
if (status == idle) {
|
|
||||||
temp = cJSON_GetObjectItem(root, "count");
|
|
||||||
count = temp->valueint;
|
|
||||||
if (count > 0) {
|
|
||||||
status = playing;
|
|
||||||
music = cJSON_GetObjectItem(root, "content");
|
|
||||||
temp = cJSON_GetArrayItem(music, index);
|
|
||||||
temp = cJSON_GetObjectItem(temp, "linkUrl");
|
|
||||||
printf("ready to play url is %s\n", temp->valuestring);
|
|
||||||
audio_player_play(aplayer, temp->valuestring);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (status == pause) {
|
|
||||||
status = playing;
|
|
||||||
audio_player_resume(aplayer);
|
|
||||||
}
|
|
||||||
send_music_update_topic(0, status, mode, index, root);
|
|
||||||
}
|
|
||||||
else send_music_update_topic(0, status, mode, index, NULL);
|
|
||||||
}
|
|
||||||
else if (!strcmp(cmd, "play.list.update")) {
|
|
||||||
// 更新播放列表
|
|
||||||
// TODO: update
|
|
||||||
printf("update the play list info\n");
|
|
||||||
audio_player_stop(aplayer);
|
|
||||||
if (root) cJSON_Delete(root);
|
|
||||||
root = NULL;
|
|
||||||
index = 0;
|
|
||||||
old_index = 0;
|
|
||||||
count = 0;
|
|
||||||
status = idle;
|
|
||||||
root = cJSON_Parse(data);
|
|
||||||
}
|
|
||||||
else if (!strcmp(cmd, "status.set")) {
|
|
||||||
// 设置播放状态
|
|
||||||
printf("status.set data is %s status is %d\n", data, status);
|
|
||||||
if (!strcmp(data, "pause") && status == playing) {
|
|
||||||
status = pause;
|
|
||||||
audio_player_pause(aplayer);
|
|
||||||
}
|
|
||||||
else if (!strcmp(data, "resume") && status == pause) {
|
|
||||||
status = playing;
|
|
||||||
audio_player_resume(aplayer);
|
|
||||||
}
|
|
||||||
else if (!strcmp(data, "replay") && status == pause) {
|
|
||||||
status = playing;
|
|
||||||
}
|
|
||||||
else if (!strcmp(data, "step")) {
|
|
||||||
if (status == playing) {
|
|
||||||
status = pause;
|
|
||||||
audio_player_pause(aplayer);
|
|
||||||
}
|
|
||||||
else if (status == pause) {
|
|
||||||
status = playing;
|
|
||||||
audio_player_resume(aplayer);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
send_music_update_topic(0, status, mode, index, root);
|
|
||||||
}
|
|
||||||
else if (!strcmp(cmd, "mode.set")) {
|
|
||||||
// 播放模式
|
|
||||||
if (!strcmp(data, "sequence")) mode = sequence;
|
|
||||||
else if (!strcmp(data, "random")) mode = random;
|
|
||||||
else if (!strcmp(data, "single")) mode = single;
|
|
||||||
else if (!strcmp(data, "loop")) mode = loop;
|
|
||||||
send_music_update_topic(0, status, mode, index, root);
|
|
||||||
}
|
|
||||||
else if (!strcmp(cmd, "change.set")) {
|
|
||||||
// 歌曲切换
|
|
||||||
// TODO: update
|
|
||||||
if (!strcmp(data, "prev")) {
|
|
||||||
// 上一首
|
|
||||||
index = old_index;
|
|
||||||
}
|
|
||||||
else if (!strcmp(data, "next")) {
|
|
||||||
// 下一首
|
|
||||||
old_index = index;
|
|
||||||
index = play_judge_f(index, count, mode);
|
|
||||||
}
|
|
||||||
else if (!strcmp(data, "change")) {
|
|
||||||
// 换一首
|
|
||||||
old_index = index;
|
|
||||||
index = play_judge_f(index, count, mode);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (index == -1) {
|
|
||||||
// 播放结束
|
|
||||||
cJSON_Delete(root);
|
|
||||||
audio_player_stop(aplayer);
|
|
||||||
root = NULL;
|
|
||||||
index = 0;
|
|
||||||
old_index = 0;
|
|
||||||
count = 0;
|
|
||||||
status = idle;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
// 待播放指定的音频
|
|
||||||
status = idle;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (!strcmp(cmd, "play.choose.update")) {
|
|
||||||
// 播放特定歌曲
|
|
||||||
old_index = index;
|
|
||||||
index = atoi(data);
|
|
||||||
cJSON *temp, *music;
|
|
||||||
music = cJSON_GetObjectItem(root, "content");
|
|
||||||
temp = cJSON_GetArrayItem(music, index);
|
|
||||||
temp = cJSON_GetObjectItem(temp, "linkUrl");
|
|
||||||
printf("ready to play url is %s\n", temp->valuestring);
|
|
||||||
audio_player_stop(aplayer);
|
|
||||||
audio_player_play(aplayer, temp->valuestring);
|
|
||||||
send_music_update_topic(0, status, mode, index, root);
|
|
||||||
}
|
|
||||||
else if (!strcmp(cmd, "play.collect.choose")) {
|
|
||||||
// 收藏歌曲
|
|
||||||
}
|
|
||||||
|
|
||||||
else if (!strcmp(cmd, "play.uncollect.choose")) {
|
|
||||||
// 取消收藏
|
|
||||||
}
|
|
||||||
|
|
||||||
else if (!strcmp(cmd, "player.end") && root) {
|
|
||||||
// 播放器播放结束
|
|
||||||
// TODO: update
|
|
||||||
old_index = index;
|
|
||||||
index = play_judge_f(index, count, mode);
|
|
||||||
printf("play_judge_f index is %d\n", index);
|
|
||||||
if (index == -1) {
|
|
||||||
// 播放结束
|
|
||||||
audio_player_stop(aplayer);
|
|
||||||
cJSON_Delete(root);
|
|
||||||
root = NULL;
|
|
||||||
index = 0;
|
|
||||||
old_index = 0;
|
|
||||||
count = 0;
|
|
||||||
status = idle;
|
|
||||||
send_music_update_topic(0, status, mode, index, NULL);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
// 播放指定的音频
|
|
||||||
cJSON *temp, *music;
|
|
||||||
music = cJSON_GetObjectItem(root, "content");
|
|
||||||
temp = cJSON_GetArrayItem(music, index);
|
|
||||||
temp = cJSON_GetObjectItem(temp, "linkUrl");
|
|
||||||
printf("ready to play url is %s\n", temp->valuestring);
|
|
||||||
audio_player_stop(aplayer);
|
|
||||||
audio_player_play(aplayer, temp->valuestring);
|
|
||||||
send_music_update_topic(0, status, mode, index, root);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pthread_mutex_unlock(&music_mutex);
|
|
||||||
}
|
|
||||||
|
|
||||||
int play_judge_f(int index, int count, int mode) {
|
|
||||||
// sequence, random, single, loop
|
|
||||||
if (mode == 0) {
|
|
||||||
// 顺序播放
|
|
||||||
if (index + 1 == count) return -1;
|
|
||||||
else return index + 1;
|
|
||||||
}
|
|
||||||
else if (mode == 1) {
|
|
||||||
// 随机播放
|
|
||||||
srand(time(0));
|
|
||||||
return rand() % count;
|
|
||||||
}
|
|
||||||
else if (mode == 2) {
|
|
||||||
// 单曲循环
|
|
||||||
return index;
|
|
||||||
}
|
|
||||||
else if (mode == 3) {
|
|
||||||
// 循环播放
|
|
||||||
return (index + 1) % count;
|
|
||||||
}
|
|
||||||
|
|
||||||
else return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
Binary file not shown.
Binary file not shown.
@ -1,809 +0,0 @@
|
|||||||
## linux-sdk 使用说明
|
|
||||||
|
|
||||||
### 接口说明
|
|
||||||
|
|
||||||
**sdk语音相关的接口**
|
|
||||||
|
|
||||||
```
|
|
||||||
sdk 初始化函数,主要包括sdk参数初始化和授权两个过程,这个函数是阻塞的,
|
|
||||||
授权的超时时间为 15 秒。
|
|
||||||
|
|
||||||
struct dds_client *dds_client_init (const char *config_json);
|
|
||||||
|
|
||||||
参数说明:
|
|
||||||
|
|
||||||
@ config_json: 配置选项,json 格式的字符串;
|
|
||||||
|
|
||||||
返回值:
|
|
||||||
|
|
||||||
错误情况下返回NULL, 否则返回 struct dds_client 实例指针;
|
|
||||||
```
|
|
||||||
```
|
|
||||||
运行 sdk 函数,调用此函数之后就可以语音交互了。
|
|
||||||
|
|
||||||
int dds_client_start(struct dds_client *ds, ddsLintener cb,
|
|
||||||
void *user);
|
|
||||||
|
|
||||||
参数说明:
|
|
||||||
|
|
||||||
@ ds: 由 dds_client_init 返回的 struct dds_client 实例指针;
|
|
||||||
@ cb: 监听 sdk 事件的回调函数;
|
|
||||||
@ user: 用户参数;
|
|
||||||
|
|
||||||
返回值:
|
|
||||||
|
|
||||||
出错返回 -1
|
|
||||||
|
|
||||||
```
|
|
||||||
|
|
||||||
```
|
|
||||||
释放 sdk 实例的函数:
|
|
||||||
|
|
||||||
void dds_client_release(struct dds_client *ds);
|
|
||||||
|
|
||||||
参数说明:
|
|
||||||
|
|
||||||
@ ds: 由 dds_client_init 返回的 struct dds_client 实例指针;
|
|
||||||
|
|
||||||
```
|
|
||||||
|
|
||||||
**下面的接口必须在 `dds_client_init ` 和 `dds_client_start` 正确返回之后才能正确执行。**
|
|
||||||
|
|
||||||
```
|
|
||||||
向 sdk 内部发送消息:
|
|
||||||
|
|
||||||
int dds_client_publish(struct dds_client *ds, int ev,
|
|
||||||
const char *data);
|
|
||||||
|
|
||||||
参数说明:
|
|
||||||
@ ds: 由 dds_client_init 返回的 struct dds_client 实例指针;
|
|
||||||
@ ev: 发送的消息事件;
|
|
||||||
@ data: 此消息附带的数据, json 格式;
|
|
||||||
|
|
||||||
|
|
||||||
返回值:
|
|
||||||
|
|
||||||
只有当 sdk 完成初始化并且授权成功之后才能正确返回,否则返回 -1
|
|
||||||
|
|
||||||
```
|
|
||||||
|
|
||||||
```
|
|
||||||
返回 nativeAPI 查询结果的接口
|
|
||||||
|
|
||||||
int dds_client_resp_nativeapi(struct dds_client *ds,
|
|
||||||
const char *native_api, const char *native_api_data_json);
|
|
||||||
|
|
||||||
参数说明:
|
|
||||||
|
|
||||||
ds: sdk 实例指针;
|
|
||||||
|
|
||||||
native_api: 这个 nativeAPI topic 名;
|
|
||||||
|
|
||||||
native_api_data_json: 查询数据结果,json string,格式如下,
|
|
||||||
"duiWidget" 字段必须包含, 且目前取值为 "text"。 用户自定义的数据必须放在
|
|
||||||
extra 字段中。
|
|
||||||
|
|
||||||
{
|
|
||||||
"duiWidget": "text",
|
|
||||||
"extra": {
|
|
||||||
"xx": "11"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
返回值: 如果 sdk 没有初始化完成或者授权成功则返回-1
|
|
||||||
|
|
||||||
```
|
|
||||||
|
|
||||||
```
|
|
||||||
内部合成的接口:
|
|
||||||
|
|
||||||
int dds_client_speak(struct dds_client *ds, const char *text);
|
|
||||||
|
|
||||||
参数说明:
|
|
||||||
|
|
||||||
ds: sdk 实例指针
|
|
||||||
|
|
||||||
text: 需要合成的文本
|
|
||||||
|
|
||||||
返回值: 如果 sdk 没有初始化完成或者授权成功则返回-1
|
|
||||||
```
|
|
||||||
|
|
||||||
```
|
|
||||||
外部 feed 音频接口:
|
|
||||||
|
|
||||||
int dds_client_feed_audio(struct dds_client *ds, char *data, int len);
|
|
||||||
|
|
||||||
参数说明:
|
|
||||||
|
|
||||||
ds: sdk 实例指针
|
|
||||||
|
|
||||||
data: 录音机数据
|
|
||||||
|
|
||||||
len: 数据长度
|
|
||||||
|
|
||||||
返回值: 出错返回 -1 ,此接口只有在 recorder 配置为外部方式才会生效。
|
|
||||||
|
|
||||||
|
|
||||||
```
|
|
||||||
|
|
||||||
```
|
|
||||||
停止当前对话,包括停止合成,取消识别等。
|
|
||||||
|
|
||||||
int dds_client_stop_dialog(struct dds_client *ds);
|
|
||||||
|
|
||||||
参数说明:
|
|
||||||
|
|
||||||
ds: sdk 实例指针
|
|
||||||
|
|
||||||
text: 需要合成的文本
|
|
||||||
|
|
||||||
返回值: 如果 sdk 没有初始化完成或者授权成功则返回-1
|
|
||||||
|
|
||||||
```
|
|
||||||
|
|
||||||
```
|
|
||||||
关闭唤醒,如果在语音对话过程中调用此接口,会在这条对话自然结束之后才会禁止唤醒。
|
|
||||||
|
|
||||||
int dds_client_disable_wakeup(struct dds_client *ds);
|
|
||||||
|
|
||||||
参数说明:
|
|
||||||
|
|
||||||
ds: sdk 实例指针
|
|
||||||
|
|
||||||
返回值: 如果 sdk 没有初始化完成或者授权成功则返回-1
|
|
||||||
|
|
||||||
```
|
|
||||||
|
|
||||||
```
|
|
||||||
打开唤醒
|
|
||||||
|
|
||||||
int dds_client_enable_wakeup(struct dds_client *ds);
|
|
||||||
|
|
||||||
参数说明:
|
|
||||||
|
|
||||||
ds: sdk 实例指针
|
|
||||||
|
|
||||||
返回值: 如果 sdk 没有初始化完成或者授权成功则返回-1
|
|
||||||
|
|
||||||
```
|
|
||||||
|
|
||||||
```
|
|
||||||
设置用户唤醒词
|
|
||||||
|
|
||||||
int dds_client_update_customword(struct dds_client *ds,
|
|
||||||
const char *word);
|
|
||||||
|
|
||||||
参数说明:
|
|
||||||
ds: sdk 实例指针
|
|
||||||
word: 唤醒词配置,格式是 json string,说明如下:
|
|
||||||
|
|
||||||
{
|
|
||||||
"greetingFile":"path:../res/tts/help.mp3", 可选
|
|
||||||
"greeting": "我在,有什么可以帮你", 可选
|
|
||||||
"pinyin": "ni hao xiao chi", 必选
|
|
||||||
"name": "你好小驰", 必选
|
|
||||||
"threshold": 0.127 必选
|
|
||||||
}
|
|
||||||
|
|
||||||
此函数成功返回后,唤醒词的相关配置会更新到 config.json 文件。
|
|
||||||
对于客户端异常断电可能导致 config.json 文件破坏的话, 需要开发者自己来避免,
|
|
||||||
比如采用备份文件的机制。
|
|
||||||
|
|
||||||
```
|
|
||||||
|
|
||||||
```
|
|
||||||
获取当前的唤醒词
|
|
||||||
|
|
||||||
char* dds_client_get_wakeupwords(struct dds_client *ds);
|
|
||||||
|
|
||||||
参数说明:
|
|
||||||
ds: sdk 实例指针
|
|
||||||
|
|
||||||
此函数返回字符串指针, 开发者需要主动释放内存。 返回字符串为json格式,如下:
|
|
||||||
|
|
||||||
{
|
|
||||||
"majorword": [{
|
|
||||||
"greetingFile": "path:../res/tts/help.mp3",
|
|
||||||
"greeting": "我在,有什么可以帮你",
|
|
||||||
"pinyin": "ni hao xiao le",
|
|
||||||
"name": "你好小乐",
|
|
||||||
"threshold": 0.144000
|
|
||||||
}],
|
|
||||||
"minorword": [{
|
|
||||||
"greetingFile": "path:../res/tts/help.mp3",
|
|
||||||
"greeting": "我在,有什么可以帮你",
|
|
||||||
"pinyin": "ni hao xiao chi",
|
|
||||||
"name": "你好小驰",
|
|
||||||
"threshold": 0.127000
|
|
||||||
}],
|
|
||||||
"cmdword": [{
|
|
||||||
"pinyin": "jiang di yin liang",
|
|
||||||
"threshold": 0.100000,
|
|
||||||
"action": "decrease.volume",
|
|
||||||
"name": "降低音量"
|
|
||||||
}],
|
|
||||||
"customword": [{
|
|
||||||
"pinyin": "ni hao tiam mao",
|
|
||||||
"name": "你好天猫",
|
|
||||||
"threshold": 0.200000
|
|
||||||
}]
|
|
||||||
}
|
|
||||||
|
|
||||||
majorword 为主唤醒词,minorword 为副唤醒词, cmdword 为命令词,
|
|
||||||
customword 为用户定义唤醒词。 其实就是 config.json 文件里面的配置。
|
|
||||||
|
|
||||||
```
|
|
||||||
|
|
||||||
```
|
|
||||||
|
|
||||||
// 获取当前的 tts 发音人,出错返回 NULL
|
|
||||||
char *dds_client_get_speaker(struct dds_client *ds);
|
|
||||||
|
|
||||||
// 获取当前的 tts 播报速度,为 float 型, 在 0 ~ 1 之间,越大表示速度越慢。
|
|
||||||
float dds_clent_get_speed(struct dds_client *ds);
|
|
||||||
|
|
||||||
// 获取当前的 tts 的播报音量大小, 为 int 型, 在 0 ~ 100 之间。
|
|
||||||
int dds_client_get_volume(struct dds_client *ds);
|
|
||||||
|
|
||||||
// 设置当前的 tts 的播报音色人,出错返回 -1
|
|
||||||
int dds_client_set_speaker(struct dds_client *ds, char *speaker);
|
|
||||||
|
|
||||||
// 设置当前的 tts 的播报速度大小,出错返回 -1
|
|
||||||
int dds_client_set_speed(struct dds_client *ds, float speed);
|
|
||||||
|
|
||||||
// 设置当前的 tts 的播报音量大小,出错返回 -1
|
|
||||||
int dds_client_set_volume(struct dds_client *ds, int vol);
|
|
||||||
|
|
||||||
```
|
|
||||||
|
|
||||||
**sdk回调消息接口**
|
|
||||||
|
|
||||||
<table>
|
|
||||||
<tr>
|
|
||||||
<th>回调函数</th>
|
|
||||||
<th>消息</th>
|
|
||||||
<th>含义</th>
|
|
||||||
<th>参数</th>
|
|
||||||
</tr>
|
|
||||||
|
|
||||||
<tr>
|
|
||||||
<td> ddsLintener </td>
|
|
||||||
<td> local_wakeup.result </td>
|
|
||||||
<td> 唤醒事件 </td>
|
|
||||||
<td> json string,形如
|
|
||||||
{"type":"major","greeting":"好的",
|
|
||||||
"word":"你好小驰"} </td>
|
|
||||||
</tr>
|
|
||||||
|
|
||||||
|
|
||||||
<tr>
|
|
||||||
<td> ddsLintener </td>
|
|
||||||
<td> doa.result </td>
|
|
||||||
<td> doa事件 </td>
|
|
||||||
<td> json string, 形如 {"dao": 100} </td>
|
|
||||||
</tr>
|
|
||||||
|
|
||||||
<tr>
|
|
||||||
<td> ddsLintener </td>
|
|
||||||
<td> sys.vad.begin </td>
|
|
||||||
<td> vad开始的事件 </td>
|
|
||||||
<td> 无 </td>
|
|
||||||
</tr>
|
|
||||||
|
|
||||||
<tr>
|
|
||||||
<td> ddsLintener </td>
|
|
||||||
<td> sys.vad.end </td>
|
|
||||||
<td> vad结束的事件 </td>
|
|
||||||
<td> 无 </td>
|
|
||||||
</tr>
|
|
||||||
|
|
||||||
<tr>
|
|
||||||
<td> ddsLintener </td>
|
|
||||||
<td> sys.tts.begin </td>
|
|
||||||
<td> 合成音开始的事件 </td>
|
|
||||||
<td> 无 </td>
|
|
||||||
</tr>
|
|
||||||
|
|
||||||
<tr>
|
|
||||||
<td> ddsLintener </td>
|
|
||||||
<td> sys.tts.end </td>
|
|
||||||
<td> 合成音结束的事件,播放结束 </td>
|
|
||||||
<td> 无 </td>
|
|
||||||
</tr>
|
|
||||||
|
|
||||||
<tr>
|
|
||||||
<td> ddsLintener </td>
|
|
||||||
<td> sys.asr.begin </td>
|
|
||||||
<td> sdk内部开始做识别 </td>
|
|
||||||
<td> 无 </td>
|
|
||||||
</tr>
|
|
||||||
|
|
||||||
<tr>
|
|
||||||
<td> ddsLintener </td>
|
|
||||||
<td> asr.speech.text </td>
|
|
||||||
<td> 实时的语音识别结果反馈 </td>
|
|
||||||
<td> json string </td>
|
|
||||||
</tr>
|
|
||||||
|
|
||||||
<tr>
|
|
||||||
<td> ddsLintener </td>
|
|
||||||
<td> asr.speech.result </td>
|
|
||||||
<td> 最终的语音识别结果反馈 </td>
|
|
||||||
<td> json string </td>
|
|
||||||
</tr>
|
|
||||||
|
|
||||||
<tr>
|
|
||||||
<td> ddsLintener </td>
|
|
||||||
<td> dm.output </td>
|
|
||||||
<td> 对话的输出结果 </td>
|
|
||||||
<td> json string </td>
|
|
||||||
</tr>
|
|
||||||
|
|
||||||
<tr>
|
|
||||||
<td> ddsLintener </td>
|
|
||||||
<td> sys.dm.end </td>
|
|
||||||
<td> 表示结束对话 </td>
|
|
||||||
<td> 无 </td>
|
|
||||||
</tr>
|
|
||||||
|
|
||||||
<tr>
|
|
||||||
<td> ddsLintener </td>
|
|
||||||
<td> device.mode.return </td>
|
|
||||||
<td> 表示设置设备状态的回复消息 </td>
|
|
||||||
<td> json string "{"result":"success"}"</td>
|
|
||||||
</tr>
|
|
||||||
|
|
||||||
<tr>
|
|
||||||
<td> ddsLintener </td>
|
|
||||||
<td> sys.client.error </td>
|
|
||||||
<td> 表示客户端出现异常情况 </td>
|
|
||||||
<td> json string "{"error":"ttsError"}" 目前 error 字段的取值一共有: ttsError, ddsNetworkError, vadSlienceTimeout</td>
|
|
||||||
</tr>
|
|
||||||
|
|
||||||
<tr>
|
|
||||||
<td> ddsLintener </td>
|
|
||||||
<td> command://xx </td>
|
|
||||||
<td> 在dui平台上配置的 command 指令 </td>
|
|
||||||
<td> json string </td>
|
|
||||||
</tr>
|
|
||||||
|
|
||||||
<tr>
|
|
||||||
<td> ddsLintener </td>
|
|
||||||
<td> native://xx </td>
|
|
||||||
<td> 在dui平台上配置的 native 指令 </td>
|
|
||||||
<td> json string </td>
|
|
||||||
</tr>
|
|
||||||
|
|
||||||
</table>
|
|
||||||
|
|
||||||
### 配置选项
|
|
||||||
|
|
||||||
```
|
|
||||||
|
|
||||||
{
|
|
||||||
"sdk": {
|
|
||||||
"configPath":"./config.json"
|
|
||||||
},
|
|
||||||
"auth": {
|
|
||||||
"productId": "278569448",
|
|
||||||
"deviceProfile": ""
|
|
||||||
},
|
|
||||||
"front": {
|
|
||||||
"aecBinPath": "",
|
|
||||||
"wakeupBinPath": "",
|
|
||||||
"beamformingBinPath": "",
|
|
||||||
"rollBack": 0
|
|
||||||
},
|
|
||||||
"vad": {
|
|
||||||
"resBinPath": "",
|
|
||||||
"pauseTime": 500,
|
|
||||||
"slienceTimeout": 5
|
|
||||||
},
|
|
||||||
"cloud": {
|
|
||||||
"productId": "278569448",
|
|
||||||
"aliasKey": "prod"
|
|
||||||
},
|
|
||||||
"recorder": {
|
|
||||||
"mode": "internal"
|
|
||||||
"samplerate":16000,
|
|
||||||
"bits":16,
|
|
||||||
"channels":1,
|
|
||||||
"device": "default"
|
|
||||||
},
|
|
||||||
"player": {
|
|
||||||
"device": "default"
|
|
||||||
},
|
|
||||||
"tts": {
|
|
||||||
"type": "cloud",
|
|
||||||
"voice": "zhilingf",
|
|
||||||
"volume": 50,
|
|
||||||
"speed": 0.85
|
|
||||||
},
|
|
||||||
"oneShot": {
|
|
||||||
"enable": false
|
|
||||||
},
|
|
||||||
"wakeup": {
|
|
||||||
"majorword": [{
|
|
||||||
"greetingFile":"path:./res/tts/help.mp3",
|
|
||||||
"greeting": "我在,有什么可以帮你",
|
|
||||||
"pinyin": "ni hao xiao le",
|
|
||||||
"name": "你好小乐",
|
|
||||||
"threshold": 0.144
|
|
||||||
}],
|
|
||||||
"minorword": [{
|
|
||||||
"greetingFile":"path:./res/tts/help.mp3",
|
|
||||||
"greeting": "我在,有什么可以帮你",
|
|
||||||
"pinyin": "ni hao xiao chi",
|
|
||||||
"name": "你好小驰",
|
|
||||||
"threshold": 0.127
|
|
||||||
}],
|
|
||||||
"minorword": [{
|
|
||||||
"greetingFile":"path:./res/tts/help.mp3",
|
|
||||||
"greeting": "我在,有什么可以帮你",
|
|
||||||
"pinyin": "ni hao xiao bu",
|
|
||||||
"name": "你好小步",
|
|
||||||
"threshold": 0.127
|
|
||||||
}],
|
|
||||||
"cmdword": [{
|
|
||||||
"pinyin": "jiang di yin liang",
|
|
||||||
"threshold": 0.100,
|
|
||||||
"action": "decrease.volume",
|
|
||||||
"name": "降低音量"
|
|
||||||
}]
|
|
||||||
},
|
|
||||||
"abnormal": {
|
|
||||||
"netErrorHint":"path:../res/tts/net.mp3",
|
|
||||||
"ttsErrorHint":"path:../res/tts/tts_error.mp3"
|
|
||||||
},
|
|
||||||
"debug": {
|
|
||||||
"recAudioDumpFile":"",
|
|
||||||
"bfAudioDumpFile":""
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
<table>
|
|
||||||
<tr>
|
|
||||||
<th>参数</th>
|
|
||||||
<th>类型</th>
|
|
||||||
<th>含义</th>
|
|
||||||
<th>是否必须</th>
|
|
||||||
</tr>
|
|
||||||
|
|
||||||
<tr>
|
|
||||||
<td> sdk </td>
|
|
||||||
<td> json 对象 </td>
|
|
||||||
<td> 客户端的一些配置 </td>
|
|
||||||
<td>必选</td>
|
|
||||||
</tr>
|
|
||||||
|
|
||||||
<tr>
|
|
||||||
<td> sdk.configPath </td>
|
|
||||||
<td> string </td>
|
|
||||||
<td> 配置文件路径 </td>
|
|
||||||
<td>必选</td>
|
|
||||||
</tr>
|
|
||||||
|
|
||||||
<tr>
|
|
||||||
<td> auth </td>
|
|
||||||
<td> json 对象 </td>
|
|
||||||
<td> 授权信息 </td>
|
|
||||||
<td>必选</td>
|
|
||||||
</tr>
|
|
||||||
|
|
||||||
<tr>
|
|
||||||
<td> auth.productId </td>
|
|
||||||
<td>string</td>
|
|
||||||
<td> dui 上创建产品ID </td>
|
|
||||||
<td>必选</td>
|
|
||||||
</tr>
|
|
||||||
|
|
||||||
<tr>
|
|
||||||
<td> auth.deviceProfile </td>
|
|
||||||
<td>string</td>
|
|
||||||
<td>授权信息</td>
|
|
||||||
<td>必选</td>
|
|
||||||
</tr>
|
|
||||||
|
|
||||||
<tr>
|
|
||||||
<td> front </td>
|
|
||||||
<td>json 对象 </td>
|
|
||||||
<td> 前端信号处理的相关配置 </td>
|
|
||||||
<td>必选</td>
|
|
||||||
</tr>
|
|
||||||
|
|
||||||
<tr>
|
|
||||||
<td> front.aecBinPath </td>
|
|
||||||
<td> string</td>
|
|
||||||
<td>aec 算法资源路径</td>
|
|
||||||
<td>可选</td>
|
|
||||||
</tr>
|
|
||||||
|
|
||||||
<tr>
|
|
||||||
<td> front.wakeupBinPath </td>
|
|
||||||
<td>string</td>
|
|
||||||
<td>唤醒算法资源路径</td>
|
|
||||||
<td>必选</td>
|
|
||||||
</tr>
|
|
||||||
|
|
||||||
<tr>
|
|
||||||
<td> front.beamformingBinPath </td>
|
|
||||||
<td>string</td>
|
|
||||||
<td>beamforming 算法资源路径</td>
|
|
||||||
<td>可选</td>
|
|
||||||
</tr>
|
|
||||||
|
|
||||||
<tr>
|
|
||||||
<td> vad </td>
|
|
||||||
<td> json 对象 </td>
|
|
||||||
<td>vad 算法模块配置 </td>
|
|
||||||
<td>必选</td>
|
|
||||||
</tr>
|
|
||||||
|
|
||||||
<tr>
|
|
||||||
<td> vad.resBinPath </td>
|
|
||||||
<td>string</td>
|
|
||||||
<td>vad算法资源路径 </td>
|
|
||||||
<td>必选</td>
|
|
||||||
</tr>
|
|
||||||
|
|
||||||
<tr>
|
|
||||||
<td> vad.pauseTime </td>
|
|
||||||
<td>int</td>
|
|
||||||
<td>vad截止检测时长,单位为 ms,默认为 500ms </td>
|
|
||||||
<td>可选</td>
|
|
||||||
</tr>
|
|
||||||
|
|
||||||
<tr>
|
|
||||||
<td> vad.slienceTimeout </td>
|
|
||||||
<td>int</td>
|
|
||||||
<td> vad 的静音检测超时时长,单位为s,默认为 6s </td>
|
|
||||||
<td>可选</td>
|
|
||||||
</tr>
|
|
||||||
|
|
||||||
<tr>
|
|
||||||
<td> cloud </td>
|
|
||||||
<td>json 对象 </td>
|
|
||||||
<td>云端产品的相关配置 </td>
|
|
||||||
<td>必选</td>
|
|
||||||
</tr>
|
|
||||||
|
|
||||||
<tr>
|
|
||||||
<td>cloud.productId </td>
|
|
||||||
<td>string</td>
|
|
||||||
<td>dui平台上创建的产品ID</td>
|
|
||||||
<td>必选 </td>
|
|
||||||
</tr>
|
|
||||||
|
|
||||||
<tr>
|
|
||||||
<td> cloud.aliasKey </td>
|
|
||||||
<td>string</td>
|
|
||||||
<td> dui平台上创建的产品ID 发布支持, 取值为 "prod | test"</td>
|
|
||||||
<td>可选,默认为 prod 分支</td>
|
|
||||||
</tr>
|
|
||||||
|
|
||||||
<tr>
|
|
||||||
<td>recorder </td>
|
|
||||||
<td>json 对象 </td>
|
|
||||||
<td>录音机的相关配置 </td>
|
|
||||||
<td>必选</td>
|
|
||||||
</tr>
|
|
||||||
|
|
||||||
<tr>
|
|
||||||
<td> recorder.mode </td>
|
|
||||||
<td> string </td>
|
|
||||||
<td> 录音方式,取值为 "internal | external" 分列表示内部录音和外部录音。 </td>
|
|
||||||
<td> 可选 </td>
|
|
||||||
</tr>
|
|
||||||
|
|
||||||
<tr>
|
|
||||||
<td> recorder.samplerate </td>
|
|
||||||
<td> int </td>
|
|
||||||
<td> 录音采样率 </td>
|
|
||||||
<td> 必选 </td>
|
|
||||||
</tr>
|
|
||||||
|
|
||||||
<tr>
|
|
||||||
<td> recorder.bits </td>
|
|
||||||
<td>int</td>
|
|
||||||
<td>录音采样位数</td>
|
|
||||||
<td>必选</td>
|
|
||||||
</tr>
|
|
||||||
|
|
||||||
<tr>
|
|
||||||
<td> recorder.channels </td>
|
|
||||||
<td>int</td>
|
|
||||||
<td>录音采用通道数</td>
|
|
||||||
<td>必选</td>
|
|
||||||
</tr>
|
|
||||||
|
|
||||||
<tr>
|
|
||||||
<td> recorder.device </td>
|
|
||||||
<td> string </td>
|
|
||||||
<td>内部录音机的设备名,默认当前系统的 default 音频设备 </td>
|
|
||||||
<td>可选</td>
|
|
||||||
</tr>
|
|
||||||
|
|
||||||
<tr>
|
|
||||||
<td> player</td>
|
|
||||||
<td> json 对象 </td>
|
|
||||||
<td>内部播放器的设置 </td>
|
|
||||||
<td>可选</td>
|
|
||||||
</tr>
|
|
||||||
|
|
||||||
<tr>
|
|
||||||
<td> player.device </td>
|
|
||||||
<td> string </td>
|
|
||||||
<td>内部播放器的设备名,默认为 default </td>
|
|
||||||
<td>可选</td>
|
|
||||||
</tr>
|
|
||||||
|
|
||||||
<tr>
|
|
||||||
<td> tts </td>
|
|
||||||
<td>json 对象</td>
|
|
||||||
<td>合成音的相关配置</td>
|
|
||||||
<td>必选</td>
|
|
||||||
</tr>
|
|
||||||
|
|
||||||
|
|
||||||
<tr>
|
|
||||||
<td> tts.type </td>
|
|
||||||
<td>string </td>
|
|
||||||
<td>合成音的类型,当前仅支持 "cloud" </td>
|
|
||||||
<td>必选</td>
|
|
||||||
</tr>
|
|
||||||
|
|
||||||
<tr>
|
|
||||||
<td> tts.voice </td>
|
|
||||||
<td>string </td>
|
|
||||||
<td>合成音的音色 </td>
|
|
||||||
<td>可选</td>
|
|
||||||
</tr>
|
|
||||||
|
|
||||||
<tr>
|
|
||||||
<td> tts.volume </td>
|
|
||||||
<td> int </td>
|
|
||||||
<td>合成音的音量 </td>
|
|
||||||
<td>可选</td>
|
|
||||||
</tr>
|
|
||||||
|
|
||||||
<tr>
|
|
||||||
<td> tts.speed </td>
|
|
||||||
<td> int </td>
|
|
||||||
<td>合成音的速度 </td>
|
|
||||||
<td>可选</td>
|
|
||||||
</tr>
|
|
||||||
|
|
||||||
<tr>
|
|
||||||
<td> oneShot </td>
|
|
||||||
<td> json 对象 </td>
|
|
||||||
<td> oneshot 模块配置 </td>
|
|
||||||
<td>必选</td>
|
|
||||||
</tr>
|
|
||||||
|
|
||||||
<tr>
|
|
||||||
<td> oneShot.enable </td>
|
|
||||||
<td> bool </td>
|
|
||||||
<td> 是否启用oneshot,当前仅支持 false </td>
|
|
||||||
<td>可选</td>
|
|
||||||
</tr>
|
|
||||||
|
|
||||||
<tr>
|
|
||||||
<td> wakeup </td>
|
|
||||||
<td> json 对象 </td>
|
|
||||||
<td> 唤醒词的相关配置</td>
|
|
||||||
<td>必选</td>
|
|
||||||
</tr>
|
|
||||||
|
|
||||||
<tr>
|
|
||||||
<td> wakeup.majorword </td>
|
|
||||||
<td> json 数组 </td>
|
|
||||||
<td> 主唤醒词的相关配置</td>
|
|
||||||
<td>必选</td>
|
|
||||||
</tr>
|
|
||||||
|
|
||||||
<tr>
|
|
||||||
<td> wakeup.minorword </td>
|
|
||||||
<td> json 数组 </td>
|
|
||||||
<td> 副唤醒词的相关配置</td>
|
|
||||||
<td>可选</td>
|
|
||||||
</tr>
|
|
||||||
|
|
||||||
<tr>
|
|
||||||
<td> wakeup.customword </td>
|
|
||||||
<td> json 数组 </td>
|
|
||||||
<td> 用户定义唤醒词的相关配置</td>
|
|
||||||
<td>可选</td>
|
|
||||||
</tr>
|
|
||||||
|
|
||||||
|
|
||||||
<tr>
|
|
||||||
<td> wakeup.cmdword </td>
|
|
||||||
<td> json 数组 </td>
|
|
||||||
<td> 快捷唤醒词配置 </td>
|
|
||||||
<td>可选</td>
|
|
||||||
</tr>
|
|
||||||
|
|
||||||
<tr>
|
|
||||||
<td> abnormal </td>
|
|
||||||
<td> json 对象 </td>
|
|
||||||
<td> sdk异常情况下对话配置 </td>
|
|
||||||
<td>可选</td>
|
|
||||||
</tr>
|
|
||||||
|
|
||||||
<tr>
|
|
||||||
<td> abnormal.netErrorHint </td>
|
|
||||||
<td> string </td>
|
|
||||||
<td> 网络错误下的提示音,需要配置成本地文件,网络不好的情况下云端合成也用不了。 </td>
|
|
||||||
<td>可选</td>
|
|
||||||
</tr>
|
|
||||||
|
|
||||||
<tr>
|
|
||||||
<td> abnormal.ttsErrorHint </td>
|
|
||||||
<td> string </td>
|
|
||||||
<td> 云端tts合成播放错误情况下的的提示音,需要配置成本地文件。 </td>
|
|
||||||
<td>可选</td>
|
|
||||||
</tr>
|
|
||||||
|
|
||||||
<tr>
|
|
||||||
<td> debug</td>
|
|
||||||
<td> json 对象 </td>
|
|
||||||
<td> 保存音频的配置选项 </td>
|
|
||||||
<td>可选</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td> debug.recAudioDumpFile</td>
|
|
||||||
<td> string </td>
|
|
||||||
<td> 原始录音保存文件路径 </td>
|
|
||||||
<td>可选</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td> debug.bfAudioDumpFile</td>
|
|
||||||
<td> string </td>
|
|
||||||
<td> beamforming算法输出的音频文件路径 </td>
|
|
||||||
<td>可选</td>
|
|
||||||
</tr>
|
|
||||||
|
|
||||||
</table>
|
|
||||||
|
|
||||||
|
|
||||||
**唤醒词说明**
|
|
||||||
|
|
||||||
```
|
|
||||||
{
|
|
||||||
"greetingFile":"path:./res/tts/help.mp3",
|
|
||||||
"greeting": "我在,有什么可以帮你",
|
|
||||||
"pinyin": "ni hao xiao chi",
|
|
||||||
"name": "你好小驰",
|
|
||||||
"threshold": 0.127
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
greetingFile: 唤醒之后播放的提示音,支持本地录音文件,传入文件路径。
|
|
||||||
greeting: 唤醒之后的提示文本, sdk内部合成。
|
|
||||||
pinyin: 唤醒词拼音。
|
|
||||||
name: 唤醒词的中文。
|
|
||||||
threshold: 唤醒词阈值。
|
|
||||||
|
|
||||||
唤醒提示音播放优先级: 如果配置了 greetingFile 则播放 greetingFile ,
|
|
||||||
否则播放 greeting 。
|
|
||||||
|
|
||||||
```
|
|
||||||
|
|
||||||
|
|
||||||
**命令唤醒词说明**
|
|
||||||
|
|
||||||
```
|
|
||||||
{
|
|
||||||
"pinyin": "jiang di yin liang",
|
|
||||||
"threshold": 0.100,
|
|
||||||
"action": "decrease.volume",
|
|
||||||
"name": "降低音量"
|
|
||||||
}
|
|
||||||
|
|
||||||
pinyin: 唤醒词拼音。
|
|
||||||
name: 唤醒词的中文。
|
|
||||||
threshold: 唤醒词阈值。
|
|
||||||
action: 该命令唤醒词对应的动作,比如这个例子中,sdk回调函数会抛出
|
|
||||||
command://decrease.volume 消息。
|
|
||||||
```
|
|
||||||
Binary file not shown.
BIN
rk3308/aispeech-2mic-32bit/dds_client/dui
Executable file
BIN
rk3308/aispeech-2mic-32bit/dds_client/dui
Executable file
Binary file not shown.
39
rk3308/aispeech-2mic-32bit/dds_client/dui_cfg.json
Executable file
39
rk3308/aispeech-2mic-32bit/dds_client/dui_cfg.json
Executable file
@ -0,0 +1,39 @@
|
|||||||
|
{
|
||||||
|
"auth":{
|
||||||
|
"productId": "100001463",
|
||||||
|
"deviceProfile": "Yhn7W3QzXThMGBG1qgJcbCmW0hmO7HYdHcfuQPFzJhgnzWrrJhPPWYTdm5qJlpyarJqcjZqL3cXdz8fKm5nNycyZmcbGy5udy52cy8bHzsuZzJ6ZmZrLzMnd092ek5OQiN3FztPdj42Qm4qci7ab3cXdzs/Pz8/Oy8nM3dPdm5qJlpyasZ6Smt3F3Z7Oy8icnpmbms6bnsvNm87Gz83MnsqZzcicy83Iy5rN3dPdjJyQj5rdxaTdnpOT3aKC"
|
||||||
|
},
|
||||||
|
"recorder":{
|
||||||
|
"device":"2mic_loopback",
|
||||||
|
"bits":16,
|
||||||
|
"channels":3,
|
||||||
|
"samplerate":16000
|
||||||
|
},
|
||||||
|
"player":{
|
||||||
|
"device":"default"
|
||||||
|
},
|
||||||
|
"wakeup":{
|
||||||
|
"cfg":{
|
||||||
|
"aecBinPath":"./res/AEC_ch3-2-ch2_1ref_common_20180705_v0.9.4.bin",
|
||||||
|
"wakeupBinPath":"./res/wakeup_aifar_comm_20180104.bin",
|
||||||
|
"beamformingBinPath":"./res/UDA_asr_chan2-2-mic2_30mm_20180504.bin",
|
||||||
|
"env":"words=ni hao xiao le,ni hao xiao chi;thresh=0.34,0.3;major=1,0;",
|
||||||
|
"rollBack":100
|
||||||
|
},
|
||||||
|
"wakeupWord":["ni hao xiao le", "ni hao xiao chi"],
|
||||||
|
"wakeupAudio":["./audio/wakeup.mp3", "./audio/minor_wakeup.mp3"]
|
||||||
|
},
|
||||||
|
"vad":{
|
||||||
|
"cfg":{
|
||||||
|
"resBinPath":"./res/vad_aihome_v0.7.bin",
|
||||||
|
"pauseTime":300
|
||||||
|
},
|
||||||
|
"startTimeoutPrompt":"./audio/vad_start_timeout2.mp3"
|
||||||
|
},
|
||||||
|
"dds":{
|
||||||
|
"productId":"100001463",
|
||||||
|
"aliasKey":"prod",
|
||||||
|
"server":"ws://dds.dui.ai/dds/v1",
|
||||||
|
"deviceProfile":"Yhn7W3QzXThMGBG1qgJcbCmW0hmO7HYdHcfuQPFzJhgnzWrrJhPPWYTdm5qJlpyarJqcjZqL3cXdz8fKm5nNycyZmcbGy5udy52cy8bHzsuZzJ6ZmZrLzMnd092ek5OQiN3FztPdj42Qm4qci7ab3cXdzs/Pz8/Oy8nM3dPdm5qJlpyasZ6Smt3F3Z7Oy8icnpmbms6bnsvNm87Gz83MnsqZzcicy83Iy5rN3dPdjJyQj5rdxaTdnpOT3aKC"
|
||||||
|
}
|
||||||
|
}
|
||||||
Binary file not shown.
BIN
rk3308/aispeech-2mic-32bit/dds_client/lib/rk3308_32/libdemo_depend.so
Executable file
BIN
rk3308/aispeech-2mic-32bit/dds_client/lib/rk3308_32/libdemo_depend.so
Executable file
Binary file not shown.
BIN
rk3308/aispeech-2mic-32bit/dds_client/lib/rk3308_32/libduilite_fespl.so
Executable file
BIN
rk3308/aispeech-2mic-32bit/dds_client/lib/rk3308_32/libduilite_fespl.so
Executable file
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
rk3308/aispeech-2mic-32bit/dds_client/res/vad_aihome_v0.7.bin
Executable file
BIN
rk3308/aispeech-2mic-32bit/dds_client/res/vad_aihome_v0.7.bin
Executable file
Binary file not shown.
@ -5,15 +5,15 @@
|
|||||||
case "$1" in
|
case "$1" in
|
||||||
start)
|
start)
|
||||||
echo "Starting $0..."
|
echo "Starting $0..."
|
||||||
cd /oem/dds_client/demo && ./demo_main &
|
cd /oem/dds_client && ./dui dui_cfg.json &
|
||||||
;;
|
;;
|
||||||
stop)
|
stop)
|
||||||
echo "Stop $0..."
|
echo "Stop $0..."
|
||||||
killall demo_main
|
killall dui
|
||||||
;;
|
;;
|
||||||
restart|reload)
|
restart|reload)
|
||||||
killall demo_main
|
killall dui
|
||||||
cd /oem/dds_client/demo && ./demo_main &
|
cd /oem/dds_client && ./dui dui_cfg.json &
|
||||||
;;
|
;;
|
||||||
*)
|
*)
|
||||||
echo "Usage: $0 {start|stop|restart}"
|
echo "Usage: $0 {start|stop|restart}"
|
||||||
|
|||||||
@ -6,7 +6,7 @@ softap_stop()
|
|||||||
{
|
{
|
||||||
echo softap_stoping
|
echo softap_stoping
|
||||||
|
|
||||||
killall dnsmasq || echo dnsmasq-exit
|
killall dui || echo dui-exit
|
||||||
ip addr delete 192.168.1.1 dev p2p0 || echo ip-addr-delete
|
ip addr delete 192.168.1.1 dev p2p0 || echo ip-addr-delete
|
||||||
killall hostapd || echo hostapd-exit
|
killall hostapd || echo hostapd-exit
|
||||||
ifconfig p2p0 down || echo p2p0
|
ifconfig p2p0 down || echo p2p0
|
||||||
@ -18,7 +18,7 @@ dds_start()
|
|||||||
{
|
{
|
||||||
softap_stop
|
softap_stop
|
||||||
#echo dds_start
|
#echo dds_start
|
||||||
pidof demo_main || $PROCESS start
|
pidof dui || $PROCESS start
|
||||||
|
|
||||||
gst-play-1.0 /data/aispeech_softap_lite/audio/connect_ok.mp3
|
gst-play-1.0 /data/aispeech_softap_lite/audio/connect_ok.mp3
|
||||||
}
|
}
|
||||||
@ -30,7 +30,7 @@ dds_stop()
|
|||||||
}
|
}
|
||||||
wifiReadyAction()
|
wifiReadyAction()
|
||||||
{
|
{
|
||||||
pidof demo_main || $PROCESS start
|
pidof dui || $PROCESS start
|
||||||
}
|
}
|
||||||
wifiUpAction()
|
wifiUpAction()
|
||||||
{
|
{
|
||||||
|
|||||||
Reference in New Issue
Block a user