From b6abca2edcb36c0c0848d1cd8dc291f23293aa80 Mon Sep 17 00:00:00 2001 From: Naveen Bobbili Date: Mon, 12 Nov 2018 16:12:38 -0800 Subject: SPEC-1924: AGL Speech Framework's Voice Service High Level 1.0 Release. Details: 1) Control plugin implementation for VSHL 1.0 2) Exposed APIs that are documented in the confluence page https://confluence.automotivelinux.org/display/SPE/Speech+EG+Architecture 3) Implemented 39 unit tests based on GTest framework to test all the low level components of VSHL binding. 4) Implemented a HTML5 based VSHL API tester application to test VSHL APIs. API specification: https://confluence.automotivelinux.org/display/SPE/Speech+EG+Architecture#SpeechEGArchitecture-HighLevelVoiceService Test performed: 1) Tested AGL service running Alexa Auto SDK https://github.com/alexa/aac-sdk on Ubuntu 16.04 and Renesas R-Car M3 board. License: Apache 2.0 Developers/Owners: Naveen Bobbili (nbobbili@amazon.com) Prakash Buddhiraja (buddhip@amazon.com) Shotaro Uchida (shotaru@amazon.co.jp) Change-Id: I3370f4ad65aff030f24f4ad571fb02d525bbfbca Signed-off-by: Naveen Bobbili --- htdocs/binding.js | 226 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 226 insertions(+) create mode 100644 htdocs/binding.js (limited to 'htdocs/binding.js') diff --git a/htdocs/binding.js b/htdocs/binding.js new file mode 100644 index 0000000..c24d62e --- /dev/null +++ b/htdocs/binding.js @@ -0,0 +1,226 @@ +var afb = new AFB("api", "mysecret"); +var ws; +var evtIdx = 0; +var count = 0; + + +//********************************************** +// Logger +//********************************************** +var log = { + command: function (api, verb, query) { + console.log("subscribe api=" + api + " verb=" + verb + " query=", query); + var question = urlWS + "/" + api + "/" + verb + "?query=" + JSON.stringify(query); + log._write("question", count + ": " + log.syntaxHighlight(question)); + }, + + event: function (obj) { + console.log("gotevent:" + JSON.stringify(obj)); + log._write("outevt", (evtIdx++) + ": " + JSON.stringify(obj)); + }, + + reply: function (obj) { + console.log("replyok:" + JSON.stringify(obj)); + log._write("output", count + ": OK: " + log.syntaxHighlight(obj)); + }, + + error: function (obj) { + console.log("replyerr:" + JSON.stringify(obj)); + log._write("output", count + ": ERROR: " + log.syntaxHighlight(obj)); + }, + + _write: function (element, msg) { + var el = document.getElementById(element); + el.innerHTML += msg + '\n'; + + // auto scroll down + setTimeout(function () { + el.scrollTop = el.scrollHeight; + }, 100); + }, + + syntaxHighlight: function (json) { + if (typeof json !== 'string') { + json = JSON.stringify(json, undefined, 2); + } + json = json.replace(/&/g, '&').replace(//g, '>'); + return json.replace(/("(\\u[a-zA-Z0-9]{4}|\\[^u]|[^\\"])*"(\s*:)?|\b(true|false|null)\b|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?)/g, function (match) { + var cls = 'number'; + if (/^"/.test(match)) { + if (/:$/.test(match)) { + cls = 'key'; + } else { + cls = 'string'; + } + } else if (/true|false/.test(match)) { + cls = 'boolean'; + } else if (/null/.test(match)) { + cls = 'null'; + } + return '' + match + ''; + }); + }, +}; + +//********************************************** +// Generic function to call binder +//*********************************************** +function callbinder(api, verb, query) { + log.command(api, verb, query); + + // ws.call return a Promise + return ws.call(api + '/' + verb, query) + .then(function (res) { + log.reply(res); + count++; + return res; + }) + .catch(function (err) { + log.reply(err); + count++; + throw err; + }); +}; + +//********************************************** +// Init - establish Websocket connection +//********************************************** +function init(elemID, api, verb, query) { + + function onopen() { + document.getElementById("main").style.visibility = "visible"; + document.getElementById("connected").innerHTML = "Binder WS Active"; + document.getElementById("connected").style.background = "lightgreen"; + ws.onevent("*", log.event); + } + + function onabort() { + document.getElementById("main").style.visibility = "hidden"; + document.getElementById("connected").innerHTML = "Connected Closed"; + document.getElementById("connected").style.background = "red"; + } + + ws = new afb.ws(onopen, onabort); +} + +function clearPre(preId) { + const pre = document.getElementById(preId); + while (pre && pre.firstChild) { + pre.removeChild(pre.firstChild); + } +} + +function fetchAndRenderVoiceAgents() { + const agentsDiv = document.getElementById('agentsDiv'); + while (agentsDiv.firstChild) { + agentsDiv.removeChild(agentsDiv.firstChild); + } + + const api = 'vshl'; + const verb = 'enumerateVoiceAgents'; + const query = {}; + + log.command(api, verb, query); + + return ws.call(api + '/' + verb, query) + .then(function (res) { + log.reply(res); + for (let index = 0; index < res.response.agents.length; ++index) { + let voiceAgent = res.response.agents[index]; + addVoiceAgent(agentsDiv, voiceAgent, res.response.default == voiceAgent.id); + } + }) + .catch(function (err) { + log.reply(err); + console.log(JSON.stringify(err)); + }); +} + +function addVoiceAgent(containerDiv, voiceAgent, isDefault) { + const agentDiv = document.createElement("div"); + + const agentName = document.createElement("h2"); + agentName.innerHTML = voiceAgent.name; + agentDiv.appendChild(agentName); + + const agentDescription = document.createElement("p"); + agentDescription.innerHTML = voiceAgent.description; + agentDiv.appendChild(agentDescription); + + if (!isDefault) { + const setDefaultBtn = document.createElement("button"); + setDefaultBtn.addEventListener('click', (evt) => { + const query = {"id": voiceAgent.id}; + callbinder('vshl', 'setDefaultVoiceAgent', query); + fetchAndRenderVoiceAgents(); + }); + setDefaultBtn.innerHTML = 'SetDefault'; + agentDiv.appendChild(setDefaultBtn); + } + + const subscribeBtn = document.createElement("button"); + subscribeBtn.addEventListener('click', (evt) => { + showAgentEventChooserDialog(voiceAgent.id); + }); + subscribeBtn.innerHTML = 'Subscribe'; + agentDiv.appendChild(subscribeBtn); + + containerDiv.appendChild(agentDiv); +} + +function showAgentEventChooserDialog(voiceAgentId) { + const modal = document.getElementById('agent-event-chooser'); + const subscribeBtn = document.getElementById('agent-subscribe-btn'); + + subscribeBtn.addEventListener('click', (evt) => { + const authState = document.getElementById('authstate').checked; + const dialogState = document.getElementById('dialogstate').checked; + const connectionState = document.getElementById('connectionstate').checked; + + const query = { + "va_id": voiceAgentId, + "events":[] + }; + if (authState) + query.events.push('voice_authstate_event'); + if (dialogState) + query.events.push('voice_dialogstate_event'); + if (connectionState) + query.events.push('voice_connectionstate_event'); + + callbinder('vshl', 'subscribe', query); + modal.close(); + }); + + // makes modal appear (adds `open` attribute) + modal.showModal(); +} + +function showTemplateUIEventChooserDialog() { + const modal = document.getElementById('templateui-event-chooser'); + const subscribeBtn = document.getElementById('templateui-subscribe-btn'); + + subscribeBtn.addEventListener('click', (evt) => { + const renderTemplate = document.getElementById('render_template').checked; + const clearTemplate = document.getElementById('clear_template').checked; + const renderPlayerInfo = document.getElementById('render_player_info').checked; + const clearPlayerInfo = document.getElementById('clear_player_info').checked; + + const query = {"actions":[]}; + + if (renderTemplate) + query.actions.push('render_template'); + if (clearTemplate) + query.actions.push('clear_template'); + if (renderPlayerInfo) + query.actions.push('render_player_info'); + if (clearPlayerInfo) + query.actions.push('clear_player_info'); + + callbinder('vshl', 'guiMetadata/subscribe', query); + modal.close(); + }); + + // makes modal appear (adds `open` attribute) + modal.showModal(); +} \ No newline at end of file -- cgit 1.2.3-korg