b604daea6bd7caeeb9f5e3308c48ae6aa6aaaae7
[apps/homescreen.git] / homescreen / src / chromecontroller.cpp
1 #include "chromecontroller.h"
2 #include "aglsocketwrapper.h"
3 #include "constants.h"
4
5 #include <QTimer>
6 #include <QDebug>
7 #include <QJsonDocument>
8
9 ChromeController::ChromeController(const QUrl &bindingUrl, QObject *parent) :
10     QObject(parent)
11   , m_aglSocket(new AglSocketWrapper(this))
12 {
13     //Alexa voice agent subscription----------------------------------------------------------------
14     {
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;
21                     if (!result) {
22                         qWarning() << "Failed to enumerate voice agents";
23                         return;
24                     }
25
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."
30                                    << dataObj;
31                         return;
32                     }
33
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."
40                                    << dataObj;
41                         return;
42                     }
43                     QString agentId = objIt.value().toString();
44                     if (agentId.isEmpty()) {
45                         qWarning() << "Default voice agent not found";
46                         return;
47                     }
48                     qDebug() << (vshl::API + QLatin1String(":") + vshl::VOICE_AGENT_ENUMERATION_VERB) << "default: " << agentId;
49
50                     objIt = dataObj.find(vshl::AGENTS_TAG);
51                     if (objIt == dataObj.constEnd()) {
52                         qWarning() << "Voice agent enumeration agents tag missing."
53                                    << dataObj;
54                         return;
55                     }
56
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())
64                             continue;
65                         if (agentId.compare(agentIt.value().toString()) == 0) {
66                             agentFound = true;
67                             break;
68                         }
69                     }
70                     if (!agentFound) {
71                         qWarning() << "Default voice agent configuration not found";
72                         return;
73                     }
74                     m_agentPresent = true;
75                     emit agentPresentChanged();
76
77                     //Voice agent subscription------------------------------------------------------
78                     {
79                         m_voiceAgentId = agentId;
80                         const QJsonObject args {
81                             { vshl::VOICE_AGENT_ID_ARG, agentId },
82                             { vshl::VOICE_AGENT_EVENTS_ARG, vshl::VOICE_AGENT_EVENTS_ARRAY }
83                         };
84                         m_aglSocket->apiCall(vshl::API, vshl::SUBSCRIBE_VERB, args,
85                         [](bool result, const QJsonValue &data) -> void {
86                             qDebug() << (vshl::API + QLatin1String(":") + vshl::SUBSCRIBE_VERB)
87                                      << "result: " << result << " val: " << data;
88                         });
89                     }
90                     //------------------------------------------------------------------------------
91                 });
92             });
93     }
94     //----------------------------------------------------------------------------------------------<
95
96     //Socket connection management------------------------------------------------------------------
97     {
98     auto connectToBinding = [bindingUrl, this]() -> void {
99         m_aglSocket->open(bindingUrl);
100         qDebug() << "Connecting to:" << bindingUrl;
101     };
102     connect(m_aglSocket, &AglSocketWrapper::disconnected, this, [connectToBinding]() -> void {
103                 QTimer::singleShot(2500, connectToBinding);
104             });
105     connectToBinding();
106     }
107     //----------------------------------------------------------------------------------------------
108
109     //Speech chrome state change event handling-----------------------------------------------------
110     {
111     connect(m_aglSocket, &AglSocketWrapper::eventReceived,
112             this, [this](const QString &eventName, const QJsonValue &data) -> void {
113         if (eventName.compare(vshl::VOICE_DIALOG_STATE_EVENT + m_voiceAgentId) == 0) {
114             const QJsonObject dataObj = QJsonDocument::fromJson(data.toString().toUtf8()).object();
115             auto objIt = dataObj.find(vshl::STATE_TAG);
116             if (objIt == dataObj.constEnd()) {
117                 qWarning() << "Voice dialog state event state missing.";
118                 return;
119             }
120             const QString stateStr = objIt.value().toString();
121             if (stateStr.compare(vshl::VOICE_DIALOG_IDLE) == 0) {
122                 setChromeState(Idle);
123             } else if (stateStr.compare(vshl::VOICE_DIALOG_LISTENING) == 0) {
124                 setChromeState(Listening);
125             } else if (stateStr.compare(vshl::VOICE_DIALOG_THINKING) == 0) {
126                 setChromeState(Thinking);
127             } else if (stateStr.compare(vshl::VOICE_DIALOG_SPEAKING) == 0) {
128                 setChromeState(Speaking);
129             } else if (stateStr.compare(vshl::VOICE_DIALOG_MICROPHONEOFF) == 0) {
130                 setChromeState(MicrophoneOff);
131             }
132         }
133     });
134     }
135     //----------------------------------------------------------------------------------------------
136 }
137
138 void ChromeController::pushToTalk()
139 {
140     m_aglSocket->apiCall(vshl::API, vshl::TAP_TO_TALK_VERB, QJsonValue(),
141                          [](bool result, const QJsonValue &data) -> void {
142         qDebug() << (vshl::API + QLatin1String(":") + vshl::TAP_TO_TALK_VERB)
143                  << "result: " << result << " val: " << data;
144     });
145 }
146
147 void ChromeController::setChromeState(ChromeController::ChromeState state)
148 {
149     const char* ChromeStateNames[MicrophoneOff + 1] = { "Idle", "Listening", "Thinking", "Speaking", "MicrophoneOff" };
150
151     if (m_chromeState != state) {
152         m_chromeState = state;
153         emit chromeStateChanged();
154         if(state <= MicrophoneOff)
155             qDebug() << "new state = " << ChromeStateNames[state];
156         else
157             qDebug() << "new state = " << state;
158     }
159 }