1529 lines
44 KiB
C
1529 lines
44 KiB
C
/**
|
|
* Copyright (2017) Baidu Inc. All rights reserved.
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
/**
|
|
* File: lightduer_dcs_router.c
|
|
* Auth: Gang Chen (chengang12@baidu.com)
|
|
* Desc: Light duer dcs directive router.
|
|
*/
|
|
|
|
#include "duerapp_config.h"
|
|
#include "lightduer_dcs_router.h"
|
|
#include "lightduer_dcs.h"
|
|
#include "printf.h"
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include "lightduer_dcs_local.h"
|
|
#include "lightduer_log.h"
|
|
#include "lightduer_memory.h"
|
|
#include "lightduer_connagent.h"
|
|
#include "lightduer_lib.h"
|
|
#include "lightduer_ca.h"
|
|
#include "lightduer_mutex.h"
|
|
#include "lightduer_ds_log_dcs.h"
|
|
#include "lightduer_random.h"
|
|
#include "lightduer_queue_cache.h"
|
|
#ifdef DUER_EVENT_HANDLER
|
|
#include "lightduer_handler.h"
|
|
#else
|
|
#include "lightduer_event_emitter.h"
|
|
#endif // DUER_EVENT_HANDLER
|
|
#include "lightduer_ds_log_e2e.h"
|
|
#include "lightduer_voice.h"
|
|
|
|
typedef struct {
|
|
char *name_space;
|
|
duer_directive_list *list;
|
|
size_t count;
|
|
} directive_namespace_list_t;
|
|
|
|
typedef enum {
|
|
STANDARD_DCS_DIRECTIVE,
|
|
PRIVATE_PROTOCAL_DIRECTIVE,
|
|
} directive_source_t;
|
|
|
|
typedef struct {
|
|
baidu_json *directive;
|
|
int index;
|
|
directive_source_t source;
|
|
} directive_node_t;
|
|
|
|
static volatile size_t s_namespace_count;
|
|
static volatile directive_namespace_list_t *s_directive_namespace_list;
|
|
static volatile size_t s_client_context_cb_count;
|
|
static volatile dcs_client_context_handler *s_dcs_client_context_cb;
|
|
static duer_qcache_handler s_directive_queue;
|
|
static duer_mutex_t s_directive_queue_lock;
|
|
static volatile duer_bool s_wait_dialog_finish;
|
|
static volatile duer_bool s_is_initialized;
|
|
static volatile duer_bool s_is_speak_pending;
|
|
static volatile int s_speaking_index;
|
|
static const char *IOT_CLOUD_EXTRA_KEY = "iot_cloud_extra";
|
|
static const char *INDEX_KEY = "index";
|
|
static const int DUMMY_INDEX = 0;
|
|
static dcs_directive_hook_handler s_dcs_directive_hook_cb = NULL;
|
|
static dcs_event_hook_handler s_dcs_hook_event_handler = NULL;
|
|
static const char *NAMESPACE_DLP = "ai.dueros.device_interface.dlp";
|
|
#define DUER_PRINT_BJSON_ESTIMATED_SIZE_FOR_REPORT_EXCEPTION (1024)
|
|
|
|
static duer_status_t duer_handle_directive(baidu_json *directive,
|
|
int index,
|
|
directive_source_t source);
|
|
|
|
duer_status_t duer_reg_client_context_cb_internal(dcs_client_context_handler cb)
|
|
{
|
|
size_t size = 0;
|
|
duer_status_t ret = DUER_OK;
|
|
dcs_client_context_handler *list = NULL;
|
|
int i = 0;
|
|
|
|
if (!cb) {
|
|
DUER_LOGE("Failed to add client context handler: param error\n");
|
|
DUER_DS_LOG_REPORT_DCS_PARAM_ERROR();
|
|
ret = DUER_ERR_INVALID_PARAMETER;
|
|
return ret;
|
|
}
|
|
|
|
if (s_dcs_client_context_cb) {
|
|
while (i < s_client_context_cb_count) {
|
|
if (s_dcs_client_context_cb[i] == cb) {
|
|
DUER_LOGD("client context cb had been registered");
|
|
return ret;
|
|
}
|
|
i++;
|
|
}
|
|
}
|
|
|
|
if (!s_dcs_client_context_cb) {
|
|
s_dcs_client_context_cb = DUER_MALLOC(sizeof(dcs_client_context_handler));
|
|
if (!s_dcs_client_context_cb) {
|
|
DUER_LOGE("Failed to add dcs client context cb: no memory\n");
|
|
DUER_DS_LOG_REPORT_DCS_MEMORY_ERROR();
|
|
ret = DUER_ERR_MEMORY_OVERFLOW;
|
|
return ret;
|
|
}
|
|
} else {
|
|
size = sizeof(dcs_client_context_handler) * (s_client_context_cb_count + 1);
|
|
list = (dcs_client_context_handler *)DUER_REALLOC((void *)s_dcs_client_context_cb, size);
|
|
if (list) {
|
|
s_dcs_client_context_cb = list;
|
|
} else {
|
|
DUER_LOGE("Failed to add dcs client context cb: no memory\n");
|
|
DUER_DS_LOG_REPORT_DCS_MEMORY_ERROR();
|
|
ret = DUER_ERR_MEMORY_OVERFLOW;
|
|
return ret;
|
|
}
|
|
}
|
|
|
|
s_dcs_client_context_cb[s_client_context_cb_count] = cb;
|
|
s_client_context_cb_count++;
|
|
|
|
return ret;
|
|
}
|
|
|
|
void duer_reg_dcs_hook_directive_hdl(dcs_directive_hook_handler cb)
|
|
{
|
|
if (!s_dcs_directive_hook_cb) {
|
|
s_dcs_directive_hook_cb = cb;
|
|
} else {
|
|
DUER_LOGI("dlp directive has been initialed");
|
|
}
|
|
}
|
|
|
|
void duer_reg_dcs_hook_event_hdl(dcs_event_hook_handler cb)
|
|
{
|
|
if (cb) {
|
|
duer_reg_dcs_event_hook_hdl_internal(cb);
|
|
s_dcs_hook_event_handler = cb;
|
|
}
|
|
}
|
|
|
|
void duer_dcs_hook_event_status_report(baidu_json *status)
|
|
{
|
|
if (s_dcs_hook_event_handler) {
|
|
s_dcs_hook_event_handler(status);
|
|
}
|
|
}
|
|
|
|
duer_status_t duer_reg_client_context_cb(dcs_client_context_handler cb)
|
|
{
|
|
duer_status_t ret = DUER_OK;
|
|
|
|
DUER_DCS_CRITICAL_ENTER();
|
|
if (s_is_initialized) {
|
|
ret = duer_reg_client_context_cb_internal(cb);
|
|
} else {
|
|
DUER_LOGW("DCS has not been initialed");
|
|
ret = DUER_ERR_FAILED;
|
|
}
|
|
DUER_DCS_CRITICAL_EXIT();
|
|
|
|
return ret;
|
|
}
|
|
|
|
baidu_json *duer_create_dcs_event(const char *name_space, const char *name, duer_bool need_msg_id)
|
|
{
|
|
baidu_json *event = NULL;
|
|
baidu_json *header = NULL;
|
|
baidu_json *payload = NULL;
|
|
const char *msg_id = NULL;
|
|
|
|
event = baidu_json_CreateObject();
|
|
if (event == NULL) {
|
|
goto error_out;
|
|
}
|
|
|
|
header = baidu_json_CreateObject();
|
|
if (header == NULL) {
|
|
goto error_out;
|
|
}
|
|
|
|
baidu_json_AddStringToObjectCS(header, DCS_NAMESPACE_KEY, name_space);
|
|
baidu_json_AddStringToObjectCS(header, DCS_NAME_KEY, name);
|
|
|
|
if (need_msg_id) {
|
|
msg_id = duer_generate_msg_id_internal();
|
|
if (msg_id) {
|
|
baidu_json_AddStringToObject(header, DCS_MESSAGE_ID_KEY, msg_id);
|
|
DUER_LOGD("msg_id: %s", msg_id);
|
|
}
|
|
}
|
|
|
|
baidu_json_AddItemToObjectCS(event, DCS_HEADER_KEY, header);
|
|
|
|
payload = baidu_json_CreateObject();
|
|
if (payload == NULL) {
|
|
goto error_out;
|
|
}
|
|
|
|
baidu_json_AddItemToObjectCS(event, DCS_PAYLOAD_KEY, payload);
|
|
|
|
return event;
|
|
|
|
error_out:
|
|
DUER_DS_LOG_REPORT_DCS_MEMORY_ERROR();
|
|
if (event) {
|
|
baidu_json_Delete(event);
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
baidu_json *duer_get_client_context_internal(void)
|
|
{
|
|
baidu_json *client_context = NULL;
|
|
baidu_json *state = NULL;
|
|
int i = 0;
|
|
|
|
client_context = baidu_json_CreateArray();
|
|
if (!client_context) {
|
|
DUER_DS_LOG_REPORT_DCS_MEMORY_ERROR();
|
|
DUER_LOGE("Memory overlow");
|
|
return NULL;
|
|
}
|
|
|
|
while ((i < s_client_context_cb_count) && (s_dcs_client_context_cb[i])) {
|
|
state = s_dcs_client_context_cb[i]();
|
|
if (state) {
|
|
baidu_json_AddItemToArray(client_context, state);
|
|
}
|
|
i++;
|
|
}
|
|
|
|
return client_context;
|
|
}
|
|
|
|
static directive_namespace_list_t *duer_get_namespace_node(const char *name_space)
|
|
{
|
|
int i = 0;
|
|
size_t size = 0;
|
|
char *new_namespace = NULL;
|
|
directive_namespace_list_t *list = NULL;
|
|
|
|
if (!s_directive_namespace_list) {
|
|
s_directive_namespace_list = DUER_MALLOC(sizeof(*s_directive_namespace_list));
|
|
if (!s_directive_namespace_list) {
|
|
return NULL;
|
|
}
|
|
|
|
DUER_MEMSET((void *)s_directive_namespace_list, 0, sizeof(*s_directive_namespace_list));
|
|
s_directive_namespace_list->name_space = duer_strdup_internal(name_space);
|
|
if (!s_directive_namespace_list->name_space) {
|
|
DUER_FREE((void *)s_directive_namespace_list);
|
|
s_directive_namespace_list = NULL;
|
|
return NULL;
|
|
}
|
|
|
|
s_namespace_count++;
|
|
return (directive_namespace_list_t *)s_directive_namespace_list;
|
|
}
|
|
|
|
for (i = 0; i < s_namespace_count; i++) {
|
|
if (DUER_STRCMP(name_space, s_directive_namespace_list[i].name_space) == 0) {
|
|
return (directive_namespace_list_t *)&s_directive_namespace_list[i];
|
|
}
|
|
}
|
|
|
|
new_namespace = duer_strdup_internal(name_space);
|
|
if (!new_namespace) {
|
|
return NULL;
|
|
}
|
|
|
|
size = sizeof(*s_directive_namespace_list) * (s_namespace_count + 1);
|
|
list = DUER_REALLOC((void *)s_directive_namespace_list, size);
|
|
if (!list) {
|
|
DUER_FREE(new_namespace);
|
|
return NULL;
|
|
}
|
|
|
|
s_directive_namespace_list = list;
|
|
DUER_MEMSET((void *)&s_directive_namespace_list[s_namespace_count],
|
|
0,
|
|
sizeof(*s_directive_namespace_list));
|
|
s_directive_namespace_list[s_namespace_count].name_space = new_namespace;
|
|
|
|
return (directive_namespace_list_t *)&s_directive_namespace_list[s_namespace_count++];
|
|
}
|
|
|
|
static duer_status_t duer_directive_duplicate(directive_namespace_list_t *node,
|
|
const duer_directive_list *directive)
|
|
{
|
|
int i = 0;
|
|
char *name = NULL;
|
|
duer_directive_list *list = NULL;
|
|
|
|
if (node->list) {
|
|
for (i = 0; i < node->count; i++) {
|
|
if (DUER_STRCMP(node->list[i].directive_name, directive->directive_name) == 0
|
|
&& node->list[i].cb == directive->cb) {
|
|
return DUER_OK;
|
|
}
|
|
}
|
|
}
|
|
|
|
name = duer_strdup_internal(directive->directive_name);
|
|
if (!name) {
|
|
DUER_DS_LOG_REPORT_DCS_MEMORY_ERROR();
|
|
return DUER_ERR_MEMORY_OVERFLOW;
|
|
}
|
|
|
|
if (node->list) {
|
|
list = (duer_directive_list *)DUER_REALLOC(node->list,
|
|
sizeof(*directive) * (node->count + 1));
|
|
} else {
|
|
list = (duer_directive_list *)DUER_MALLOC(sizeof(*directive));
|
|
}
|
|
|
|
if (!list) {
|
|
DUER_FREE(name);
|
|
DUER_DS_LOG_REPORT_DCS_MEMORY_ERROR();
|
|
return DUER_ERR_MEMORY_OVERFLOW;
|
|
}
|
|
|
|
list[node->count].cb = directive->cb;
|
|
list[node->count].directive_name = name;
|
|
node->list = list;
|
|
node->count++;
|
|
|
|
return DUER_OK;
|
|
}
|
|
|
|
duer_status_t duer_add_dcs_directive_internal(const duer_directive_list *directive,
|
|
size_t count,
|
|
const char *name_space)
|
|
{
|
|
int i = 0;
|
|
duer_status_t ret = DUER_OK;
|
|
directive_namespace_list_t *node;
|
|
DUER_LOGI("namespace: %s", name_space);
|
|
|
|
if (!directive || (count == 0) || !name_space) {
|
|
DUER_LOGE("Failed to add dcs directive: param error");
|
|
DUER_DS_LOG_REPORT_DCS_PARAM_ERROR();
|
|
ret = DUER_ERR_INVALID_PARAMETER;
|
|
goto exit;
|
|
}
|
|
|
|
node = duer_get_namespace_node(name_space);
|
|
if (!node) {
|
|
ret = DUER_ERR_MEMORY_OVERFLOW;
|
|
DUER_LOGE("Failed to add dcs directive: no memory");
|
|
DUER_DS_LOG_REPORT_DCS_MEMORY_ERROR();
|
|
goto exit;
|
|
}
|
|
|
|
for (i = 0; i < count; i++) {
|
|
ret = duer_directive_duplicate(node, &directive[i]);
|
|
if (ret != DUER_OK) {
|
|
DUER_LOGE("Failed to add dcs directive: %s, errcode: %d",
|
|
directive[i].directive_name,
|
|
ret);
|
|
break;
|
|
}
|
|
}
|
|
|
|
exit:
|
|
if ((ret != DUER_OK) && (ret != DUER_ERR_INVALID_PARAMETER)) {
|
|
while (i < count) {
|
|
duer_ds_log_dcs_add_directive_fail(directive[i++].directive_name);
|
|
}
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
static duer_status_t duer_directive_enqueue(baidu_json *directive,
|
|
int index,
|
|
directive_source_t source)
|
|
{
|
|
duer_status_t rs = DUER_OK;
|
|
directive_node_t *node = NULL;
|
|
directive_node_t *tmp_node = NULL;
|
|
duer_qcache_iterator *p = NULL; // used to find the location to insert the directive
|
|
duer_qcache_iterator *target = NULL; // insert the directive after q
|
|
|
|
node = (directive_node_t *)DUER_MALLOC(sizeof(directive_node_t));
|
|
if (!node) {
|
|
DUER_LOGE("Failed to cache directive: memory overlow");
|
|
rs = DUER_ERR_MEMORY_OVERFLOW;
|
|
goto RET;
|
|
}
|
|
|
|
node->directive = baidu_json_Duplicate(directive, 0);
|
|
if (!node->directive) {
|
|
rs = DUER_ERR_MEMORY_OVERFLOW;
|
|
goto RET;
|
|
}
|
|
node->index = index;
|
|
node->source = source;
|
|
|
|
p = duer_qcache_head(s_directive_queue);
|
|
while (p) {
|
|
tmp_node = (directive_node_t *)duer_qcache_data(p);
|
|
if (!tmp_node) {
|
|
DUER_LOGE("Failed to get directive node");
|
|
rs = DUER_ERR_FAILED;
|
|
goto RET;
|
|
}
|
|
|
|
if (tmp_node->index > index) {
|
|
break;
|
|
}
|
|
|
|
target = p;
|
|
p = duer_qcache_next(p);
|
|
}
|
|
|
|
rs = duer_qcache_insert(s_directive_queue, target, node);
|
|
if (rs != DUER_OK) {
|
|
DUER_LOGE("Failed to insert directive to queue");
|
|
}
|
|
|
|
RET:
|
|
if (rs != DUER_OK) {
|
|
if (node) {
|
|
baidu_json_release(node->directive);
|
|
DUER_FREE(node);
|
|
}
|
|
}
|
|
|
|
return rs;
|
|
}
|
|
|
|
duer_status_t duer_add_dcs_directive(const duer_directive_list *directive,
|
|
size_t count,
|
|
const char *name_space)
|
|
{
|
|
duer_status_t ret = DUER_OK;
|
|
|
|
DUER_DCS_CRITICAL_ENTER();
|
|
if (s_is_initialized) {
|
|
ret = duer_add_dcs_directive_internal(directive, count, name_space);
|
|
} else {
|
|
DUER_LOGW("DCS has not been initialed");
|
|
ret = DUER_ERR_FAILED;
|
|
}
|
|
DUER_DCS_CRITICAL_EXIT();
|
|
|
|
return ret;
|
|
}
|
|
|
|
static duer_status_t duer_dialog_finish_cb(const baidu_json *directive)
|
|
{
|
|
DUER_DCS_CRITICAL_ENTER();
|
|
duer_listen_stop_internal();
|
|
s_wait_dialog_finish = DUER_FALSE;
|
|
duer_play_channel_control_internal(DCS_DIALOG_FINISHED);
|
|
DUER_DCS_CRITICAL_EXIT();
|
|
|
|
return DUER_OK;
|
|
}
|
|
|
|
void duer_dialog_started(void)
|
|
{
|
|
s_wait_dialog_finish = DUER_TRUE;
|
|
}
|
|
|
|
static baidu_json *duer_create_directive(const char *namespace,
|
|
const char *name,
|
|
const char *dialog_id)
|
|
{
|
|
baidu_json *directive = NULL;
|
|
baidu_json *header = NULL;
|
|
baidu_json *payload = NULL;
|
|
const char *msg_id = NULL;
|
|
|
|
directive = baidu_json_CreateObject();
|
|
if (directive == NULL) {
|
|
goto error_out;
|
|
}
|
|
|
|
header = baidu_json_CreateObject();
|
|
if (header == NULL) {
|
|
goto error_out;
|
|
}
|
|
|
|
baidu_json_AddItemToObjectCS(directive, DCS_HEADER_KEY, header);
|
|
baidu_json_AddStringToObjectCS(header, DCS_NAMESPACE_KEY, namespace);
|
|
baidu_json_AddStringToObjectCS(header, DCS_NAME_KEY, name);
|
|
baidu_json_AddStringToObject(header, DCS_DIALOG_REQUEST_ID_KEY, dialog_id);
|
|
|
|
msg_id = duer_generate_msg_id_internal();
|
|
if (msg_id) {
|
|
baidu_json_AddStringToObject(header, DCS_MESSAGE_ID_KEY, msg_id);
|
|
DUER_LOGD("msg_id: %s", msg_id);
|
|
}
|
|
|
|
payload = baidu_json_CreateObject();
|
|
if (payload == NULL) {
|
|
goto error_out;
|
|
}
|
|
|
|
baidu_json_AddItemToObjectCS(directive, DCS_PAYLOAD_KEY, payload);
|
|
|
|
return directive;
|
|
|
|
error_out:
|
|
DUER_DS_LOG_REPORT_DCS_MEMORY_ERROR();
|
|
if (directive) {
|
|
baidu_json_Delete(directive);
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
static duer_status_t duer_session_finish_callback(void *data)
|
|
{
|
|
baidu_json *directive = (baidu_json *)data;
|
|
|
|
if (directive == NULL) {
|
|
directive = duer_create_directive(DCS_PRIVATE_NAMESPACE,
|
|
DCS_DIALOGUE_FINISHED_NAME,
|
|
duer_get_request_id_internal());
|
|
}
|
|
|
|
if (directive) {
|
|
duer_handle_directive(directive, 1024, PRIVATE_PROTOCAL_DIRECTIVE);
|
|
}
|
|
|
|
baidu_json_Delete(directive);
|
|
|
|
return DUER_OK;
|
|
}
|
|
|
|
static dcs_directive_handler *duer_dcs_get_handlers(const char *name_space,
|
|
const char *name,
|
|
int *count)
|
|
{
|
|
directive_namespace_list_t *node = NULL;
|
|
dcs_directive_handler *ret = NULL;
|
|
dcs_directive_handler *buf = NULL;
|
|
int i = 0;
|
|
|
|
*count = 0;
|
|
|
|
if (!s_is_initialized) {
|
|
return NULL;
|
|
}
|
|
|
|
for (i = 0; i < s_namespace_count; i++) {
|
|
if (DUER_STRCMP(s_directive_namespace_list[i].name_space,
|
|
name_space) == 0) {
|
|
node = (directive_namespace_list_t *)&s_directive_namespace_list[i];
|
|
}
|
|
}
|
|
|
|
if (!node) {
|
|
return NULL;
|
|
}
|
|
|
|
for (i = 0; i < node->count; i++) {
|
|
if (DUER_STRCMP(node->list[i].directive_name, name) == 0) {
|
|
if (!ret) {
|
|
buf = DUER_MALLOC((*count + 1) * sizeof(*ret));
|
|
} else {
|
|
buf = DUER_REALLOC(ret, (*count + 1) * sizeof(*ret));
|
|
}
|
|
|
|
if (!buf) {
|
|
DUER_LOGE("Failed to get all handlers");
|
|
break;
|
|
}
|
|
|
|
ret = buf;
|
|
ret[*count] = node->list[i].cb;
|
|
*count = *count + 1;
|
|
}
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
duer_status_t duer_execute_directive(baidu_json *directive)
|
|
{
|
|
int i = 0;
|
|
int hdlr_count = 0;
|
|
duer_status_t rs = DUER_OK;
|
|
baidu_json *name = NULL;
|
|
baidu_json *name_space = NULL;
|
|
baidu_json *header = NULL;
|
|
dcs_directive_handler *handler = NULL;
|
|
|
|
header = baidu_json_GetObjectItem(directive, DCS_HEADER_KEY);
|
|
if (!header) {
|
|
DUER_LOGE("Failed to parse directive header");
|
|
rs = DUER_MSG_RSP_BAD_REQUEST;
|
|
goto RET;
|
|
}
|
|
|
|
name_space = baidu_json_GetObjectItem(header, DCS_NAMESPACE_KEY);
|
|
if (!name_space || !name_space->valuestring) {
|
|
DUER_LOGE("Failed to parse directive namespace");
|
|
rs = DUER_MSG_RSP_BAD_REQUEST;
|
|
goto RET;
|
|
}
|
|
|
|
name = baidu_json_GetObjectItem(header, DCS_NAME_KEY);
|
|
if (!name || !name->valuestring) {
|
|
DUER_LOGE("Failed to parse directive name");
|
|
rs = DUER_MSG_RSP_BAD_REQUEST;
|
|
goto RET;
|
|
}
|
|
|
|
DUER_LOGI("Directive namespace: %s", name_space->valuestring);
|
|
DUER_LOGI("Directive name: %s", name->valuestring);
|
|
|
|
if (!DUER_MEMCMP(name_space->valuestring, NAMESPACE_DLP, DUER_STRLEN(NAMESPACE_DLP))) {
|
|
if (s_dcs_directive_hook_cb) {
|
|
s_dcs_directive_hook_cb(directive);
|
|
}
|
|
goto RET;
|
|
}
|
|
|
|
#ifdef DUER_MONITOR_TEST_ENABLE
|
|
duer_dcs_monitor_test_add_result(name_space->valuestring, name->valuestring);
|
|
#endif
|
|
|
|
DUER_DCS_CRITICAL_ENTER();
|
|
handler = duer_dcs_get_handlers(name_space->valuestring, name->valuestring, &hdlr_count);
|
|
DUER_DCS_CRITICAL_EXIT();
|
|
|
|
if (handler) {
|
|
for (i = 0; i < hdlr_count; i++) {
|
|
rs = handler[i](directive);
|
|
if (rs != DUER_OK) {
|
|
goto RET;
|
|
}
|
|
}
|
|
} else {
|
|
DUER_LOGE("unrecognized directive: %s, namespace: %s\n",
|
|
name->valuestring,
|
|
name_space->valuestring);
|
|
rs = DUER_MSG_RSP_NOT_FOUND;
|
|
}
|
|
|
|
RET:
|
|
if (handler) {
|
|
DUER_FREE(handler);
|
|
}
|
|
|
|
return rs;
|
|
}
|
|
|
|
static duer_bool duer_is_directive_equal(const char *namespace1,
|
|
const char *name1,
|
|
const char *namespace2,
|
|
const char *name2)
|
|
{
|
|
if (namespace1 && name1 && namespace2 && name2) {
|
|
if ((DUER_STRCMP(name1, name2) == 0) && (DUER_STRCMP(namespace1, namespace2) == 0)) {
|
|
return DUER_TRUE;
|
|
}
|
|
}
|
|
|
|
return DUER_FALSE;
|
|
}
|
|
|
|
static duer_bool duer_is_speak_directive(baidu_json *directive)
|
|
{
|
|
baidu_json *name = NULL;
|
|
baidu_json *name_space = NULL;
|
|
baidu_json *header = NULL;
|
|
duer_bool is_speak_directive = DUER_FALSE;
|
|
|
|
header = baidu_json_GetObjectItem(directive, DCS_HEADER_KEY);
|
|
if (header) {
|
|
name = baidu_json_GetObjectItem(header, DCS_NAME_KEY);
|
|
name_space = baidu_json_GetObjectItem(header, DCS_NAMESPACE_KEY);
|
|
if (name && name_space && name->valuestring && name_space->valuestring) {
|
|
is_speak_directive = duer_is_directive_equal(name_space->valuestring,
|
|
name->valuestring,
|
|
DCS_VOICE_OUTPUT_NAMESPACE,
|
|
DCS_SPEAK_NAME);
|
|
}
|
|
}
|
|
|
|
return is_speak_directive;
|
|
}
|
|
|
|
static void duer_dcs_check_and_report_exception(directive_node_t *node, duer_status_t rs)
|
|
{
|
|
baidu_json *value = NULL;
|
|
char *payload = NULL;
|
|
|
|
if (rs == DUER_OK) {
|
|
return;
|
|
}
|
|
|
|
if (!node || !node->directive) {
|
|
return;
|
|
}
|
|
|
|
value = baidu_json_CreateObject();
|
|
if (!value) {
|
|
DUER_DS_LOG_REPORT_DCS_MEMORY_ERROR();
|
|
return;
|
|
}
|
|
|
|
baidu_json_AddItemReferenceToObject(value, DCS_DIRECTIVE_KEY, node->directive);
|
|
#ifdef DUER_BJSON_PRINT_WITH_ESTIMATED_SIZE
|
|
payload = baidu_json_PrintBuffered(value,
|
|
DUER_PRINT_BJSON_ESTIMATED_SIZE_FOR_REPORT_EXCEPTION, 0);
|
|
#else
|
|
payload = baidu_json_PrintUnformatted(value);
|
|
#endif // DUER_BJSON_PRINT_WITH_ESTIMATED_SIZE
|
|
baidu_json_Delete(value);
|
|
value = NULL;
|
|
if (!payload) {
|
|
DUER_DS_LOG_REPORT_DCS_MEMORY_ERROR();
|
|
return;
|
|
}
|
|
baidu_json_Delete(node->directive);
|
|
node->directive = NULL;
|
|
|
|
if (rs == DUER_MSG_RSP_NOT_FOUND) {
|
|
value = duer_get_exception_internal(payload, 0,
|
|
DCS_UNSUPPORTED_OPERATION_TYPE, "Unknow directive");
|
|
} else if (rs == DUER_MSG_RSP_BAD_REQUEST) {
|
|
value = duer_get_exception_internal(payload, 0,
|
|
DCS_UNEXPECTED_INFORMATION_RECEIVED_TYPE,
|
|
"Bad directive");
|
|
} else {
|
|
value = duer_get_exception_internal(payload, 0, DCS_INTERNAL_ERROR_TYPE, "Internal error");
|
|
}
|
|
|
|
if (payload) {
|
|
baidu_json_release(payload);
|
|
}
|
|
rs = DUER_ERR_FAILED;
|
|
if (value) {
|
|
rs = duer_dcs_data_report_internal(value, DUER_TRUE);
|
|
baidu_json_Delete(value);
|
|
value = NULL;
|
|
}
|
|
if (rs != DUER_OK) {
|
|
duer_ds_log_dcs_event_report_fail(DCS_EXCEPTION_ENCOUNTERED_NAME);
|
|
}
|
|
}
|
|
|
|
static void duer_execute_caching_directive(int what, void *data)
|
|
{
|
|
duer_bool is_speak_directive = DUER_FALSE;
|
|
duer_status_t rs = DUER_OK;
|
|
directive_node_t *node = NULL;
|
|
|
|
duer_mutex_lock(s_directive_queue_lock);
|
|
do {
|
|
if (!s_directive_queue) {
|
|
DUER_LOGW("s_directive_queue = null");
|
|
break;
|
|
}
|
|
|
|
if (duer_qcache_length(s_directive_queue) == 0) {
|
|
break;
|
|
}
|
|
|
|
node = duer_qcache_pop(s_directive_queue);
|
|
if (!node || !node->directive) {
|
|
DUER_LOGE("Failed to get directive");
|
|
break;
|
|
}
|
|
|
|
is_speak_directive = duer_is_speak_directive(node->directive);
|
|
if (is_speak_directive) {
|
|
s_wait_dialog_finish = DUER_TRUE;
|
|
s_is_speak_pending = DUER_TRUE;
|
|
s_speaking_index = node->index;
|
|
}
|
|
|
|
rs = duer_execute_directive(node->directive);
|
|
if (node->source == STANDARD_DCS_DIRECTIVE) {
|
|
duer_dcs_check_and_report_exception(node, rs);
|
|
}
|
|
|
|
if (node->directive) {
|
|
baidu_json_Delete(node->directive);
|
|
node->directive = NULL;
|
|
}
|
|
DUER_FREE(node);
|
|
|
|
if (!s_is_speak_pending) {
|
|
if (duer_qcache_length(s_directive_queue) > 0) {
|
|
#ifdef DUER_EVENT_HANDLER
|
|
duer_handler_handle(duer_execute_caching_directive, 0, NULL);
|
|
#else
|
|
duer_emitter_emit(duer_execute_caching_directive, 0, NULL);
|
|
#endif // DUER_EVENT_HANDLER
|
|
}
|
|
}
|
|
} while (0);
|
|
|
|
duer_mutex_unlock(s_directive_queue_lock);
|
|
}
|
|
|
|
const char *duer_create_request_id(void)
|
|
{
|
|
return duer_create_request_id_internal(DCS_DIALOG_NONE);
|
|
}
|
|
|
|
static void duer_clear_directive_queue(int what, void *data)
|
|
{
|
|
directive_node_t *node = NULL;
|
|
|
|
duer_mutex_lock(s_directive_queue_lock);
|
|
|
|
s_speaking_index = DUMMY_INDEX;
|
|
if (s_is_speak_pending) {
|
|
duer_dcs_stop_speak_handler();
|
|
s_is_speak_pending = DUER_FALSE;
|
|
}
|
|
s_wait_dialog_finish = DUER_FALSE;
|
|
duer_speech_on_stop_internal();
|
|
|
|
if (!s_directive_queue) {
|
|
duer_mutex_unlock(s_directive_queue_lock);
|
|
return;
|
|
}
|
|
|
|
do {
|
|
node = duer_qcache_pop(s_directive_queue);
|
|
if (node) {
|
|
baidu_json_Delete(node->directive);
|
|
DUER_FREE(node);
|
|
}
|
|
} while (duer_qcache_length(s_directive_queue) > 0);
|
|
|
|
duer_mutex_unlock(s_directive_queue_lock);
|
|
}
|
|
|
|
void duer_cancel_caching_directive_internal()
|
|
{
|
|
#ifdef DUER_EVENT_HANDLER
|
|
duer_handler_handle(duer_clear_directive_queue, 0, NULL);
|
|
#else
|
|
duer_emitter_emit(duer_clear_directive_queue, 0, NULL);
|
|
#endif // DUER_EVENT_HANDLER
|
|
}
|
|
|
|
duer_bool duer_wait_dialog_finished_internal(void)
|
|
{
|
|
return s_wait_dialog_finish;
|
|
}
|
|
|
|
void duer_speak_directive_finished_internal(void)
|
|
{
|
|
duer_mutex_lock(s_directive_queue_lock);
|
|
|
|
s_speaking_index = DUMMY_INDEX;
|
|
s_is_speak_pending = DUER_FALSE;
|
|
do {
|
|
if (!s_directive_queue) {
|
|
DUER_LOGW("s_directive_queue = null");
|
|
break;
|
|
}
|
|
|
|
if (duer_qcache_length(s_directive_queue) > 0) {
|
|
#ifdef DUER_EVENT_HANDLER
|
|
duer_handler_handle(duer_execute_caching_directive, 0, NULL);
|
|
#else
|
|
duer_emitter_emit(duer_execute_caching_directive, 0, NULL);
|
|
#endif // DUER_EVENT_HANDLER
|
|
}
|
|
} while (0);
|
|
duer_mutex_unlock(s_directive_queue_lock);
|
|
}
|
|
|
|
#ifdef DUER_STATISTICS_E2E
|
|
static void duer_e2e_response(const char *name_space, const char *name)
|
|
{
|
|
duer_bool is_e2e_response_directive = DUER_FALSE;
|
|
|
|
if (!duer_ds_e2e_wait_response()) {
|
|
return;
|
|
}
|
|
|
|
is_e2e_response_directive = duer_is_directive_equal(name_space,
|
|
name,
|
|
DCS_VOICE_OUTPUT_NAMESPACE,
|
|
DCS_SPEAK_NAME);
|
|
if (!is_e2e_response_directive) {
|
|
is_e2e_response_directive = duer_is_directive_equal(name_space,
|
|
name,
|
|
DCS_AUDIO_PLAYER_NAMESPACE,
|
|
DCS_PLAY_NAME);
|
|
}
|
|
|
|
if (is_e2e_response_directive) {
|
|
duer_ds_e2e_event(DUER_E2E_RESPONSE);
|
|
}
|
|
}
|
|
#endif
|
|
|
|
static duer_status_t duer_handle_directive(baidu_json *directive,
|
|
int index,
|
|
directive_source_t source)
|
|
{
|
|
baidu_json *dialog_id = NULL;
|
|
baidu_json *name = NULL;
|
|
baidu_json *header = NULL;
|
|
baidu_json *name_space = NULL;
|
|
const char *current_dialog_id = NULL;
|
|
duer_status_t rs = DUER_OK;
|
|
duer_bool is_unblock_directive = DUER_FALSE;
|
|
|
|
header = baidu_json_GetObjectItem(directive, DCS_HEADER_KEY);
|
|
if (!header) {
|
|
DUER_LOGE("Failed to parse header");
|
|
return DUER_MSG_RSP_BAD_REQUEST;
|
|
}
|
|
|
|
dialog_id = baidu_json_GetObjectItem(header, DCS_DIALOG_REQUEST_ID_KEY);
|
|
// execute the directive immediately if no dialog_id item
|
|
if (!dialog_id) {
|
|
rs = duer_execute_directive(directive);
|
|
return rs;
|
|
}
|
|
|
|
if (!dialog_id->valuestring) {
|
|
DUER_LOGE("Failed to parse dialog_id");
|
|
return DUER_MSG_RSP_BAD_REQUEST;
|
|
}
|
|
|
|
current_dialog_id = duer_get_request_id_internal();
|
|
if (!current_dialog_id) {
|
|
DUER_LOGE("Failed to get current dialog id");
|
|
return DUER_ERR_FAILED;
|
|
}
|
|
|
|
name = baidu_json_GetObjectItem(header, DCS_NAME_KEY);
|
|
if (!name || !name->valuestring) {
|
|
DUER_LOGE("Failed to parse name");
|
|
return DUER_MSG_RSP_BAD_REQUEST;
|
|
}
|
|
|
|
if (DUER_STRCMP(current_dialog_id, dialog_id->valuestring)) {
|
|
DUER_LOGI("Drop the directive for old dialog_Id: %s, current dialog_Id: %s",
|
|
dialog_id->valuestring, current_dialog_id);
|
|
duer_ds_log_dcs_directive_drop(current_dialog_id,
|
|
dialog_id->valuestring,
|
|
name->valuestring);
|
|
return DUER_OK;
|
|
}
|
|
|
|
name_space = baidu_json_GetObjectItem(header, DCS_NAMESPACE_KEY);
|
|
if (!name_space || !name_space->valuestring) {
|
|
DUER_LOGE("Failed to parse namespace");
|
|
return DUER_MSG_RSP_BAD_REQUEST;
|
|
}
|
|
|
|
#ifdef DUER_STATISTICS_E2E
|
|
duer_e2e_response(name_space->valuestring, name->valuestring);
|
|
#endif
|
|
|
|
is_unblock_directive = duer_is_directive_equal(name_space->valuestring,
|
|
name->valuestring,
|
|
DCS_VOICE_INPUT_NAMESPACE,
|
|
DCS_STOP_LISTEN_NAME);
|
|
if (!is_unblock_directive) {
|
|
is_unblock_directive = duer_is_directive_equal(name_space->valuestring,
|
|
name->valuestring,
|
|
DCS_SCREEN_NAMESPACE,
|
|
DCS_RENDER_VOICE_INPUT_TEXT_NAME);
|
|
}
|
|
|
|
if (is_unblock_directive) {
|
|
DUER_LOGD("Unblocked directive");
|
|
rs = duer_execute_directive(directive);
|
|
return rs;
|
|
}
|
|
|
|
duer_mutex_lock(s_directive_queue_lock);
|
|
|
|
if (s_directive_queue) {
|
|
rs = duer_directive_enqueue(directive, index, source);
|
|
|
|
if (rs == DUER_OK) {
|
|
if ((duer_qcache_length(s_directive_queue) == 1 && !s_is_speak_pending)
|
|
|| (s_is_speak_pending && index < s_speaking_index)) {
|
|
#ifdef DUER_EVENT_HANDLER
|
|
rs = duer_handler_handle(duer_execute_caching_directive, 0, NULL);
|
|
#else
|
|
rs = duer_emitter_emit(duer_execute_caching_directive, 0, NULL);
|
|
#endif // DUER_EVENT_HANDLER
|
|
}
|
|
} else {
|
|
DUER_LOGE("Failed to enqueue directive");
|
|
}
|
|
|
|
DUER_LOGD("queue len: %d", duer_qcache_length(s_directive_queue));
|
|
}
|
|
duer_mutex_unlock(s_directive_queue_lock);
|
|
|
|
return rs;
|
|
}
|
|
|
|
// now the last parameter payload is not used
|
|
static duer_status_t duer_dcs_directive_parse(duer_msg_t *msg,
|
|
baidu_json **value,
|
|
baidu_json **directive,
|
|
baidu_json **header,
|
|
baidu_json **name_space,
|
|
baidu_json **name,
|
|
char **payload)
|
|
{
|
|
duer_status_t rs = DUER_OK;
|
|
baidu_json *directive_header = NULL;
|
|
|
|
do {
|
|
if (!s_is_initialized) {
|
|
DUER_LOGW("DCS has been uninitialized");
|
|
rs = DUER_MSG_RSP_NOT_FOUND;
|
|
break;
|
|
}
|
|
|
|
if (!msg) {
|
|
rs = DUER_MSG_RSP_BAD_REQUEST;
|
|
break;
|
|
}
|
|
|
|
if (!value || !directive) {
|
|
rs = DUER_ERR_INVALID_PARAMETER;
|
|
break;
|
|
}
|
|
|
|
if (!msg->payload || msg->payload_len <= 0) {
|
|
rs = DUER_MSG_RSP_BAD_REQUEST;
|
|
break;
|
|
}
|
|
|
|
*value = baidu_json_Parse((const char *)msg->payload);
|
|
|
|
if (*value == NULL) {
|
|
DUER_LOGE("Failed to parse payload");
|
|
rs = DUER_ERR_FAILED;
|
|
break;
|
|
}
|
|
|
|
*directive = baidu_json_GetObjectItem(*value, DCS_DIRECTIVE_KEY);
|
|
if (*directive == NULL) {
|
|
DUER_LOGE("Failed to parse directive");
|
|
rs = DUER_MSG_RSP_BAD_REQUEST;
|
|
break;
|
|
}
|
|
|
|
if (!header && !name_space && !name) {
|
|
break;
|
|
}
|
|
|
|
directive_header = baidu_json_GetObjectItem(*directive, DCS_HEADER_KEY);
|
|
if (!directive_header) {
|
|
DUER_LOGE("Failed to parse header");
|
|
rs = DUER_MSG_RSP_BAD_REQUEST;
|
|
break;
|
|
}
|
|
|
|
if (header) {
|
|
*header = directive_header;
|
|
}
|
|
|
|
if (name_space) {
|
|
*name_space = baidu_json_GetObjectItem(directive_header, DCS_NAMESPACE_KEY);
|
|
if (*name_space == NULL || (*name_space)->valuestring == NULL) {
|
|
DUER_LOGE("Failed to parse directive namespace");
|
|
rs = DUER_MSG_RSP_BAD_REQUEST;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (name) {
|
|
*name = baidu_json_GetObjectItem(directive_header, DCS_NAME_KEY);
|
|
if (*name == NULL || (*name)->valuestring == NULL) {
|
|
DUER_LOGE("Failed to parse directive namespace");
|
|
rs = DUER_MSG_RSP_BAD_REQUEST;
|
|
break;
|
|
}
|
|
}
|
|
} while (0);
|
|
|
|
return rs;
|
|
}
|
|
|
|
static int duer_get_directive_index(baidu_json *value, const char *name)
|
|
{
|
|
baidu_json *index = NULL;
|
|
baidu_json *extra_info = NULL;
|
|
|
|
extra_info = baidu_json_GetObjectItem(value, IOT_CLOUD_EXTRA_KEY);
|
|
if (extra_info) {
|
|
index = baidu_json_GetObjectItem(extra_info, INDEX_KEY);
|
|
#if 0
|
|
baidu_json *timestamp = baidu_json_GetObjectItem(extra_info, "timestamp");
|
|
DUER_LOGI("directive name:%s, timestamp:%s, index:%d",
|
|
name,
|
|
(timestamp && timestamp->valuestring) ? timestamp->valuestring : "",
|
|
index ? index->valueint : DUMMY_INDEX);
|
|
#endif
|
|
}
|
|
|
|
return index ? index->valueint : DUMMY_INDEX;
|
|
}
|
|
|
|
static duer_status_t duer_dcs_router(duer_context ctx, duer_msg_t *msg, duer_addr_t *addr)
|
|
{
|
|
char *payload = NULL;
|
|
duer_status_t rs = DUER_OK;
|
|
baidu_json *directive = NULL;
|
|
baidu_json *value = NULL;
|
|
duer_msg_code_e msg_code = DUER_MSG_RSP_CHANGED;
|
|
baidu_json *name = NULL;
|
|
int index = DUMMY_INDEX;
|
|
|
|
DUER_LOGV("Enter");
|
|
|
|
do {
|
|
rs = duer_dcs_directive_parse(msg, &value, &directive, NULL, NULL, &name, NULL);
|
|
if (rs != DUER_OK) {
|
|
break;
|
|
}
|
|
|
|
index = duer_get_directive_index(value, name->valuestring);
|
|
rs = duer_handle_directive(directive, index, STANDARD_DCS_DIRECTIVE);
|
|
} while (0);
|
|
|
|
if (rs != DUER_OK) {
|
|
if (rs == DUER_MSG_RSP_NOT_FOUND) {
|
|
duer_report_exception_internal((const char *)msg->payload,
|
|
msg->payload_len,
|
|
DCS_UNSUPPORTED_OPERATION_TYPE,
|
|
"Unknow directive");
|
|
msg_code = DUER_MSG_RSP_NOT_FOUND;
|
|
} else if (rs == DUER_MSG_RSP_BAD_REQUEST) {
|
|
duer_report_exception_internal((const char *)msg->payload,
|
|
msg->payload_len,
|
|
DCS_UNEXPECTED_INFORMATION_RECEIVED_TYPE,
|
|
"Bad directive");
|
|
msg_code = DUER_MSG_RSP_BAD_REQUEST;
|
|
} else if (msg->payload_len == 2
|
|
&& DUER_STRNCMP((const char *)msg->payload, "\r\n", 2) == 0) {
|
|
DUER_LOGW("Receive an empty message");
|
|
msg_code = DUER_MSG_RSP_INTERNAL_SERVER_ERROR;
|
|
} else {
|
|
duer_report_exception_internal((const char *)msg->payload,
|
|
msg->payload_len,
|
|
DCS_INTERNAL_ERROR_TYPE,
|
|
"Internal error");
|
|
msg_code = DUER_MSG_RSP_INTERNAL_SERVER_ERROR;
|
|
}
|
|
}
|
|
|
|
duer_response(msg, msg_code, NULL, 0);
|
|
|
|
if (payload) {
|
|
DUER_FREE(payload);
|
|
}
|
|
|
|
if (value) {
|
|
baidu_json_Delete(value);
|
|
}
|
|
|
|
return rs;
|
|
}
|
|
|
|
static duer_status_t duer_private_protocal_cb(duer_context ctx, duer_msg_t *msg, duer_addr_t *addr)
|
|
{
|
|
duer_status_t rs = DUER_OK;
|
|
baidu_json *value = NULL;
|
|
baidu_json *name = NULL;
|
|
baidu_json *name_space = NULL;
|
|
baidu_json *header = NULL;
|
|
baidu_json *directive = NULL;
|
|
baidu_json *client_context = NULL;
|
|
baidu_json *response_json = NULL;
|
|
char *response_data = NULL;
|
|
size_t response_data_size = 0;
|
|
duer_bool seperated_response = DUER_FALSE;
|
|
duer_msg_code_e msg_code = DUER_MSG_RSP_CHANGED;
|
|
int index = DUMMY_INDEX;
|
|
|
|
DUER_LOGV("Enter");
|
|
|
|
rs = duer_dcs_directive_parse(msg, &value, &directive, &header, &name_space, &name, NULL);
|
|
if (rs != DUER_OK) {
|
|
goto RET;
|
|
}
|
|
|
|
if (DUER_STRCMP(DCS_GET_STATUS_NAME, name->valuestring) == 0
|
|
&& DUER_STRCMP(DCS_PRIVATE_NAMESPACE, name_space->valuestring) == 0) {
|
|
if (msg->token_len > 0) {
|
|
DUER_LOGI("response, mid:%d", msg->msg_id);
|
|
duer_response(msg, DUER_MSG_EMPTY_MESSAGE, NULL, 0);// ack in empty message first!
|
|
seperated_response = DUER_TRUE;
|
|
}
|
|
DUER_DCS_CRITICAL_ENTER();
|
|
client_context = duer_get_client_context_internal();
|
|
DUER_DCS_CRITICAL_EXIT();
|
|
if (client_context) {
|
|
response_json = baidu_json_CreateObject();
|
|
if (response_json) {
|
|
baidu_json_AddItemToObjectCS(response_json, DCS_CLIENT_CONTEXT_KEY, client_context);
|
|
//response_data = baidu_json_PrintUnformatted(response_json);
|
|
//response_data_size = response_data ? DUER_STRLEN(response_data) : 0;
|
|
} else {
|
|
DUER_LOGE("Failed to create response msg: memory too low");
|
|
baidu_json_Delete(client_context);
|
|
rs = DUER_ERR_MEMORY_OVERFLOW;
|
|
}
|
|
}
|
|
} else {
|
|
index = duer_get_directive_index(value, name->valuestring);
|
|
rs = duer_handle_directive(directive, index, PRIVATE_PROTOCAL_DIRECTIVE);
|
|
}
|
|
|
|
RET:
|
|
|
|
if (rs != DUER_OK) {
|
|
if (rs == DUER_MSG_RSP_BAD_REQUEST) {
|
|
msg_code = DUER_MSG_RSP_BAD_REQUEST;
|
|
} else {
|
|
msg_code = DUER_MSG_RSP_INTERNAL_SERVER_ERROR;
|
|
}
|
|
}
|
|
|
|
if (seperated_response == DUER_FALSE) {
|
|
duer_response(msg, msg_code, response_data, response_data_size);
|
|
} else {
|
|
DUER_LOGI("seperated response, token_len:%d", msg->token_len);
|
|
duer_seperate_response((const char *)msg->token, msg->token_len, msg_code, response_json);
|
|
}
|
|
|
|
if (response_json) {
|
|
baidu_json_Delete(response_json);
|
|
}
|
|
|
|
if (response_data) {
|
|
DUER_FREE(response_data);
|
|
}
|
|
|
|
if (value) {
|
|
baidu_json_Delete(value);
|
|
}
|
|
|
|
return rs;
|
|
}
|
|
|
|
static duer_status_t duer_iot_cloud_cb(duer_context ctx, duer_msg_t *msg, duer_addr_t *addr)
|
|
{
|
|
duer_status_t rs = DUER_OK;
|
|
baidu_json *value = NULL;
|
|
baidu_json *directive = NULL;
|
|
duer_msg_code_e msg_code = DUER_MSG_RSP_CHANGED;
|
|
|
|
DUER_LOGV("Enter");
|
|
|
|
rs = duer_dcs_directive_parse(msg, &value, &directive, NULL, NULL, NULL, NULL);
|
|
if (rs == DUER_OK) {
|
|
rs = duer_execute_directive(directive);
|
|
}
|
|
|
|
if (rs != DUER_OK) {
|
|
if (rs == DUER_MSG_RSP_NOT_FOUND) {
|
|
msg_code = DUER_MSG_RSP_NOT_FOUND;
|
|
} else if (rs == DUER_MSG_RSP_BAD_REQUEST) {
|
|
msg_code = DUER_MSG_RSP_BAD_REQUEST;
|
|
} else {
|
|
msg_code = DUER_MSG_RSP_INTERNAL_SERVER_ERROR;
|
|
}
|
|
}
|
|
|
|
duer_response(msg, msg_code, NULL, 0);
|
|
|
|
if (value) {
|
|
baidu_json_Delete(value);
|
|
}
|
|
|
|
return rs;
|
|
}
|
|
|
|
void duer_dcs_dialog_cancel(void)
|
|
{
|
|
DUER_DCS_CRITICAL_ENTER();
|
|
if (s_is_initialized) {
|
|
duer_create_request_id_internal(DCS_DIALOG_NONE);
|
|
} else {
|
|
DUER_LOGW("DCS has not been initialized");
|
|
}
|
|
DUER_DCS_CRITICAL_EXIT();
|
|
}
|
|
|
|
static duer_status_t dummy_directive_cb(const baidu_json *directive)
|
|
{
|
|
return DUER_OK;
|
|
}
|
|
|
|
int duer_dcs_data_send(baidu_json *data)
|
|
{
|
|
return duer_data_report(data);
|
|
}
|
|
|
|
int duer_dcs_data_report(baidu_json *data)
|
|
{
|
|
return duer_dcs_data_report_internal(data, DUER_TRUE);
|
|
}
|
|
|
|
static duer_status_t duer_dlp_cb(duer_context ctx, duer_msg_t *msg, duer_addr_t *addr)
|
|
{
|
|
duer_status_t rs = DUER_OK;
|
|
baidu_json *value = NULL;
|
|
baidu_json *directive = NULL;
|
|
duer_msg_code_e msg_code = DUER_MSG_RSP_CHANGED;
|
|
|
|
DUER_LOGV("Enter");
|
|
|
|
rs = duer_dcs_directive_parse(msg, &value, &directive, NULL, NULL, NULL, NULL);
|
|
if (rs == DUER_OK) {
|
|
rs = duer_execute_directive(directive);
|
|
}
|
|
|
|
if (rs != DUER_OK) {
|
|
if (rs == DUER_MSG_RSP_NOT_FOUND) {
|
|
msg_code = DUER_MSG_RSP_NOT_FOUND;
|
|
} else if (rs == DUER_MSG_RSP_BAD_REQUEST) {
|
|
msg_code = DUER_MSG_RSP_BAD_REQUEST;
|
|
} else {
|
|
msg_code = DUER_MSG_RSP_INTERNAL_SERVER_ERROR;
|
|
}
|
|
}
|
|
|
|
duer_response(msg, msg_code, NULL, 0);
|
|
|
|
if (value) {
|
|
baidu_json_Delete(value);
|
|
}
|
|
|
|
return rs;
|
|
}
|
|
|
|
void duer_dcs_framework_init()
|
|
{
|
|
duer_res_t res[] = {
|
|
{
|
|
DUER_RES_MODE_DYNAMIC,
|
|
DUER_RES_OP_PUT,
|
|
(char *)DCS_DUER_DIRECTIVE_PATH,
|
|
{
|
|
duer_dcs_router
|
|
}
|
|
},
|
|
{
|
|
DUER_RES_MODE_DYNAMIC,
|
|
DUER_RES_OP_PUT,
|
|
(char *)DCS_DUER_PRIVATE_PATH,
|
|
{
|
|
duer_private_protocal_cb
|
|
}
|
|
},
|
|
{
|
|
DUER_RES_MODE_DYNAMIC,
|
|
DUER_RES_OP_PUT,
|
|
(char *)DCS_IOTCLOUD_DIRECTIVE_PATH,
|
|
{
|
|
duer_iot_cloud_cb
|
|
}
|
|
},
|
|
{
|
|
DUER_RES_MODE_DYNAMIC,
|
|
DUER_RES_OP_PUT,
|
|
(char *)DCS_DUER_DLP_PATH,
|
|
{
|
|
duer_dlp_cb
|
|
}
|
|
},
|
|
};
|
|
|
|
duer_add_resources(res, sizeof(res) / sizeof(res[0]));
|
|
duer_ds_e2e_set_dialog_id_cb(duer_get_request_id_internal);
|
|
duer_reg_dialog_id_cb(duer_get_request_id_internal);
|
|
|
|
duer_dcs_local_init_internal();
|
|
DUER_DCS_CRITICAL_ENTER();
|
|
|
|
if (s_is_initialized) {
|
|
DUER_DCS_CRITICAL_EXIT();
|
|
DUER_LOGW("DCS has been initialized");
|
|
return;
|
|
}
|
|
|
|
duer_dcs_sys_exit_internal();
|
|
|
|
if (!s_directive_queue) {
|
|
s_directive_queue = duer_qcache_create();
|
|
if (!s_directive_queue) {
|
|
DUER_LOGE("Failed to create DCS directive queue");
|
|
}
|
|
}
|
|
|
|
if (!s_directive_queue_lock) {
|
|
s_directive_queue_lock = duer_mutex_create();
|
|
if (!s_directive_queue_lock) {
|
|
DUER_LOGE("Failed to create s_directive_queue_lock");
|
|
}
|
|
}
|
|
|
|
duer_directive_list directive = {DCS_DIALOGUE_FINISHED_NAME, duer_dialog_finish_cb};
|
|
duer_add_dcs_directive_internal(&directive, 1, DCS_PRIVATE_NAMESPACE);
|
|
|
|
// Unnecessary directives might be received for some special reason, exception event will be
|
|
// reported to cloud if these directives have no handler. Hence we register default callbacks
|
|
// for them.
|
|
duer_directive_list list[] = {
|
|
{DCS_RENDER_PLAYER_INFO, dummy_directive_cb},
|
|
{DCS_RENDER_AUDIO_LIST, dummy_directive_cb},
|
|
{DCS_RENDER_ALBUM_LIST, dummy_directive_cb},
|
|
};
|
|
duer_add_dcs_directive_internal(list,
|
|
sizeof(list) / sizeof(list[0]),
|
|
DCS_SCREEN_EXTENDED_CARD_NAMESPACE);
|
|
|
|
duer_directive_list screen_directive[] = {
|
|
{DCS_RENDER_VOICE_INPUT_TEXT_NAME, dummy_directive_cb},
|
|
{DCS_RENDER_CARD_NAME, dummy_directive_cb},
|
|
};
|
|
duer_add_dcs_directive_internal(screen_directive,
|
|
sizeof(screen_directive) / sizeof(screen_directive[0]),
|
|
DCS_SCREEN_NAMESPACE);
|
|
|
|
s_is_initialized = DUER_TRUE;
|
|
|
|
duer_declare_sys_interface_internal();
|
|
duer_dcs_play_control_init_internal();
|
|
DUER_DCS_CRITICAL_EXIT();
|
|
}
|
|
|
|
void duer_dcs_uninitialize(void)
|
|
{
|
|
int i = 0;
|
|
int j = 0;
|
|
|
|
DUER_DCS_CRITICAL_ENTER();
|
|
|
|
if (!s_is_initialized) {
|
|
DUER_LOGW("DCS has not been initialized");
|
|
DUER_DCS_CRITICAL_EXIT();
|
|
return;
|
|
}
|
|
|
|
duer_dcs_sys_exit_internal();
|
|
s_is_initialized = DUER_FALSE;
|
|
|
|
while (i < s_namespace_count) {
|
|
if (s_directive_namespace_list[i].name_space) {
|
|
DUER_FREE(s_directive_namespace_list[i].name_space);
|
|
}
|
|
|
|
if (s_directive_namespace_list[i].list) {
|
|
for (j = 0; j < s_directive_namespace_list[i].count; j++) {
|
|
if (s_directive_namespace_list[i].list[j].directive_name) {
|
|
DUER_FREE((void *)s_directive_namespace_list[i].list[j].directive_name);
|
|
}
|
|
}
|
|
DUER_FREE(s_directive_namespace_list[i].list);
|
|
}
|
|
|
|
i++;
|
|
}
|
|
|
|
s_namespace_count = 0;
|
|
if (s_directive_namespace_list) {
|
|
DUER_FREE((void *)s_directive_namespace_list);
|
|
s_directive_namespace_list = NULL;
|
|
}
|
|
|
|
if (s_dcs_client_context_cb) {
|
|
DUER_FREE((void *)s_dcs_client_context_cb);
|
|
s_dcs_client_context_cb = NULL;
|
|
}
|
|
|
|
s_client_context_cb_count = 0;
|
|
|
|
duer_mutex_lock(s_directive_queue_lock);
|
|
if (s_directive_queue) {
|
|
duer_qcache_destroy(s_directive_queue);
|
|
s_directive_queue = NULL;
|
|
}
|
|
duer_mutex_unlock(s_directive_queue_lock);
|
|
|
|
duer_sys_interface_uninitialize_internal();
|
|
duer_dcs_alert_uninitialize_internal();
|
|
duer_dcs_audio_player_uninitialize_internal();
|
|
duer_dcs_device_control_uninitialize_internal();
|
|
duer_dcs_play_control_uninitialize_internal();
|
|
duer_dcs_infrared_control_uninitialize_internal();
|
|
duer_dcs_voice_output_uninitialize_internal();
|
|
duer_dcs_voice_input_uninitialize_internal();
|
|
duer_dcs_screen_uninitialize_internal();
|
|
duer_dcs_local_uninitialize_internal();
|
|
|
|
DUER_DCS_CRITICAL_EXIT();
|
|
}
|
|
|
|
baidu_json *duer_dcs_get_client_context(void)
|
|
{
|
|
baidu_json *client_context = NULL;
|
|
|
|
DUER_DCS_CRITICAL_ENTER();
|
|
client_context = duer_get_client_context_internal();
|
|
DUER_DCS_CRITICAL_EXIT();
|
|
|
|
return client_context;
|
|
}
|