aispeech: update v0.2.1
Change-Id: If9af87c22d73164476fb9abbb08b3e6fa7eeb739 Signed-off-by: Nyx Zheng <zyh@rock-chips.com>
This commit is contained in:
committed by
Zheng YingHang
parent
a6ad2bf547
commit
796ddd2e57
@ -5,6 +5,8 @@
|
|||||||
extern "C" {
|
extern "C" {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#define AUDIO_PLAYER_EXPORT __attribute ((visibility("default")))
|
||||||
|
|
||||||
#define AUDIO_PLAYER_EV_BEGIN 0x01
|
#define AUDIO_PLAYER_EV_BEGIN 0x01
|
||||||
#define AUDIO_PLAYER_EV_START 0x02
|
#define AUDIO_PLAYER_EV_START 0x02
|
||||||
#define AUDIO_PLAYER_EV_END 0x03
|
#define AUDIO_PLAYER_EV_END 0x03
|
||||||
@ -16,17 +18,19 @@ extern "C" {
|
|||||||
typedef int (*audio_player_callback)(void *userdata, int ev);
|
typedef int (*audio_player_callback)(void *userdata, int ev);
|
||||||
typedef struct audio_player audio_player_t;
|
typedef struct audio_player audio_player_t;
|
||||||
|
|
||||||
audio_player_t *audio_player_new(char *dev, audio_player_callback ccb, void *userdata);
|
AUDIO_PLAYER_EXPORT audio_player_t *audio_player_new(audio_player_callback ccb, void *userdata);
|
||||||
int audio_player_delete(audio_player_t *aplayer);
|
AUDIO_PLAYER_EXPORT int audio_player_delete(audio_player_t *aplayer);
|
||||||
int audio_player_play(audio_player_t *aplayer, char *path);
|
AUDIO_PLAYER_EXPORT int audio_player_play(audio_player_t *aplayer, char *path);
|
||||||
int audio_player_pause(audio_player_t *aplayer);
|
AUDIO_PLAYER_EXPORT int audio_player_pause(audio_player_t *aplayer);
|
||||||
int audio_player_resume(audio_player_t *aplayer);
|
AUDIO_PLAYER_EXPORT int audio_player_resume(audio_player_t *aplayer);
|
||||||
int audio_player_stop(audio_player_t *aplayer);
|
AUDIO_PLAYER_EXPORT int audio_player_stop(audio_player_t *aplayer);
|
||||||
|
|
||||||
int audio_player_get_volume(char *dev, int *l_vol, int *r_vol);
|
AUDIO_PLAYER_EXPORT int audio_player_get_volume(char *dev, int *l_vol, int *r_vol);
|
||||||
int audio_player_set_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);
|
||||||
|
|
||||||
int audio_player_set_channel_volume(audio_player_t *aplayer, float multiplier);
|
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
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
|
|||||||
@ -15,14 +15,15 @@ extern "C"
|
|||||||
{
|
{
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define DDS_CLIENT_VERSION "DDS_CLIENT 0.1.7"
|
#define DDS_CLIENT_VERSION "DDS_CLIENT 0.2.1"
|
||||||
|
|
||||||
#define DDS_CLIENT_TTS_ZHILING "zhilingf"
|
#define DDS_CLIENT_TTS_ZHILING "zhilingf" // 甜美女神
|
||||||
#define DDS_CLIENT_TTS_GDG "gdgm"
|
#define DDS_CLIENT_TTS_GDG "gdgm" // 沉稳纲叔
|
||||||
#define DDS_CLIENT_TTS_GEYOU "geyou"
|
#define DDS_CLIENT_TTS_GEYOU "geyou" // 淡定葛爷
|
||||||
#define DDS_CLIENT_TTS_HYANIF "hyanif"
|
#define DDS_CLIENT_TTS_HYANIF "hyanif" // 邻家女声
|
||||||
#define DDS_CLIENT_TTS_XIJUNM "xijunm"
|
#define DDS_CLIENT_TTS_XIJUNM "xijunm" // 标准男声
|
||||||
#define DDS_CLIENT_TTS_QIANRAN "qianranf"
|
#define DDS_CLIENT_TTS_QIANRAN "qianranf" // 可爱童声
|
||||||
|
#define DDS_CLIENT_TTS_LUCYF "lucyf" // 标准女声
|
||||||
|
|
||||||
#define DDS_CLIENT_USER_EV_BASE 1000
|
#define DDS_CLIENT_USER_EV_BASE 1000
|
||||||
#define DDS_CLIENT_USER_DEVICE_MODE 1001
|
#define DDS_CLIENT_USER_DEVICE_MODE 1001
|
||||||
@ -81,6 +82,8 @@ int dds_client_set_volume(struct dds_client *ds, int vol);
|
|||||||
*/
|
*/
|
||||||
int dds_client_disable_wakeup(struct dds_client *ds);
|
int dds_client_disable_wakeup(struct dds_client *ds);
|
||||||
int dds_client_enable_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
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
|
|||||||
@ -4,7 +4,10 @@ LOCAL_SRC_DIRS += json
|
|||||||
LOCAL_SRC_DIRS += button
|
LOCAL_SRC_DIRS += button
|
||||||
|
|
||||||
LOCAL_CFLAGS := -rdynamic -g -O0 -Wall -DMG_ENABLE_THREADS -Wno-unused-variable -fPIC
|
LOCAL_CFLAGS := -rdynamic -g -O0 -Wall -DMG_ENABLE_THREADS -Wno-unused-variable -fPIC
|
||||||
LOCAL_CFLAGS += -I.. -Ijson/ -Ibutton
|
LOCAL_CFLAGS += -I.. -Ijson/ -Ibutton -Ibusserver/mongoose -Ibusserver/src
|
||||||
|
LOCAL_CFLAGS += -DRK3308_BOARD_V11
|
||||||
|
LOCAL_CFLAGS += -DPDM_MIC # for v11
|
||||||
|
#
|
||||||
|
|
||||||
LOCAL_LDFLAGS += -Wl,-rpath,../
|
LOCAL_LDFLAGS += -Wl,-rpath,../
|
||||||
LOCAL_LDFLAGS += -L../ -ldds_client
|
LOCAL_LDFLAGS += -L../ -ldds_client
|
||||||
@ -26,7 +29,7 @@ CC = ../../../../../../buildroot/output/rockchip_rk3308_release/host/usr/bin/aar
|
|||||||
|
|
||||||
CFLAGS += $(LOCAL_CFLAGS)
|
CFLAGS += $(LOCAL_CFLAGS)
|
||||||
|
|
||||||
demo_main: main.o music.o json/cJSON.o button/button_api.o
|
demo_main: main.o music.o json/cJSON.o button/button_api.o busserver/src/busserver.o busserver/mongoose/mongoose.c
|
||||||
$(CC) -o $@ $^ $(CFLAGS) $(LOCAL_LDFLAGS) -lm
|
$(CC) -o $@ $^ $(CFLAGS) $(LOCAL_LDFLAGS) -lm
|
||||||
|
|
||||||
clean:
|
clean:
|
||||||
|
|||||||
@ -3,10 +3,14 @@ LOCAL_SRC_FILES += main.c
|
|||||||
LOCAL_SRC_FILES += music.c
|
LOCAL_SRC_FILES += music.c
|
||||||
LOCAL_SRC_DIRS += json
|
LOCAL_SRC_DIRS += json
|
||||||
LOCAL_SRC_DIRS += button
|
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 := -rdynamic -g -O0 -Wall -DMG_ENABLE_THREADS -Wno-unused-variable -fPIC
|
||||||
LOCAL_CFLAGS += -I.. -Ijson/ -Ibutton/
|
LOCAL_CFLAGS += -I.. -Ijson/ -Ibutton/ -Ibusserver/mongoose -Ibusserver/src
|
||||||
LOCAL_CFLAGS += -DRK3308_BOARD_V11
|
LOCAL_CFLAGS += -DRK3308_BOARD_V11
|
||||||
|
LOCAL_CFLAGS += -DPDM_MIC # for v11
|
||||||
|
#LOCAL_CFLAGS += -DDUAL_MIC # for 2mic
|
||||||
|
|
||||||
LOCAL_LDFLAGS += -Wl,-rpath,../
|
LOCAL_LDFLAGS += -Wl,-rpath,../
|
||||||
LOCAL_LDFLAGS += -L../ -ldds_client
|
LOCAL_LDFLAGS += -L../ -ldds_client
|
||||||
|
|||||||
12
rk3308/aispeech/dds_client/demo/busserver/aimakefile
Executable file
12
rk3308/aispeech/dds_client/demo/busserver/aimakefile
Executable file
@ -0,0 +1,12 @@
|
|||||||
|
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)
|
||||||
16
rk3308/aispeech/dds_client/demo/busserver/mongoose/LICENSE
Executable file
16
rk3308/aispeech/dds_client/demo/busserver/mongoose/LICENSE
Executable file
@ -0,0 +1,16 @@
|
|||||||
|
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>.
|
||||||
12332
rk3308/aispeech/dds_client/demo/busserver/mongoose/mongoose.c
Executable file
12332
rk3308/aispeech/dds_client/demo/busserver/mongoose/mongoose.c
Executable file
File diff suppressed because it is too large
Load Diff
4340
rk3308/aispeech/dds_client/demo/busserver/mongoose/mongoose.h
Executable file
4340
rk3308/aispeech/dds_client/demo/busserver/mongoose/mongoose.h
Executable file
File diff suppressed because it is too large
Load Diff
BIN
rk3308/aispeech/dds_client/demo/busserver/mongoose/mongoose.o
Executable file
BIN
rk3308/aispeech/dds_client/demo/busserver/mongoose/mongoose.o
Executable file
Binary file not shown.
188
rk3308/aispeech/dds_client/demo/busserver/src/busserver.c
Executable file
188
rk3308/aispeech/dds_client/demo/busserver/src/busserver.c
Executable file
@ -0,0 +1,188 @@
|
|||||||
|
/*================================================================
|
||||||
|
* 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;
|
||||||
|
}
|
||||||
|
|
||||||
31
rk3308/aispeech/dds_client/demo/busserver/src/busserver.h
Executable file
31
rk3308/aispeech/dds_client/demo/busserver/src/busserver.h
Executable file
@ -0,0 +1,31 @@
|
|||||||
|
#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
|
||||||
|
|
||||||
BIN
rk3308/aispeech/dds_client/demo/busserver/src/busserver.o
Executable file
BIN
rk3308/aispeech/dds_client/demo/busserver/src/busserver.o
Executable file
Binary file not shown.
43
rk3308/aispeech/dds_client/demo/busserver/src/main.c
Executable file
43
rk3308/aispeech/dds_client/demo/busserver/src/main.c
Executable file
@ -0,0 +1,43 @@
|
|||||||
|
/*================================================================
|
||||||
|
* 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;
|
||||||
|
}
|
||||||
BIN
rk3308/aispeech/dds_client/demo/busserver/src/main.o
Executable file
BIN
rk3308/aispeech/dds_client/demo/busserver/src/main.o
Executable file
Binary file not shown.
BIN
rk3308/aispeech/dds_client/demo/busserver/test
Executable file
BIN
rk3308/aispeech/dds_client/demo/busserver/test
Executable file
Binary file not shown.
@ -11,7 +11,7 @@
|
|||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#define RK3308_BOARD_V11
|
|
||||||
struct button{
|
struct button{
|
||||||
pthread_t pid;
|
pthread_t pid;
|
||||||
int fd;
|
int fd;
|
||||||
@ -29,7 +29,7 @@ typedef enum {
|
|||||||
PHY_BUTTON_CODE_VOLUME_SUB = 114,
|
PHY_BUTTON_CODE_VOLUME_SUB = 114,
|
||||||
|
|
||||||
//只支持短按
|
//只支持短按
|
||||||
PHY_BUTTON_CODE_MUTE = KEY_MICMUTE,
|
PHY_BUTTON_CODE_MUTE = 248,
|
||||||
|
|
||||||
//只支持短按
|
//只支持短按
|
||||||
PHY_BUTTON_CODE_PLAY_PAUSE = 207,
|
PHY_BUTTON_CODE_PLAY_PAUSE = 207,
|
||||||
|
|||||||
BIN
rk3308/aispeech/dds_client/demo/button/button_api.o
Normal file → Executable file
BIN
rk3308/aispeech/dds_client/demo/button/button_api.o
Normal file → Executable file
Binary file not shown.
@ -1,4 +1,7 @@
|
|||||||
{
|
{
|
||||||
|
"sdk": {
|
||||||
|
"configPath":"./config.json"
|
||||||
|
},
|
||||||
"auth": {
|
"auth": {
|
||||||
"productId": "278572662",
|
"productId": "278572662",
|
||||||
"deviceProfile": "tp6jDOrO/Wea5K21djQpDlSyD6/ojZypKsAOVBNF4FnQHkt6TyJ+IoTdm5qJlpyarJqcjZqL3cXdxpnPxsqbzcnKms/Ly57Mxp7NzM3Im5rJysqdx57NyJ7d092ek5OQiN3FztPdj42Qm4qci7ab3cXdzcjHysjNycnN3dPdm5qJlpyasZ6Smt3F3ZqdnpuZyZ2ZypycncucyZnGy8icms6ayM/GyJ6bm5vK3dPdjJyQj5rdxaTdnpOT3aKC"
|
"deviceProfile": "tp6jDOrO/Wea5K21djQpDlSyD6/ojZypKsAOVBNF4FnQHkt6TyJ+IoTdm5qJlpyarJqcjZqL3cXdxpnPxsqbzcnKms/Ly57Mxp7NzM3Im5rJysqdx57NyJ7d092ek5OQiN3FztPdj42Qm4qci7ab3cXdzcjHysjNycnN3dPdm5qJlpyasZ6Smt3F3ZqdnpuZyZ2ZypycncucyZnGy8icms6ayM/GyJ6bm5vK3dPdjJyQj5rdxaTdnpOT3aKC"
|
||||||
@ -11,7 +14,7 @@
|
|||||||
},
|
},
|
||||||
"vad": {
|
"vad": {
|
||||||
"resBinPath": "../res/vad/vad_aihome_v0.6.bin",
|
"resBinPath": "../res/vad/vad_aihome_v0.6.bin",
|
||||||
"pauseTime": 300,
|
"pauseTime": 500,
|
||||||
"slienceTimeout": 6
|
"slienceTimeout": 6
|
||||||
},
|
},
|
||||||
"cloud": {
|
"cloud": {
|
||||||
@ -38,18 +41,19 @@
|
|||||||
},
|
},
|
||||||
"wakeup": {
|
"wakeup": {
|
||||||
"majorword": [{
|
"majorword": [{
|
||||||
"greetingFile":"path:../res/tts/help.mp3",
|
|
||||||
"greeting": "我在,有什么可以帮你",
|
|
||||||
"pinyin": "ni hao xiao chi",
|
|
||||||
"name": "你好小池",
|
|
||||||
"threshold": 0.37
|
|
||||||
}, {
|
|
||||||
"greetingFile":"path:../res/tts/help.mp3",
|
"greetingFile":"path:../res/tts/help.mp3",
|
||||||
"greeting": "我在,有什么可以帮你",
|
"greeting": "我在,有什么可以帮你",
|
||||||
"pinyin": "ni hao xiao le",
|
"pinyin": "ni hao xiao le",
|
||||||
"name": "你好小乐",
|
"name": "你好小乐",
|
||||||
"threshold": 0.34
|
"threshold": 0.34
|
||||||
}],
|
}],
|
||||||
|
"minorword":[{
|
||||||
|
"greetingFile":"path:../res/tts/help.mp3",
|
||||||
|
"greeting": "我在,有什么可以帮你",
|
||||||
|
"pinyin": "ni hao xiao chi",
|
||||||
|
"name": "你好小驰",
|
||||||
|
"threshold": 0.34
|
||||||
|
}],
|
||||||
"cmdword": [{
|
"cmdword": [{
|
||||||
"pinyin": "jiang di yin liang",
|
"pinyin": "jiang di yin liang",
|
||||||
"threshold": 0.100,
|
"threshold": 0.100,
|
||||||
@ -58,7 +62,12 @@
|
|||||||
}]
|
}]
|
||||||
},
|
},
|
||||||
"abnormal": {
|
"abnormal": {
|
||||||
"netErrorHint":"path:../res/tts/net.mp3"
|
"netErrorHint":"path:../res/tts/net.mp3",
|
||||||
|
"ttsErrorHint":"path:../res/tts/tts_error.mp3"
|
||||||
|
},
|
||||||
|
"debug": {
|
||||||
|
"recAudioDumpFile":"",
|
||||||
|
"bfAudioDumpFile":""
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Binary file not shown.
Binary file not shown.
@ -17,26 +17,29 @@
|
|||||||
#include <time.h>
|
#include <time.h>
|
||||||
#include "dds_client.h"
|
#include "dds_client.h"
|
||||||
#include "button.h"
|
#include "button.h"
|
||||||
|
#include "busserver.h"
|
||||||
#include "cJSON.h"
|
#include "cJSON.h"
|
||||||
#include <stdbool.h>
|
|
||||||
int is_enable_wakeup = 1;
|
|
||||||
struct dds_client *dc = NULL;
|
struct dds_client *dc = NULL;
|
||||||
bool m_is_dialog = false;
|
int is_enable_wakeup = 1;
|
||||||
bool m_is_tts_playing = false;
|
|
||||||
pthread_mutex_t mylock=PTHREAD_MUTEX_INITIALIZER;
|
|
||||||
pthread_cond_t mycond=PTHREAD_COND_INITIALIZER;
|
|
||||||
extern int music_player_init(char *dev);
|
extern int music_player_init(char *dev);
|
||||||
extern int music_player_start();
|
extern int music_player_start();
|
||||||
extern bool music_is_playing(void);
|
extern void play_manager_f(const char *cmd, const char *data, char **user_data);
|
||||||
extern void play_manager_f(const char *cmd, const char *data);
|
|
||||||
void handle_doa_result(int doa);
|
void handle_doa_result(int doa);
|
||||||
|
static send_tts_update_topic ();
|
||||||
|
|
||||||
#define WAIT_WAKEUP_SYSTEM_CMD "./aispeech_led -m on 4"
|
#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 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 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 RUNNING_TTS_SYSTEM_CMD "./aispeech_led -m on -b 2 2"
|
||||||
#define DISABLE_WAKEUP_SYSTEM_CMD "./aispeech_led -m on -b 2 1"
|
#define DISABLE_WAKEUP_SYSTEM_CMD "./aispeech_led -m on -b 2 1"
|
||||||
|
#include <stdbool.h>
|
||||||
|
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 led_off() {
|
void led_off() {
|
||||||
printf("%s\n", __func__);
|
printf("%s\n", __func__);
|
||||||
system("./aispeech_led -m on 4");
|
system("./aispeech_led -m on 4");
|
||||||
@ -64,8 +67,8 @@ void do_system_sleep() {
|
|||||||
void dds_cb(const char *topic, const char *topic_data, void *user) {
|
void dds_cb(const char *topic, const char *topic_data, void *user) {
|
||||||
static int end_dialog = 0;
|
static int end_dialog = 0;
|
||||||
|
|
||||||
printf("####### dds cb receive topic: %s\n", topic);
|
printf("dds cb receive topic: %s\n", topic);
|
||||||
printf("####### dds cb receive topic_data: %s\n", topic_data);
|
printf("dds cb receive topic_data: %s\n", topic_data);
|
||||||
|
|
||||||
if (!strcmp(topic, "dm.output")) {
|
if (!strcmp(topic, "dm.output")) {
|
||||||
cJSON *root = cJSON_Parse(topic_data);
|
cJSON *root = cJSON_Parse(topic_data);
|
||||||
@ -77,7 +80,7 @@ void dds_cb(const char *topic, const char *topic_data, void *user) {
|
|||||||
cJSON *count = cJSON_GetObjectItem(widget, "count");
|
cJSON *count = cJSON_GetObjectItem(widget, "count");
|
||||||
if (count && count->valueint > 0) {
|
if (count && count->valueint > 0) {
|
||||||
char *out = cJSON_PrintUnformatted(widget);
|
char *out = cJSON_PrintUnformatted(widget);
|
||||||
play_manager_f("play.list.update", out);
|
play_manager_f("play.list.update", out, NULL);
|
||||||
free(out);
|
free(out);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -91,7 +94,6 @@ void dds_cb(const char *topic, const char *topic_data, void *user) {
|
|||||||
system(WAIT_WAKEUP_SYSTEM_CMD);
|
system(WAIT_WAKEUP_SYSTEM_CMD);
|
||||||
clean_silence_frame();
|
clean_silence_frame();
|
||||||
m_is_dialog = false;
|
m_is_dialog = false;
|
||||||
printf("dm.output close dialog\n");
|
|
||||||
cJSON_Delete(root);
|
cJSON_Delete(root);
|
||||||
}
|
}
|
||||||
else if (!strcmp(topic, "doa.result")) {
|
else if (!strcmp(topic, "doa.result")) {
|
||||||
@ -104,62 +106,100 @@ void dds_cb(const char *topic, const char *topic_data, void *user) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
else if (!strcmp(topic, "command://spk.speaker.close")) {
|
else if (!strcmp(topic, "command://spk.speaker.close")) {
|
||||||
play_manager_f("play.list.clear", NULL);
|
play_manager_f("play.list.clear", NULL, NULL);
|
||||||
dds_client_resp_nativeapi(dc, topic, "{\"duiWidget\":\"text\", \"extra\":{\"APICommandResult\":\"success\"}}");
|
dds_client_resp_nativeapi(dc, topic, "{\"duiWidget\":\"text\", \"extra\":{\"APICommandResult\":\"success\"}}");
|
||||||
}
|
}
|
||||||
else if (!strcmp(topic, "native://mediacontrol.media.single")) {
|
else if (!strcmp(topic, "native://mediacontrol.media.single")) {
|
||||||
play_manager_f("mode.set", "single");
|
play_manager_f("mode.set", "single", NULL);
|
||||||
dds_client_resp_nativeapi(dc, topic, "{\"duiWidget\":\"text\", \"extra\":{\"APICommandResult\":\"success\"}}");
|
dds_client_resp_nativeapi(dc, topic, "{\"duiWidget\":\"text\", \"extra\":{\"APICommandResult\":\"success\"}}");
|
||||||
}
|
}
|
||||||
else if (!strcmp(topic, "native://mediacontrol.media.sequence")) {
|
else if (!strcmp(topic, "native://mediacontrol.media.sequence")) {
|
||||||
play_manager_f("mode.set", "sequence");
|
play_manager_f("mode.set", "sequence", NULL);
|
||||||
dds_client_resp_nativeapi(dc, topic, "{\"duiWidget\":\"text\", \"extra\":{\"APICommandResult\":\"success\"}}");
|
dds_client_resp_nativeapi(dc, topic, "{\"duiWidget\":\"text\", \"extra\":{\"APICommandResult\":\"success\"}}");
|
||||||
}
|
}
|
||||||
else if (!strcmp(topic, "native://mediacontrol.media.random")) {
|
else if (!strcmp(topic, "native://mediacontrol.media.random")) {
|
||||||
play_manager_f("mode.set", "random");
|
play_manager_f("mode.set", "random", NULL);
|
||||||
dds_client_resp_nativeapi(dc, topic, "{\"duiWidget\":\"text\", \"extra\":{\"APICommandResult\":\"success\"}}");
|
dds_client_resp_nativeapi(dc, topic, "{\"duiWidget\":\"text\", \"extra\":{\"APICommandResult\":\"success\"}}");
|
||||||
}
|
}
|
||||||
else if (!strcmp(topic, "native://mediacontrol.media.loop")) {
|
else if (!strcmp(topic, "native://mediacontrol.media.loop")) {
|
||||||
play_manager_f("mode.set", "loop");
|
play_manager_f("mode.set", "loop", NULL);
|
||||||
dds_client_resp_nativeapi(dc, topic, "{\"duiWidget\":\"text\", \"extra\":{\"APICommandResult\":\"success\"}}");
|
dds_client_resp_nativeapi(dc, topic, "{\"duiWidget\":\"text\", \"extra\":{\"APICommandResult\":\"success\"}}");
|
||||||
}
|
}
|
||||||
else if (!strcmp(topic, "native://mediacontrol.media.pause")) {
|
else if (!strcmp(topic, "native://mediacontrol.media.pause")) {
|
||||||
play_manager_f("status.set", "pause");
|
play_manager_f("status.set", "pause", NULL);
|
||||||
dds_client_resp_nativeapi(dc, topic, "{\"duiWidget\":\"text\", \"extra\":{\"APICommandResult\":\"success\"}}");
|
dds_client_resp_nativeapi(dc, topic, "{\"duiWidget\":\"text\", \"extra\":{\"APICommandResult\":\"success\"}}");
|
||||||
}
|
}
|
||||||
else if (!strcmp(topic, "native://mediacontrol.media.continue")) {
|
else if (!strcmp(topic, "native://mediacontrol.media.continue")) {
|
||||||
play_manager_f("status.set", "resume");
|
play_manager_f("status.set", "resume", NULL);
|
||||||
dds_client_resp_nativeapi(dc, topic, "{\"duiWidget\":\"text\", \"extra\":{\"APICommandResult\":\"success\"}}");
|
dds_client_resp_nativeapi(dc, topic, "{\"duiWidget\":\"text\", \"extra\":{\"APICommandResult\":\"success\"}}");
|
||||||
}
|
}
|
||||||
else if (!strcmp(topic, "native://mediacontrol.media.stop")) {
|
else if (!strcmp(topic, "native://mediacontrol.media.stop")) {
|
||||||
play_manager_f("play.list.clear", NULL);
|
play_manager_f("play.list.clear", NULL, NULL);
|
||||||
dds_client_resp_nativeapi(dc, topic, "{\"duiWidget\":\"text\", \"extra\":{\"APICommandResult\":\"success\"}}");
|
dds_client_resp_nativeapi(dc, topic, "{\"duiWidget\":\"text\", \"extra\":{\"APICommandResult\":\"success\"}}");
|
||||||
}
|
}
|
||||||
else if (!strcmp(topic, "native://mediacontrol.media.replay")) {
|
else if (!strcmp(topic, "native://mediacontrol.media.replay")) {
|
||||||
play_manager_f("status.set", "replay");
|
play_manager_f("status.set", "replay", NULL);
|
||||||
dds_client_resp_nativeapi(dc, topic, "{\"duiWidget\":\"text\", \"extra\":{\"APICommandResult\":\"success\"}}");
|
dds_client_resp_nativeapi(dc, topic, "{\"duiWidget\":\"text\", \"extra\":{\"APICommandResult\":\"success\"}}");
|
||||||
}
|
}
|
||||||
else if (!strcmp(topic, "native://mediacontrol.media.prev")) {
|
else if (!strcmp(topic, "native://mediacontrol.media.prev")) {
|
||||||
play_manager_f("change.set", "prev");
|
play_manager_f("change.set", "prev", NULL);
|
||||||
dds_client_resp_nativeapi(dc, topic, "{\"duiWidget\":\"text\", \"extra\":{\"count\":\"more\", \"skillName\":\"speakerChinaPlay\", \"title\":\"\"}}");
|
dds_client_resp_nativeapi(dc, topic, "{\"duiWidget\":\"text\", \"extra\":{\"count\":\"more\", \"skillName\":\"speakerChinaPlay\", \"title\":\"\"}}");
|
||||||
}
|
}
|
||||||
else if (!strcmp(topic, "native://mediacontrol.media.next")) {
|
else if (!strcmp(topic, "native://mediacontrol.media.next")) {
|
||||||
play_manager_f("change.set", "next");
|
play_manager_f("change.set", "next", NULL);
|
||||||
dds_client_resp_nativeapi(dc, topic, "{\"duiWidget\":\"text\", \"extra\":{\"count\":\"more\", \"skillName\":\"speakerChinaPlay\", \"title\":\"\"}}");
|
dds_client_resp_nativeapi(dc, topic, "{\"duiWidget\":\"text\", \"extra\":{\"count\":\"more\", \"skillName\":\"speakerChinaPlay\", \"title\":\"\"}}");
|
||||||
}
|
}
|
||||||
else if (!strcmp(topic, "native://mediacontrol.media.change")) {
|
else if (!strcmp(topic, "native://mediacontrol.media.change")) {
|
||||||
play_manager_f("change.set", "change");
|
play_manager_f("change.set", "change", NULL);
|
||||||
dds_client_resp_nativeapi(dc, topic, "{\"duiWidget\":\"text\", \"extra\":{\"count\":\"more\", \"skillName\":\"speakerChinaPlay\", \"title\":\"\"}}");
|
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")) {
|
else if (!strcmp(topic, "command://spk.speaker.voice")) {
|
||||||
cJSON *root = cJSON_Parse(topic_data);
|
cJSON *root = cJSON_Parse(topic_data);
|
||||||
cJSON *voice = cJSON_GetObjectItem(root, "voice");
|
cJSON *voice = cJSON_GetObjectItem(root, "voice");
|
||||||
if (voice) {
|
if (voice) {
|
||||||
play_manager_f("volume.set", voice->valuestring);
|
play_manager_f("volume.set", voice->valuestring, NULL);
|
||||||
}
|
}
|
||||||
play_manager_f("status.set", "resume");
|
play_manager_f("status.set", "resume", NULL);
|
||||||
|
// speak
|
||||||
|
music_player_play("../res/tts/vol.mp3");
|
||||||
cJSON_Delete(root);
|
cJSON_Delete(root);
|
||||||
}
|
}
|
||||||
|
|
||||||
else if (!strcmp(topic, "native://alarm.set")) {
|
else if (!strcmp(topic, "native://alarm.set")) {
|
||||||
dds_client_resp_nativeapi(dc, topic, "{\"duiWidget\":\"text\", \"extra\":{\"text\":\"已为您设置闹钟\"}}");
|
dds_client_resp_nativeapi(dc, topic, "{\"duiWidget\":\"text\", \"extra\":{\"text\":\"已为您设置闹钟\"}}");
|
||||||
}
|
}
|
||||||
@ -188,18 +228,17 @@ void dds_cb(const char *topic, const char *topic_data, void *user) {
|
|||||||
|
|
||||||
else if (!strcmp(topic, "local_wakeup.result")) {
|
else if (!strcmp(topic, "local_wakeup.result")) {
|
||||||
end_dialog = 0;
|
end_dialog = 0;
|
||||||
play_manager_f("status.set", "pause");
|
play_manager_f("status.set", "pause", NULL);
|
||||||
}
|
}
|
||||||
else if (!strcmp(topic, "sys.dm.end")) {
|
else if (!strcmp(topic, "sys.dm.end")) {
|
||||||
// 对话退出
|
// 对话退出
|
||||||
play_manager_f("play.list.check", NULL);
|
play_manager_f("play.list.check", NULL, NULL);
|
||||||
system(WAIT_WAKEUP_SYSTEM_CMD);
|
system(WAIT_WAKEUP_SYSTEM_CMD);
|
||||||
clean_silence_frame();
|
clean_silence_frame();
|
||||||
m_is_dialog = false;
|
m_is_dialog = false;
|
||||||
if (!is_enable_wakeup) {
|
if (!is_enable_wakeup) {
|
||||||
system(DISABLE_WAKEUP_SYSTEM_CMD);
|
system(DISABLE_WAKEUP_SYSTEM_CMD);
|
||||||
}
|
}
|
||||||
printf("sys.dm.end out \n");
|
|
||||||
}
|
}
|
||||||
else if (!strcmp(topic, "sys.tts.begin")) {
|
else if (!strcmp(topic, "sys.tts.begin")) {
|
||||||
clean_silence_frame();
|
clean_silence_frame();
|
||||||
@ -220,6 +259,12 @@ void dds_cb(const char *topic, const char *topic_data, void *user) {
|
|||||||
|
|
||||||
void handle_doa_result(int doa) {
|
void handle_doa_result(int doa) {
|
||||||
printf("handle_doa_result doa is %d\n", 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] = {
|
static char *doa_led_table[12] = {
|
||||||
"./aispeech_led -m single -i 2 0",
|
"./aispeech_led -m single -i 2 0",
|
||||||
"./aispeech_led -m single -i 3 0",
|
"./aispeech_led -m single -i 3 0",
|
||||||
@ -235,6 +280,23 @@ void handle_doa_result(int doa) {
|
|||||||
"./aispeech_led -m single -i 1 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 >= 0) {
|
||||||
if (doa >=345 || doa < 15) {
|
if (doa >=345 || doa < 15) {
|
||||||
system(doa_led_table[0]);
|
system(doa_led_table[0]);
|
||||||
@ -284,26 +346,27 @@ void button_cb(button_event_t ev, void *userdata) {
|
|||||||
|
|
||||||
if (ev == BUTTON_EVENT_VOLUME_ADD) {
|
if (ev == BUTTON_EVENT_VOLUME_ADD) {
|
||||||
//短按触发
|
//短按触发
|
||||||
play_manager_f("volume.set", "+");
|
play_manager_f("volume.set", "+", NULL);
|
||||||
}
|
}
|
||||||
else if (ev == BUTTON_EVENT_VOLUME_SUB) {
|
else if (ev == BUTTON_EVENT_VOLUME_SUB) {
|
||||||
//短按触发
|
//短按触发
|
||||||
play_manager_f("volume.set", "-");
|
play_manager_f("volume.set", "-", NULL);
|
||||||
}
|
}
|
||||||
else if (ev == BUTTON_EVENT_PREV) {
|
else if (ev == BUTTON_EVENT_PREV) {
|
||||||
//长按每隔1.5秒触发一次
|
//长按每隔1.5秒触发一次
|
||||||
play_manager_f("change.set", "prev");
|
play_manager_f("change.set", "prev", NULL);
|
||||||
play_manager_f("play.list.check", NULL);
|
play_manager_f("play.list.check", NULL, NULL);
|
||||||
}
|
}
|
||||||
else if (ev == BUTTON_EVENT_NEXT) {
|
else if (ev == BUTTON_EVENT_NEXT) {
|
||||||
//长按每隔1.5秒触发一次
|
//长按每隔1.5秒触发一次
|
||||||
play_manager_f("change.set", "next");
|
play_manager_f("change.set", "next", NULL);
|
||||||
play_manager_f("play.list.check", NULL);
|
play_manager_f("play.list.check", NULL, NULL);
|
||||||
}
|
}
|
||||||
else if (ev == BUTTON_EVENT_PLAY_PAUSE) {
|
else if (ev == BUTTON_EVENT_PLAY_PAUSE) {
|
||||||
//短按触发
|
//短按触发
|
||||||
play_manager_f("status.set", "step");
|
play_manager_f("status.set", "step", NULL);
|
||||||
} else if (ev == BUTTON_EVENT_MUTE_UNMUTE) {
|
}
|
||||||
|
else if (ev == BUTTON_EVENT_MUTE_UNMUTE) {
|
||||||
// mute
|
// mute
|
||||||
if (is_enable_wakeup) {
|
if (is_enable_wakeup) {
|
||||||
is_enable_wakeup = 0;
|
is_enable_wakeup = 0;
|
||||||
@ -319,6 +382,132 @@ void button_cb(button_event_t ev, void *userdata) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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) {
|
void *button_routine(void *user) {
|
||||||
button_config_t config = {
|
button_config_t config = {
|
||||||
.dev = "/dev/input/event0", // v11: event0 | v10: event1
|
.dev = "/dev/input/event0", // v11: event0 | v10: event1
|
||||||
@ -332,6 +521,10 @@ void *button_routine(void *user) {
|
|||||||
return (void *)0;
|
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
|
const unsigned int voice_inactive_max_count = 16000 * 5; //16k, 3 seconds
|
||||||
unsigned int read_voice_inactive_frames(void)
|
unsigned int read_voice_inactive_frames(void)
|
||||||
{
|
{
|
||||||
@ -407,7 +600,6 @@ void *vad_detect_func(void* arg) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
int main () {
|
int main () {
|
||||||
int ret;
|
int ret;
|
||||||
char config[1024 * 5];
|
char config[1024 * 5];
|
||||||
@ -432,6 +624,11 @@ int main () {
|
|||||||
// 2. start the music player
|
// 2. start the music player
|
||||||
music_player_start();
|
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
|
// 3. run the dds client
|
||||||
dc = dds_client_init(config);
|
dc = dds_client_init(config);
|
||||||
assert(dc != NULL);
|
assert(dc != NULL);
|
||||||
@ -445,15 +642,29 @@ int main () {
|
|||||||
|
|
||||||
// 5. system init
|
// 5. system init
|
||||||
system("amixer cset name='Master Playback Volume' 70");
|
system("amixer cset name='Master Playback Volume' 70");
|
||||||
system("alsaucm -c rockchiprk3308v");
|
|
||||||
system("chmod +x aispeech_led");
|
system("chmod +x aispeech_led");
|
||||||
|
|
||||||
|
|
||||||
pthread_t softvad_detect;
|
pthread_t softvad_detect;
|
||||||
pthread_create(&softvad_detect,NULL,vad_detect_func,NULL);
|
pthread_create(&softvad_detect,NULL,vad_detect_func,NULL);
|
||||||
|
|
||||||
led_off();//led init
|
led_off();//led init
|
||||||
|
|
||||||
|
#ifdef PDM_MIC
|
||||||
|
system("amixer -c 0 cset name='ADC ALC Group 0 Left Volume' 20");
|
||||||
|
system("amixer -c 0 cset name='ADC ALC Group 0 Right Volume' 20");
|
||||||
|
#else
|
||||||
|
system("amixer -c 0 cset name='ADC ALC Group 0 Left Volume' 28");
|
||||||
|
system("amixer -c 0 cset name='ADC ALC Group 0 Right Volume' 28");
|
||||||
|
system("amixer -c 0 cset name='ADC ALC Group 1 Left Volume' 28");
|
||||||
|
system("amixer -c 0 cset name='ADC ALC Group 1 Right Volume' 28");
|
||||||
|
system("amixer -c 0 cset name='ADC ALC Group 2 Left Volume' 28");
|
||||||
|
system("amixer -c 0 cset name='ADC ALC Group 2 Right Volume' 28");
|
||||||
|
system("amixer -c 0 cset name='ADC ALC Group 3 Left Volume' 18");
|
||||||
|
system("amixer -c 0 cset name='ADC ALC Group 3 Right Volume' 18");
|
||||||
|
#endif
|
||||||
|
|
||||||
|
send_tts_update_topic();
|
||||||
|
|
||||||
select(0, 0, 0, 0, 0);
|
select(0, 0, 0, 0, 0);
|
||||||
|
|
||||||
dds_client_release(dc);
|
dds_client_release(dc);
|
||||||
|
|||||||
Binary file not shown.
@ -1,5 +1,5 @@
|
|||||||
/*================================================================
|
/*================================================================
|
||||||
* Copyright (C) 2018 FREEDOM Ltd. All rights reserved.
|
* Copyright (C) 2018 AISPEECH Ltd. All rights reserved.
|
||||||
*
|
*
|
||||||
* 文件名称:music.c
|
* 文件名称:music.c
|
||||||
* 创 建 者:chenjie.gu
|
* 创 建 者:chenjie.gu
|
||||||
@ -20,13 +20,14 @@
|
|||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
|
|
||||||
audio_player_t *aplayer = NULL;
|
audio_player_t *aplayer = NULL;
|
||||||
float vol_multiplier = 0.4;
|
float vol_multiplier = 0.5;
|
||||||
|
int vol_system = 70;
|
||||||
int player_is_end = 0;
|
int player_is_end = 0;
|
||||||
pthread_mutex_t music_mutex;
|
pthread_mutex_t music_mutex;
|
||||||
|
|
||||||
int play_judge_f(int index, int count, int mode);
|
int play_judge_f(int index, int count, int mode);
|
||||||
void play_manager_f(const char *cmd, const char *data);
|
|
||||||
|
|
||||||
|
void play_manager_f(const char *cmd, const char *data, char **user_data);
|
||||||
static int g_player_ev = AUDIO_PLAYER_EV_END;
|
static int g_player_ev = AUDIO_PLAYER_EV_END;
|
||||||
|
|
||||||
bool music_is_playing(void) {
|
bool music_is_playing(void) {
|
||||||
@ -52,7 +53,7 @@ void *player_routine(void *user) {
|
|||||||
while (1) {
|
while (1) {
|
||||||
if (player_is_end) {
|
if (player_is_end) {
|
||||||
player_is_end = 0;
|
player_is_end = 0;
|
||||||
play_manager_f("player.end", NULL);
|
play_manager_f("player.end", NULL, NULL);
|
||||||
}
|
}
|
||||||
usleep(100 * 1000);
|
usleep(100 * 1000);
|
||||||
}
|
}
|
||||||
@ -60,9 +61,11 @@ void *player_routine(void *user) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
int music_player_init(char *dev) {
|
int music_player_init(char *dev) {
|
||||||
aplayer = audio_player_new(dev, play_callback, NULL);
|
aplayer = audio_player_new(play_callback, NULL);
|
||||||
|
audio_player_set_device(aplayer, dev);
|
||||||
audio_player_set_channel_volume(aplayer, vol_multiplier);
|
audio_player_set_channel_volume(aplayer, vol_multiplier);
|
||||||
pthread_mutex_init(&music_mutex, NULL);
|
pthread_mutex_init(&music_mutex, NULL);
|
||||||
|
system("amixer cset name='Master Playback Volume' 70");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -78,7 +81,45 @@ int music_player_start() {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void play_manager_f(const char *cmd, const char *data) {
|
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
|
* 1. volume.set
|
||||||
@ -92,6 +133,7 @@ void play_manager_f(const char *cmd, const char *data) {
|
|||||||
* 9. play.collect.choose
|
* 9. play.collect.choose
|
||||||
* 10. play.uncollect.choose
|
* 10. play.uncollect.choose
|
||||||
* 11. player.end
|
* 11. player.end
|
||||||
|
* 12. music.info
|
||||||
*/
|
*/
|
||||||
|
|
||||||
enum PLAY_MODE {
|
enum PLAY_MODE {
|
||||||
@ -99,7 +141,7 @@ void play_manager_f(const char *cmd, const char *data) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
enum PLAY_STATUS {
|
enum PLAY_STATUS {
|
||||||
idle, pause, playing
|
idle, playing, pause
|
||||||
};
|
};
|
||||||
|
|
||||||
static enum PLAY_MODE mode = sequence;
|
static enum PLAY_MODE mode = sequence;
|
||||||
@ -116,30 +158,23 @@ void play_manager_f(const char *cmd, const char *data) {
|
|||||||
if (!strcmp(cmd, "volume.set")) {
|
if (!strcmp(cmd, "volume.set")) {
|
||||||
// 设置音量
|
// 设置音量
|
||||||
if (!strcmp(data, "+")) {
|
if (!strcmp(data, "+")) {
|
||||||
vol_multiplier += 0.05;
|
vol_system += 10;
|
||||||
if (vol_multiplier > 1.0) vol_multiplier = 0.99;
|
if (vol_system > 100) vol_system = 100;
|
||||||
audio_player_set_channel_volume(aplayer, vol_multiplier);
|
|
||||||
|
|
||||||
printf("set vol_multiplier to %f\n", vol_multiplier);
|
|
||||||
printf("set vol to %d\n", (int)(vol_multiplier * 100.0));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
else if (!strcmp(data, "-")) {
|
else if (!strcmp(data, "-")) {
|
||||||
vol_multiplier -= 0.05;
|
vol_system -= 10;
|
||||||
if (vol_multiplier < 0.01) vol_multiplier = 0.01;
|
if (vol_system < 0) vol_system = 0;
|
||||||
|
|
||||||
audio_player_set_channel_volume(aplayer, vol_multiplier);
|
|
||||||
printf("set vol_multiplier to %f\n", vol_multiplier);
|
|
||||||
printf("set vol to %d\n", (int)(vol_multiplier * 100.0));
|
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
int vol = atoi(data);
|
vol_system = atoi(data);
|
||||||
vol_multiplier = vol / 100.0;
|
|
||||||
|
|
||||||
audio_player_set_channel_volume(aplayer, vol_multiplier);
|
|
||||||
printf("set vol_multiplier to %f\n", vol_multiplier);
|
|
||||||
printf("set vol to %d\n", (int)(vol_multiplier * 100.0));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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")) {
|
else if (!strcmp(cmd, "play.list.clear")) {
|
||||||
@ -152,10 +187,20 @@ void play_manager_f(const char *cmd, const char *data) {
|
|||||||
old_index = 0;
|
old_index = 0;
|
||||||
count = 0;
|
count = 0;
|
||||||
status = idle;
|
status = idle;
|
||||||
|
send_music_update_topic(0, status, mode, index, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
else if (!strcmp(cmd, "play.list.get")) {
|
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")) {
|
else if (!strcmp(cmd, "play.list.check")) {
|
||||||
// 开始真正播放
|
// 开始真正播放
|
||||||
cJSON *temp, *music;
|
cJSON *temp, *music;
|
||||||
@ -176,7 +221,9 @@ void play_manager_f(const char *cmd, const char *data) {
|
|||||||
status = playing;
|
status = playing;
|
||||||
audio_player_resume(aplayer);
|
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")) {
|
else if (!strcmp(cmd, "play.list.update")) {
|
||||||
// 更新播放列表
|
// 更新播放列表
|
||||||
@ -204,14 +251,6 @@ void play_manager_f(const char *cmd, const char *data) {
|
|||||||
}
|
}
|
||||||
else if (!strcmp(data, "replay") && status == pause) {
|
else if (!strcmp(data, "replay") && status == pause) {
|
||||||
status = playing;
|
status = playing;
|
||||||
|
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
else if (!strcmp(data, "step")) {
|
else if (!strcmp(data, "step")) {
|
||||||
if (status == playing) {
|
if (status == playing) {
|
||||||
@ -223,6 +262,7 @@ void play_manager_f(const char *cmd, const char *data) {
|
|||||||
audio_player_resume(aplayer);
|
audio_player_resume(aplayer);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
send_music_update_topic(0, status, mode, index, root);
|
||||||
}
|
}
|
||||||
else if (!strcmp(cmd, "mode.set")) {
|
else if (!strcmp(cmd, "mode.set")) {
|
||||||
// 播放模式
|
// 播放模式
|
||||||
@ -230,6 +270,7 @@ void play_manager_f(const char *cmd, const char *data) {
|
|||||||
else if (!strcmp(data, "random")) mode = random;
|
else if (!strcmp(data, "random")) mode = random;
|
||||||
else if (!strcmp(data, "single")) mode = single;
|
else if (!strcmp(data, "single")) mode = single;
|
||||||
else if (!strcmp(data, "loop")) mode = loop;
|
else if (!strcmp(data, "loop")) mode = loop;
|
||||||
|
send_music_update_topic(0, status, mode, index, root);
|
||||||
}
|
}
|
||||||
else if (!strcmp(cmd, "change.set")) {
|
else if (!strcmp(cmd, "change.set")) {
|
||||||
// 歌曲切换
|
// 歌曲切换
|
||||||
@ -266,33 +307,16 @@ void play_manager_f(const char *cmd, const char *data) {
|
|||||||
}
|
}
|
||||||
else if (!strcmp(cmd, "play.choose.update")) {
|
else if (!strcmp(cmd, "play.choose.update")) {
|
||||||
// 播放特定歌曲
|
// 播放特定歌曲
|
||||||
// TODO: update
|
|
||||||
int find = 0;
|
|
||||||
int i = 0;
|
|
||||||
cJSON *temp = cJSON_Parse(data);
|
|
||||||
temp = cJSON_GetObjectItem(temp, "linkUrl");
|
|
||||||
|
|
||||||
cJSON *music = cJSON_GetObjectItem(root, "content");
|
|
||||||
cJSON *xx;
|
|
||||||
for (i = 0; i < count; i++) {
|
|
||||||
xx = cJSON_GetArrayItem(music, i);
|
|
||||||
xx = cJSON_GetObjectItem(xx, "linkUrl");
|
|
||||||
if (!strcmp(xx->valuestring, temp->valuestring)) {
|
|
||||||
find = 1;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (find) {
|
|
||||||
old_index = index;
|
old_index = index;
|
||||||
index = i;
|
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);
|
printf("ready to play url is %s\n", temp->valuestring);
|
||||||
audio_player_stop(aplayer);
|
audio_player_stop(aplayer);
|
||||||
audio_player_play(aplayer, temp->valuestring);
|
audio_player_play(aplayer, temp->valuestring);
|
||||||
}
|
send_music_update_topic(0, status, mode, index, root);
|
||||||
else {
|
|
||||||
// 播放歌曲不在播放列表里面
|
|
||||||
printf("wwwwwwwwwwwwwwwwwwwwwwwwwww\n");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else if (!strcmp(cmd, "play.collect.choose")) {
|
else if (!strcmp(cmd, "play.collect.choose")) {
|
||||||
// 收藏歌曲
|
// 收藏歌曲
|
||||||
@ -317,6 +341,7 @@ void play_manager_f(const char *cmd, const char *data) {
|
|||||||
old_index = 0;
|
old_index = 0;
|
||||||
count = 0;
|
count = 0;
|
||||||
status = idle;
|
status = idle;
|
||||||
|
send_music_update_topic(0, status, mode, index, NULL);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
// 播放指定的音频
|
// 播放指定的音频
|
||||||
@ -327,6 +352,7 @@ void play_manager_f(const char *cmd, const char *data) {
|
|||||||
printf("ready to play url is %s\n", temp->valuestring);
|
printf("ready to play url is %s\n", temp->valuestring);
|
||||||
audio_player_stop(aplayer);
|
audio_player_stop(aplayer);
|
||||||
audio_player_play(aplayer, temp->valuestring);
|
audio_player_play(aplayer, temp->valuestring);
|
||||||
|
send_music_update_topic(0, status, mode, index, root);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Binary file not shown.
BIN
rk3308/aispeech/dds_client/demo/说法示例.pdf
Executable file
BIN
rk3308/aispeech/dds_client/demo/说法示例.pdf
Executable file
Binary file not shown.
@ -47,6 +47,8 @@ void dds_client_release(struct dds_client *ds);
|
|||||||
|
|
||||||
```
|
```
|
||||||
|
|
||||||
|
**下面的接口必须在 `dds_client_init ` 和 `dds_client_start` 正确返回之后才能正确执行。**
|
||||||
|
|
||||||
```
|
```
|
||||||
向 sdk 内部发送消息:
|
向 sdk 内部发送消息:
|
||||||
|
|
||||||
@ -140,7 +142,7 @@ text: 需要合成的文本
|
|||||||
```
|
```
|
||||||
|
|
||||||
```
|
```
|
||||||
关闭唤醒,此接口会终止当前的对话。
|
关闭唤醒,如果在语音对话过程中调用此接口,会在这条对话自然结束之后才会禁止唤醒。
|
||||||
|
|
||||||
int dds_client_disable_wakeup(struct dds_client *ds);
|
int dds_client_disable_wakeup(struct dds_client *ds);
|
||||||
|
|
||||||
@ -165,6 +167,73 @@ ds: sdk 实例指针
|
|||||||
|
|
||||||
```
|
```
|
||||||
|
|
||||||
|
```
|
||||||
|
设置用户唤醒词
|
||||||
|
|
||||||
|
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
|
// 获取当前的 tts 发音人,出错返回 NULL
|
||||||
@ -187,7 +256,6 @@ int dds_client_set_volume(struct dds_client *ds, int vol);
|
|||||||
|
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
**sdk回调消息接口**
|
**sdk回调消息接口**
|
||||||
|
|
||||||
<table>
|
<table>
|
||||||
@ -285,6 +353,13 @@ int dds_client_set_volume(struct dds_client *ds, int vol);
|
|||||||
<td> json string "{"result":"success"}"</td>
|
<td> json string "{"result":"success"}"</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
|
||||||
|
<tr>
|
||||||
|
<td> ddsLintener </td>
|
||||||
|
<td> sys.client.error </td>
|
||||||
|
<td> 表示客户端出现异常情况 </td>
|
||||||
|
<td> json string "{"error":"ttsError"}" 目前 error 字段的取值一共有: ttsError, ddsNetworkError, vadSlienceTimeout</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
<tr>
|
<tr>
|
||||||
<td> ddsLintener </td>
|
<td> ddsLintener </td>
|
||||||
<td> command://xx </td>
|
<td> command://xx </td>
|
||||||
@ -306,6 +381,9 @@ int dds_client_set_volume(struct dds_client *ds, int vol);
|
|||||||
```
|
```
|
||||||
|
|
||||||
{
|
{
|
||||||
|
"sdk": {
|
||||||
|
"configPath":"./config.json"
|
||||||
|
},
|
||||||
"auth": {
|
"auth": {
|
||||||
"productId": "278569448",
|
"productId": "278569448",
|
||||||
"deviceProfile": ""
|
"deviceProfile": ""
|
||||||
@ -337,6 +415,10 @@ int dds_client_set_volume(struct dds_client *ds, int vol);
|
|||||||
},
|
},
|
||||||
"tts": {
|
"tts": {
|
||||||
"type": "cloud",
|
"type": "cloud",
|
||||||
|
"zhilingf": {
|
||||||
|
"resBinPath":"",
|
||||||
|
"dictPath":""
|
||||||
|
},
|
||||||
"voice": "zhilingf",
|
"voice": "zhilingf",
|
||||||
"volume": 50,
|
"volume": 50,
|
||||||
"speed": 0.85
|
"speed": 0.85
|
||||||
@ -346,18 +428,26 @@ int dds_client_set_volume(struct dds_client *ds, int vol);
|
|||||||
},
|
},
|
||||||
"wakeup": {
|
"wakeup": {
|
||||||
"majorword": [{
|
"majorword": [{
|
||||||
"greetingFile":"path:./res/tts/help.mp3",
|
|
||||||
"greeting": "我在,有什么可以帮你",
|
|
||||||
"pinyin": "ni hao xiao chi",
|
|
||||||
"name": "你好小驰",
|
|
||||||
"threshold": 0.127
|
|
||||||
}, {
|
|
||||||
"greetingFile":"path:./res/tts/help.mp3",
|
"greetingFile":"path:./res/tts/help.mp3",
|
||||||
"greeting": "我在,有什么可以帮你",
|
"greeting": "我在,有什么可以帮你",
|
||||||
"pinyin": "ni hao xiao le",
|
"pinyin": "ni hao xiao le",
|
||||||
"name": "你好小乐",
|
"name": "你好小乐",
|
||||||
"threshold": 0.144
|
"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": [{
|
"cmdword": [{
|
||||||
"pinyin": "jiang di yin liang",
|
"pinyin": "jiang di yin liang",
|
||||||
"threshold": 0.100,
|
"threshold": 0.100,
|
||||||
@ -366,7 +456,12 @@ int dds_client_set_volume(struct dds_client *ds, int vol);
|
|||||||
}]
|
}]
|
||||||
},
|
},
|
||||||
"abnormal": {
|
"abnormal": {
|
||||||
"netErrorHint":"path:../res/tts/net.mp3"
|
"netErrorHint":"path:../res/tts/net.mp3",
|
||||||
|
"ttsErrorHint":"path:../res/tts/tts_error.mp3"
|
||||||
|
},
|
||||||
|
"debug": {
|
||||||
|
"recAudioDumpFile":"",
|
||||||
|
"bfAudioDumpFile":""
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
@ -379,6 +474,20 @@ int dds_client_set_volume(struct dds_client *ds, int vol);
|
|||||||
<th>是否必须</th>
|
<th>是否必须</th>
|
||||||
</tr>
|
</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>
|
<tr>
|
||||||
<td> auth </td>
|
<td> auth </td>
|
||||||
<td> json 对象 </td>
|
<td> json 对象 </td>
|
||||||
@ -544,14 +653,34 @@ int dds_client_set_volume(struct dds_client *ds, int vol);
|
|||||||
<tr>
|
<tr>
|
||||||
<td> tts.type </td>
|
<td> tts.type </td>
|
||||||
<td>string </td>
|
<td>string </td>
|
||||||
<td>合成音的类型,当前仅支持 "cloud" </td>
|
<td>合成音的类型,支持 "cloud" | "local" 分别表示云端合成和本地合成</td>
|
||||||
|
<td>必选</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td> tts.voice </td>
|
||||||
|
<td>string </td>
|
||||||
|
<td>合成音的音色,如果为本地合成, 仅支持 "zhilingf" </td>
|
||||||
<td>必选</td>
|
<td>必选</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
|
||||||
<tr>
|
<tr>
|
||||||
<td> tts.voice </td>
|
<td> tts.zhilingf </td>
|
||||||
<td>string </td>
|
<td> json 对象 </td>
|
||||||
<td>合成音的音色 </td>
|
<td>当 tts.type 为 "local"时,会根据 tts.voice 选择对应音色的合成资源路径。</td>
|
||||||
|
<td>可选</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
<tr>
|
||||||
|
<td> tts.zhilingf.resBinPath </td>
|
||||||
|
<td> string </td>
|
||||||
|
<td>本地合成 zhilingf 的资源路径</td>
|
||||||
|
<td>可选</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
<tr>
|
||||||
|
<td> tts.zhilingf.dictPath </td>
|
||||||
|
<td> string </td>
|
||||||
|
<td>本地合成 zhilingf 的词典路径</td>
|
||||||
<td>可选</td>
|
<td>可选</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
|
||||||
@ -593,15 +722,30 @@ int dds_client_set_volume(struct dds_client *ds, int vol);
|
|||||||
<tr>
|
<tr>
|
||||||
<td> wakeup.majorword </td>
|
<td> wakeup.majorword </td>
|
||||||
<td> json 数组 </td>
|
<td> json 数组 </td>
|
||||||
<td> 唤醒词的相关配置</td>
|
<td> 主唤醒词的相关配置</td>
|
||||||
<td>必选</td>
|
<td>必选</td>
|
||||||
</tr>
|
</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>
|
<tr>
|
||||||
<td> wakeup.cmdword </td>
|
<td> wakeup.cmdword </td>
|
||||||
<td> json 数组 </td>
|
<td> json 数组 </td>
|
||||||
<td> 快捷唤醒词配置 </td>
|
<td> 快捷唤醒词配置 </td>
|
||||||
<td>必选</td>
|
<td>可选</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
|
||||||
<tr>
|
<tr>
|
||||||
@ -618,6 +762,32 @@ int dds_client_set_volume(struct dds_client *ds, int vol);
|
|||||||
<td>可选</td>
|
<td>可选</td>
|
||||||
</tr>
|
</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>
|
</table>
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
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/dds_client/res/tts/tts_error.mp3
Executable file
BIN
rk3308/aispeech/dds_client/res/tts/tts_error.mp3
Executable file
Binary file not shown.
BIN
rk3308/aispeech/dds_client/res/tts/vol.mp3
Executable file
BIN
rk3308/aispeech/dds_client/res/tts/vol.mp3
Executable file
Binary file not shown.
Reference in New Issue
Block a user