aboutsummaryrefslogtreecommitdiffstats
path: root/homescreen/src/chromecontroller.cpp
diff options
context:
space:
mode:
authorNaveen Bobbili <nbobbili@amazon.com>2019-04-28 20:51:16 -0700
committerJan-Simon Möller <jsmoeller@linuxfoundation.org>2019-11-12 15:32:46 +0100
commit0349f05f5885987952a2d8de03983b36722b264e (patch)
tree95c2f3a30447831deda72625c8a60f077ac671ee /homescreen/src/chromecontroller.cpp
parent0bdd39b247661c1a0406d450d578d4ff3fd171b0 (diff)
Add push to talk support to homescreen
Reworked version of Alexa specific changes from ICS to add push to talk button for voice services to homescreen media area. v2: change config.xml to audiomixer v3: reworked to not be Alexa specific: - Now use the default voiceagent if available, instead of hard-coding Alexa usage - The Alexa logo for the button has been replaced with a generic microphone icon derived from the radio application's launcher icon. This is a placeholder until a new icon is provided by LF graphics team. Meeting any Amazon requirements around Alexa chrome is now envisioned as being provided for with a TBD voiceagent API enhancement. - The QML for the PTT button has been moved to MediaAreaBlank.qml, which seems a more logical location for it ATM. It is likely that the MediaArea QML should be simplified in a future change, as it currently contains a signficant amount of unused code. - The PTT button has been moved to the left hand side of the media area, as this seems more sensible if demonstrating driver usage. - The delay on fade-out of the master volume slider has been lowered to 3 seconds from 5, with the PTT button present it started seeming excessive during testing. - Some extra debug messages have been added to make tracking the voiceagent state more straightforward. Bug-AGL: SPEC-2764, Signed-off-by: Naveen Bobbili <nbobbili@amazon.com> Signed-off-by: Jan-Simon Moeller <jsmoeller@linuxfoundation.org> Signed-off-by: Scott Murray <scott.murray@konsulko.com> Change-Id: I398bf7aebc5c9b459b1fce94511eee3698c08347
Diffstat (limited to 'homescreen/src/chromecontroller.cpp')
-rw-r--r--homescreen/src/chromecontroller.cpp159
1 files changed, 159 insertions, 0 deletions
diff --git a/homescreen/src/chromecontroller.cpp b/homescreen/src/chromecontroller.cpp
new file mode 100644
index 0000000..b604dae
--- /dev/null
+++ b/homescreen/src/chromecontroller.cpp
@@ -0,0 +1,159 @@
+#include "chromecontroller.h"
+#include "aglsocketwrapper.h"
+#include "constants.h"
+
+#include <QTimer>
+#include <QDebug>
+#include <QJsonDocument>
+
+ChromeController::ChromeController(const QUrl &bindingUrl, QObject *parent) :
+ QObject(parent)
+ , m_aglSocket(new AglSocketWrapper(this))
+{
+ //Alexa voice agent subscription----------------------------------------------------------------
+ {
+ connect(m_aglSocket, &AglSocketWrapper::connected,
+ this, [this]() -> void {
+ m_aglSocket->apiCall(vshl::API, vshl::VOICE_AGENT_ENUMERATION_VERB, QJsonValue(),
+ [this](bool result, const QJsonValue &data) -> void {
+ qDebug() << (vshl::API + QLatin1String(":") + vshl::VOICE_AGENT_ENUMERATION_VERB)
+ << "result: " << result << " val: " << data;
+ if (!result) {
+ qWarning() << "Failed to enumerate voice agents";
+ return;
+ }
+
+ QJsonObject dataObj = data.toObject();
+ auto objIt = dataObj.find(vshl::RESPONSE_TAG);
+ if (objIt == dataObj.constEnd()) {
+ qWarning() << "Voice agent enumeration response tag missing."
+ << dataObj;
+ return;
+ }
+
+ // Get default voice agent
+ dataObj = objIt.value().toObject();
+ QJsonObject responseObj = dataObj;
+ objIt = dataObj.find(vshl::DEFAULT_TAG);
+ if (objIt == dataObj.constEnd()) {
+ qWarning() << "Voice agent enumeration default agent tag missing."
+ << dataObj;
+ return;
+ }
+ QString agentId = objIt.value().toString();
+ if (agentId.isEmpty()) {
+ qWarning() << "Default voice agent not found";
+ return;
+ }
+ qDebug() << (vshl::API + QLatin1String(":") + vshl::VOICE_AGENT_ENUMERATION_VERB) << "default: " << agentId;
+
+ objIt = dataObj.find(vshl::AGENTS_TAG);
+ if (objIt == dataObj.constEnd()) {
+ qWarning() << "Voice agent enumeration agents tag missing."
+ << dataObj;
+ return;
+ }
+
+ // Sanity check that the default agent is actually listed
+ bool agentFound = false;
+ const QJsonArray agents = objIt.value().toArray();
+ for (const QJsonValue &agent : agents) {
+ const QJsonObject agentObj = agent.toObject();
+ auto agentIt = agentObj.find(vshl::ID_TAG);
+ if (agentIt == agentObj.constEnd())
+ continue;
+ if (agentId.compare(agentIt.value().toString()) == 0) {
+ agentFound = true;
+ break;
+ }
+ }
+ if (!agentFound) {
+ qWarning() << "Default voice agent configuration not found";
+ return;
+ }
+ m_agentPresent = true;
+ emit agentPresentChanged();
+
+ //Voice agent subscription------------------------------------------------------
+ {
+ m_voiceAgentId = agentId;
+ const QJsonObject args {
+ { vshl::VOICE_AGENT_ID_ARG, agentId },
+ { vshl::VOICE_AGENT_EVENTS_ARG, vshl::VOICE_AGENT_EVENTS_ARRAY }
+ };
+ m_aglSocket->apiCall(vshl::API, vshl::SUBSCRIBE_VERB, args,
+ [](bool result, const QJsonValue &data) -> void {
+ qDebug() << (vshl::API + QLatin1String(":") + vshl::SUBSCRIBE_VERB)
+ << "result: " << result << " val: " << data;
+ });
+ }
+ //------------------------------------------------------------------------------
+ });
+ });
+ }
+ //----------------------------------------------------------------------------------------------<
+
+ //Socket connection management------------------------------------------------------------------
+ {
+ auto connectToBinding = [bindingUrl, this]() -> void {
+ m_aglSocket->open(bindingUrl);
+ qDebug() << "Connecting to:" << bindingUrl;
+ };
+ connect(m_aglSocket, &AglSocketWrapper::disconnected, this, [connectToBinding]() -> void {
+ QTimer::singleShot(2500, connectToBinding);
+ });
+ connectToBinding();
+ }
+ //----------------------------------------------------------------------------------------------
+
+ //Speech chrome state change event handling-----------------------------------------------------
+ {
+ connect(m_aglSocket, &AglSocketWrapper::eventReceived,
+ this, [this](const QString &eventName, const QJsonValue &data) -> void {
+ if (eventName.compare(vshl::VOICE_DIALOG_STATE_EVENT + m_voiceAgentId) == 0) {
+ const QJsonObject dataObj = QJsonDocument::fromJson(data.toString().toUtf8()).object();
+ auto objIt = dataObj.find(vshl::STATE_TAG);
+ if (objIt == dataObj.constEnd()) {
+ qWarning() << "Voice dialog state event state missing.";
+ return;
+ }
+ const QString stateStr = objIt.value().toString();
+ if (stateStr.compare(vshl::VOICE_DIALOG_IDLE) == 0) {
+ setChromeState(Idle);
+ } else if (stateStr.compare(vshl::VOICE_DIALOG_LISTENING) == 0) {
+ setChromeState(Listening);
+ } else if (stateStr.compare(vshl::VOICE_DIALOG_THINKING) == 0) {
+ setChromeState(Thinking);
+ } else if (stateStr.compare(vshl::VOICE_DIALOG_SPEAKING) == 0) {
+ setChromeState(Speaking);
+ } else if (stateStr.compare(vshl::VOICE_DIALOG_MICROPHONEOFF) == 0) {
+ setChromeState(MicrophoneOff);
+ }
+ }
+ });
+ }
+ //----------------------------------------------------------------------------------------------
+}
+
+void ChromeController::pushToTalk()
+{
+ m_aglSocket->apiCall(vshl::API, vshl::TAP_TO_TALK_VERB, QJsonValue(),
+ [](bool result, const QJsonValue &data) -> void {
+ qDebug() << (vshl::API + QLatin1String(":") + vshl::TAP_TO_TALK_VERB)
+ << "result: " << result << " val: " << data;
+ });
+}
+
+void ChromeController::setChromeState(ChromeController::ChromeState state)
+{
+ const char* ChromeStateNames[MicrophoneOff + 1] = { "Idle", "Listening", "Thinking", "Speaking", "MicrophoneOff" };
+
+ if (m_chromeState != state) {
+ m_chromeState = state;
+ emit chromeStateChanged();
+ if(state <= MicrophoneOff)
+ qDebug() << "new state = " << ChromeStateNames[state];
+ else
+ qDebug() << "new state = " << state;
+ }
+}