1 #include "chromecontroller.h"
2 #include "aglsocketwrapper.h"
7 #include <QJsonDocument>
9 ChromeController::ChromeController(const QUrl &bindingUrl, QObject *parent) :
11 , m_aglSocket(new AglSocketWrapper(this))
13 //Alexa voice agent subscription----------------------------------------------------------------
15 connect(m_aglSocket, &AglSocketWrapper::connected,
16 this, [this]() -> void {
17 m_aglSocket->apiCall(vshl::API, vshl::VOICE_AGENT_ENUMERATION_VERB, QJsonValue(),
18 [this](bool result, const QJsonValue &data) -> void {
19 qDebug() << (vshl::API + QLatin1String(":") + vshl::VOICE_AGENT_ENUMERATION_VERB)
20 << "result: " << result << " val: " << data;
22 qWarning() << "Failed to enumerate voice agents";
26 QJsonObject dataObj = data.toObject();
27 auto objIt = dataObj.find(vshl::RESPONSE_TAG);
28 if (objIt == dataObj.constEnd()) {
29 qWarning() << "Voice agent enumeration response tag missing."
34 // Get default voice agent
35 dataObj = objIt.value().toObject();
36 QJsonObject responseObj = dataObj;
37 objIt = dataObj.find(vshl::DEFAULT_TAG);
38 if (objIt == dataObj.constEnd()) {
39 qWarning() << "Voice agent enumeration default agent tag missing."
43 QString agentId = objIt.value().toString();
44 if (agentId.isEmpty()) {
45 qWarning() << "Default voice agent not found";
48 qDebug() << (vshl::API + QLatin1String(":") + vshl::VOICE_AGENT_ENUMERATION_VERB) << "default: " << agentId;
50 objIt = dataObj.find(vshl::AGENTS_TAG);
51 if (objIt == dataObj.constEnd()) {
52 qWarning() << "Voice agent enumeration agents tag missing."
57 // Sanity check that the default agent is actually listed
58 bool agentFound = false;
59 const QJsonArray agents = objIt.value().toArray();
60 for (const QJsonValue &agent : agents) {
61 const QJsonObject agentObj = agent.toObject();
62 auto agentIt = agentObj.find(vshl::ID_TAG);
63 if (agentIt == agentObj.constEnd())
65 if (agentId.compare(agentIt.value().toString()) == 0) {
67 auto nameIt = agentObj.find(vshl::NAME_TAG);
68 if (nameIt != agentObj.constEnd()) {
69 m_voiceAgentName = nameIt.value().toString();
70 emit agentNameChanged();
76 qWarning() << "Default voice agent configuration not found";
79 m_agentPresent = true;
80 emit agentPresentChanged();
82 //Voice agent subscription------------------------------------------------------
84 m_voiceAgentId = agentId;
85 const QJsonObject args {
86 { vshl::VOICE_AGENT_ID_ARG, agentId },
87 { vshl::VOICE_AGENT_EVENTS_ARG, vshl::VOICE_AGENT_EVENTS_ARRAY }
89 m_aglSocket->apiCall(vshl::API, vshl::SUBSCRIBE_VERB, args,
90 [](bool result, const QJsonValue &data) -> void {
91 qDebug() << (vshl::API + QLatin1String(":") + vshl::SUBSCRIBE_VERB)
92 << "result: " << result << " val: " << data;
95 //------------------------------------------------------------------------------
99 //----------------------------------------------------------------------------------------------<
101 //Socket connection management------------------------------------------------------------------
103 auto connectToBinding = [bindingUrl, this]() -> void {
104 m_aglSocket->open(bindingUrl);
105 qDebug() << "Connecting to:" << bindingUrl;
107 connect(m_aglSocket, &AglSocketWrapper::disconnected, this, [connectToBinding]() -> void {
108 QTimer::singleShot(2500, connectToBinding);
112 //----------------------------------------------------------------------------------------------
114 //Speech chrome state change event handling-----------------------------------------------------
116 connect(m_aglSocket, &AglSocketWrapper::eventReceived,
117 this, [this](const QString &eventName, const QJsonValue &data) -> void {
118 if (eventName.compare(vshl::VOICE_DIALOG_STATE_EVENT + m_voiceAgentId) == 0) {
119 const QJsonObject dataObj = data.toObject();
120 auto objIt = dataObj.find(vshl::STATE_TAG);
121 if (objIt == dataObj.constEnd()) {
122 qWarning() << "Voice dialog state event state missing.";
125 const QString stateStr = objIt.value().toString();
126 if (stateStr.compare(vshl::VOICE_DIALOG_IDLE) == 0) {
127 setChromeState(Idle);
128 } else if (stateStr.compare(vshl::VOICE_DIALOG_LISTENING) == 0) {
129 setChromeState(Listening);
130 } else if (stateStr.compare(vshl::VOICE_DIALOG_THINKING) == 0) {
131 setChromeState(Thinking);
132 } else if (stateStr.compare(vshl::VOICE_DIALOG_SPEAKING) == 0) {
133 setChromeState(Speaking);
134 } else if (stateStr.compare(vshl::VOICE_DIALOG_MICROPHONEOFF) == 0) {
135 setChromeState(MicrophoneOff);
140 //----------------------------------------------------------------------------------------------
143 void ChromeController::pushToTalk()
145 m_aglSocket->apiCall(vshl::API, vshl::TAP_TO_TALK_VERB, QJsonValue(),
146 [](bool result, const QJsonValue &data) -> void {
147 qDebug() << (vshl::API + QLatin1String(":") + vshl::TAP_TO_TALK_VERB)
148 << "result: " << result << " val: " << data;
152 void ChromeController::setChromeState(ChromeController::ChromeState state)
154 const char* ChromeStateNames[MicrophoneOff + 1] = { "Idle", "Listening", "Thinking", "Speaking", "MicrophoneOff" };
156 if (m_chromeState != state) {
157 m_chromeState = state;
158 emit chromeStateChanged();
159 if(state <= MicrophoneOff)
160 qDebug() << "new state = " << ChromeStateNames[state];
162 qDebug() << "new state = " << state;