Display Alexa specific chrome when it is used
[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                             auto nameIt = agentObj.find(vshl::NAME_TAG);
68                             if (nameIt != agentObj.constEnd()) {
69                                 m_voiceAgentName = nameIt.value().toString();
70                                 emit agentNameChanged();
71                             }
72                             break;
73                         }
74                     }
75                     if (!agentFound) {
76                         qWarning() << "Default voice agent configuration not found";
77                         return;
78                     }
79                     m_agentPresent = true;
80                     emit agentPresentChanged();
81
82                     //Voice agent subscription------------------------------------------------------
83                     {
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 }
88                         };
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;
93                         });
94                     }
95                     //------------------------------------------------------------------------------
96                 });
97             });
98     }
99     //----------------------------------------------------------------------------------------------<
100
101     //Socket connection management------------------------------------------------------------------
102     {
103     auto connectToBinding = [bindingUrl, this]() -> void {
104         m_aglSocket->open(bindingUrl);
105         qDebug() << "Connecting to:" << bindingUrl;
106     };
107     connect(m_aglSocket, &AglSocketWrapper::disconnected, this, [connectToBinding]() -> void {
108                 QTimer::singleShot(2500, connectToBinding);
109             });
110     connectToBinding();
111     }
112     //----------------------------------------------------------------------------------------------
113
114     //Speech chrome state change event handling-----------------------------------------------------
115     {
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 = QJsonDocument::fromJson(data.toString().toUtf8()).object();
120             auto objIt = dataObj.find(vshl::STATE_TAG);
121             if (objIt == dataObj.constEnd()) {
122                 qWarning() << "Voice dialog state event state missing.";
123                 return;
124             }
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);
136             }
137         }
138     });
139     }
140     //----------------------------------------------------------------------------------------------
141 }
142
143 void ChromeController::pushToTalk()
144 {
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;
149     });
150 }
151
152 void ChromeController::setChromeState(ChromeController::ChromeState state)
153 {
154     const char* ChromeStateNames[MicrophoneOff + 1] = { "Idle", "Listening", "Thinking", "Speaking", "MicrophoneOff" };
155
156     if (m_chromeState != state) {
157         m_chromeState = state;
158         emit chromeStateChanged();
159         if(state <= MicrophoneOff)
160             qDebug() << "new state = " << ChromeStateNames[state];
161         else
162             qDebug() << "new state = " << state;
163     }
164 }