aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorScott Murray <scott.murray@konsulko.com>2019-12-29 21:05:27 -0500
committerScott Murray <scott.murray@konsulko.com>2019-12-30 01:58:35 +0000
commitdc5104d4254c9789a9b1ebce4543f0558e56aaac (patch)
treeb2555bf9bf36d1dbab531c88f3e1bba3681ddc3b /src
parented834a643e3843c0f805ea33363c9f2889d2bab3 (diff)
Add signal-composer voice event support
Add support for triggering listening (push-to-talk/PTT) via the signal-composer "event.voice" event. This enables PTT from the steering wheel for the CES demo. Note that this relies on a fix to signal-composer to add the session context uuid to the replies from event subscribe calls. Without that, it's not feasible to catch the signal-composer events with the libappcontroller event scheme and some more significant rework would be required. Bug-AGL: SPEC-3048 Signed-off-by: Scott Murray <scott.murray@konsulko.com> Change-Id: I22c7265c2f08ecc0a598fd88ddf4fd53f8c3e880
Diffstat (limited to 'src')
-rw-r--r--src/plugins/VshlCoreApi.cpp108
-rw-r--r--src/plugins/VshlCoreApi.h2
2 files changed, 110 insertions, 0 deletions
diff --git a/src/plugins/VshlCoreApi.cpp b/src/plugins/VshlCoreApi.cpp
index abe4577..b14f949 100644
--- a/src/plugins/VshlCoreApi.cpp
+++ b/src/plugins/VshlCoreApi.cpp
@@ -66,6 +66,11 @@ static std::unique_ptr<vshlcore::utilities::events::EventRouter> sEventRouter;
using json = nlohmann::json;
using Level = vshlcore::utilities::logging::Logger::Level;
+static const char *signalcomposer_events[] = {
+ "event.voice",
+ NULL,
+};
+
CTLP_ONLOAD(plugin, ret) {
if (plugin->api == nullptr) {
return -1;
@@ -195,6 +200,29 @@ CTLP_CAPI(onLoginPairExpiredEvent, source, argsJ, eventJ) {
return 0;
}
+CTLP_CAPI(onVoiceTriggerEvent, source, argsJ, eventJ) {
+ if (sVRRequestProcessor == nullptr) {
+ return -1;
+ }
+
+ json eventJson = json::parse(json_object_to_json_string(eventJ));
+ if (eventJson.find("uid") == eventJson.end()) {
+ sLogger->log(Level::ERROR, TAG, "onVoiceTriggerEvent: No uid found.");
+ return -1;
+ }
+ if (eventJson.find("value") == eventJson.end()) {
+ sLogger->log(Level::ERROR, TAG, "onVoiceTriggerEvent: No value found.");
+ return -1;
+ }
+ std::string uid(eventJson["uid"].get<std::string>());
+ bool value(eventJson["value"].get<bool>());
+ if (uid == "event.voice" && value == true) {
+ sVRRequestProcessor->startListening();
+ }
+
+ return 0;
+}
+
// Helper function to add events for voice agent to controller
// configuration. It relies on the controller configuration being
// available via the userdata of the API pointer.
@@ -406,6 +434,86 @@ CTLP_CAPI(loadVoiceAgentsConfig, source, argsJ, eventJ) {
return 0;
}
+// Helper function to add signal composer events for voice triggers to
+// controller configuration. It relies on the controller configuration
+// being available via the userdata of the API pointer.
+static int AddVoiceTriggerEvents(std::string &agentApi, std::string &uuid) {
+ // Retrieve section config from api handle
+ CtlConfigT *ctrlConfig = (CtlConfigT*) afb_api_get_userdata(sAfbApi->getApi());
+ if (ctrlConfig == nullptr) {
+ sLogger->log(Level::ERROR, TAG, "AddVoiceAgentEvents: ctrlConfig == nullptr");
+ return -1;
+ }
+
+ CtlSectionT* section = nullptr;
+ for (int idx = 0; ctrlConfig->sections[idx].key != NULL; ++idx) {
+ if (!strcasecmp(ctrlConfig->sections[idx].key, "events")) {
+ section = &(ctrlConfig->sections[idx]);
+ break;
+ }
+ }
+ if (section == nullptr) {
+ sLogger->log(Level::ERROR, TAG, "AddVoiceTriggerEvents: events section not found");
+ return -1;
+ }
+
+ // Fill out events JSON array to pass to the controller
+ json_object* eventsJ = json_object_new_array();
+
+ json_object *eventJ = json_object_new_object();
+ std::string uid = agentApi + "/" + uuid;
+ json_object *uidJ = json_object_new_string(uid.c_str());
+ json_object_object_add(eventJ, "uid", uidJ);
+ json_object *actionJ = json_object_new_string("plugin://vshl-core#onVoiceTriggerEvent");
+ json_object_object_add(eventJ, "action", actionJ);
+ json_object_array_add(eventsJ, eventJ);
+
+ // Call into controller to add event actions
+ // NOTE: AFAICT the JSON objects end up reused by the controller data
+ // structures, so eventsJ should not be freed with a put after
+ // this call.
+ int rc = AddActionsToSection(sAfbApi->getApi(), section, eventsJ, 0);
+ if (rc != 0) {
+ stringstream message;
+ message << "AddVoiceTriggerEvents: AddActionsToSection rc = " << rc;
+ sLogger->log(Level::WARNING, TAG, message.str().c_str());
+ }
+ return rc;
+}
+
+CTLP_CAPI(subscribeVoiceTriggerEvents, source, argsJ, eventJ) {
+ // Subscribe to signal-composer voice/PTT events
+ const char **tmp = signalcomposer_events;
+ json_object *args = json_object_new_object();
+ json_object *signals = json_object_new_array();
+
+ while (*tmp) {
+ json_object_array_add(signals, json_object_new_string(*tmp++));
+ }
+ json_object_object_add(args, "signal", signals);
+ if (json_object_array_length(signals)) {
+ struct json_object *responseJ;
+ int rc = afb_api_call_sync(sAfbApi->getApi(), "signal-composer",
+ "subscribe", args, &responseJ, NULL, NULL);
+ if (rc == 0 && responseJ) {
+ struct json_object *uuidJ;
+ json_object_object_get_ex(responseJ, "uuid", &uuidJ);
+ if (uuidJ) {
+ std::string uuid(json_object_get_string(uuidJ));
+ std::string api("signal-composer");
+ AddVoiceTriggerEvents(api, uuid);
+ }
+ }
+ if (responseJ)
+ json_object_put(responseJ);
+ } else {
+ json_object_put(args);
+ }
+
+ // Always return zero so service will start
+ return 0;
+}
+
CTLP_CAPI(startListening, source, argsJ, eventJ) {
if (sVoiceAgentsDataManager == nullptr) {
return -1;
diff --git a/src/plugins/VshlCoreApi.h b/src/plugins/VshlCoreApi.h
index eb90190..7c5bf69 100644
--- a/src/plugins/VshlCoreApi.h
+++ b/src/plugins/VshlCoreApi.h
@@ -29,7 +29,9 @@ int onConnectionStateEvent(CtlSourceT* source, json_object* argsJ, json_object*
int onDialogStateEvent(CtlSourceT* source, json_object* argsJ, json_object* queryJ);
int onLoginPairReceivedEvent(CtlSourceT* source, json_object* argsJ, json_object* queryJ);
int onLoginPairExpiredEvent(CtlSourceT* source, json_object* argsJ, json_object* queryJ);
+int onVoiceTriggerEvent(CtlSourceT* source, json_object* argsJ, json_object* queryJ);
int loadVoiceAgentsConfig(CtlSourceT* source, json_object* argsJ, json_object* queryJ);
+int subscribeVoiceTriggerEvents(CtlSourceT* source, json_object* argsJ, json_object* queryJ);
int startListening(CtlSourceT* source, json_object* argsJ, json_object* queryJ);
int cancelListening(CtlSourceT* source, json_object* argsJ, json_object* queryJ);
int enumerateVoiceAgents(CtlSourceT* source, json_object* argsJ, json_object* queryJ);