diff options
author | Naveen Bobbili <nbobbili@amazon.com> | 2019-04-28 20:51:16 -0700 |
---|---|---|
committer | Jan-Simon Möller <jsmoeller@linuxfoundation.org> | 2019-11-12 15:32:46 +0100 |
commit | 0349f05f5885987952a2d8de03983b36722b264e (patch) | |
tree | 95c2f3a30447831deda72625c8a60f077ac671ee /homescreen/src/chromecontroller.cpp | |
parent | 0bdd39b247661c1a0406d450d578d4ff3fd171b0 (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.cpp | 159 |
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; + } +} |