summaryrefslogtreecommitdiffstats
path: root/voice
diff options
context:
space:
mode:
Diffstat (limited to 'voice')
-rw-r--r--voice/CMakeLists.txt4
-rw-r--r--voice/voice.cpp199
-rw-r--r--voice/voice.h73
-rw-r--r--voice/voiceagentmodel.cpp220
-rw-r--r--voice/voiceagentmodel.h65
-rw-r--r--voice/voiceagentprofile.cpp142
-rw-r--r--voice/voiceagentprofile.h78
-rw-r--r--voice/voiceagentregistry.cpp154
-rw-r--r--voice/voiceagentregistry.h76
-rw-r--r--voice/voicemessage.cpp115
-rw-r--r--voice/voicemessage.h59
11 files changed, 1185 insertions, 0 deletions
diff --git a/voice/CMakeLists.txt b/voice/CMakeLists.txt
new file mode 100644
index 0000000..61b8fe2
--- /dev/null
+++ b/voice/CMakeLists.txt
@@ -0,0 +1,4 @@
+add_headers(voice.h voicemessage.h
+ voiceagentregistry.h voiceagentprofile.h voiceagentmodel.h)
+add_sources(voice.cpp voicemessage.cpp
+ voiceagentregistry.cpp voiceagentprofile.cpp voiceagentmodel.cpp)
diff --git a/voice/voice.cpp b/voice/voice.cpp
new file mode 100644
index 0000000..40349d1
--- /dev/null
+++ b/voice/voice.cpp
@@ -0,0 +1,199 @@
+/*
+ * Copyright (C) 2019 Konsulko Group
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <QStringList>
+#include "voice.h"
+#include "message.h"
+#include "messageengine.h"
+#include "responsemessage.h"
+#include "voicemessage.h"
+#include "voiceagentregistry.h"
+
+Voice::Voice (QUrl &url, QQmlContext *context, QObject *parent) :
+ QObject(parent),
+ m_loop(nullptr)
+{
+ m_loop = new MessageEngine(url);
+ m_var = new VoiceAgentRegistry(this, context, parent);
+
+ QObject::connect(m_loop, &MessageEngine::connected,
+ this, &Voice::onConnected);
+ QObject::connect(m_loop, &MessageEngine::disconnected,
+ this, &Voice::onDisconnected);
+ QObject::connect(m_loop, &MessageEngine::messageReceived,
+ this, &Voice::onMessageReceived);
+}
+
+Voice::~Voice()
+{
+ delete m_loop;
+ delete m_var;
+}
+
+void Voice::scan()
+{
+ VoiceMessage *vmsg = new VoiceMessage();
+ QJsonObject parameter;
+
+ vmsg->createRequest("enumerateVoiceAgents", parameter);
+ m_loop->sendMessage(vmsg);
+ delete vmsg;
+}
+
+void Voice::getCBLpair(QString id)
+{
+ triggerCBLProcess(id);
+}
+
+void Voice::subscribeAgentToVshlEvents(QString id)
+{
+ QJsonArray events = QJsonArray::fromStringList(vshl_events);
+ VoiceMessage *vmsg = new VoiceMessage();
+ QJsonObject parameter;
+
+ parameter.insert("va_id", id);
+ parameter.insert("events", events);
+ vmsg->createRequest("subscribe", parameter);
+ m_loop->sendMessage(vmsg);
+ delete vmsg;
+}
+
+void Voice::unsubscribeAgentFromVshlEvents(QString id)
+{
+ QJsonArray events = QJsonArray::fromStringList(vshl_events);
+ VoiceMessage *vmsg = new VoiceMessage();
+ QJsonObject parameter;
+
+ parameter.insert("va_id", id);
+ parameter.insert("events", events);
+ vmsg->createRequest("unsubscribe", parameter);
+ m_loop->sendMessage(vmsg);
+ delete vmsg;
+}
+
+void Voice::triggerCBLProcess(QString id)
+{
+ QJsonArray events;
+ VoiceMessage *vmsg = new VoiceMessage();
+ QJsonObject parameter;
+
+ parameter.insert("va_id", id);
+ parameter.insert("events", events);
+ vmsg->createRequest("subscribeToLoginEvents", parameter);
+ m_loop->sendMessage(vmsg);
+ delete vmsg;
+}
+
+void Voice::parseAgentsList(QJsonArray agents)
+{
+ for (auto value : agents) {
+ QJsonObject a = value.toObject();
+ QString id = m_var->addAgent(a);
+ subscribeAgentToVshlEvents(id);
+ }
+}
+
+
+
+void Voice::processEvent(VoiceMessage *vmsg)
+{
+ const QString str = vmsg->eventName();
+ QJsonObject data = vmsg->eventData();
+ QString agentId = data.value("va_id").toString();
+ QString state = data.value("state").toString();
+
+ if (vmsg->isAuthStateEvent()) {
+ m_var->setAuthState(
+ agentId,
+ static_cast<VoiceAgentRegistry::ServiceAuthState>(
+ m_var->stringToEnum(state, "ServiceAuthState")));
+
+ return;
+ }
+ else if (vmsg->isConnectionStateEvent()) {
+ m_var->setConnectionState(
+ agentId,
+ static_cast<VoiceAgentRegistry::AgentConnectionState>(
+ m_var->stringToEnum(state, "AgentConnectionState")));
+ return;
+ }
+ else if (vmsg->isDialogStateEvent()) {
+ m_var->setDialogState(
+ agentId,
+ static_cast<VoiceAgentRegistry::VoiceDialogState>(
+ m_var->stringToEnum(state, "VoiceDialogState")));
+ return;
+ }
+ else if (vmsg->isCblEvent()) {
+ auto payload_iter = data.find("payload");
+ if (payload_iter == data.end())
+ qWarning() << "no top-level payload field in event";
+ auto payload_stringval = payload_iter.value().toString();
+ if (!payload_stringval.isEmpty())
+ payload_stringval.remove('\n');
+ QJsonDocument infodoc = QJsonDocument::fromJson(payload_stringval.toUtf8());
+ QJsonObject info = infodoc.object();
+ QJsonObject properties = info.value("payload").toObject();
+ QString url = properties.value("url").toString();
+ QString code = properties.value("code").toString();
+ if (str.contains("expired"))
+ m_var->updateLoginData(agentId, code, url, true);
+ else if (str.contains("received")) {
+ m_var->updateLoginData(agentId, code, url, false);
+ } else
+ qWarning() << "unknown cbl event";
+ return;
+ }
+
+ qWarning() << "Unknown vshl event:" << str;
+}
+
+void Voice::processReply(ResponseMessage *rmsg)
+{
+ if (rmsg->replyStatus() == "failed") {
+ qWarning() << "Reply Failed received for verb:" << rmsg->requestVerb();
+ } else if (rmsg->requestVerb() == "enumerateVoiceAgents") {
+ parseAgentsList(rmsg->replyData().value("agents").toArray());
+ m_var->setDefaultId(
+ rmsg->replyData().value("default").toString());
+ } else
+ qWarning() << "discarding reply received for verb:" <<
+ rmsg->requestVerb();
+}
+
+void Voice::onConnected()
+{
+ scan();
+}
+
+void Voice::onDisconnected()
+{
+ QStringList mvarlist = m_var->getAgentsListById();
+ QStringList::iterator it;
+ for (it = mvarlist.begin(); it != mvarlist.end(); ++it)
+ unsubscribeAgentFromVshlEvents(*it);
+}
+
+void Voice::onMessageReceived(MessageType type, Message *msg)
+{
+ if (msg->isEvent() && type == VoiceEventMessage) {
+ processEvent(qobject_cast<VoiceMessage*>(msg));
+ } else if (msg->isReply() && (type == ResponseRequestMessage)) {
+ processReply(qobject_cast<ResponseMessage*>(msg));
+ } else
+ qWarning() << "Received unknown message type:" << type;
+ msg->deleteLater();
+}
diff --git a/voice/voice.h b/voice/voice.h
new file mode 100644
index 0000000..d4c288e
--- /dev/null
+++ b/voice/voice.h
@@ -0,0 +1,73 @@
+/*
+ * Copyright (C) 2019 Konsulko Group
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef VOICE_H
+#define VOICE_H
+
+#include <QDebug>
+#include <QObject>
+#include <QJsonArray>
+#include <QtQml/QQmlContext>
+#include "message.h"
+
+class MessageEngine;
+class ResponseMessage;
+class VoiceMessage;
+class VoiceAgentRegistry;
+
+class Voice : public QObject
+{
+ Q_OBJECT
+
+ public:
+ explicit Voice(QUrl &url, QQmlContext *context,
+ QObject * parent = Q_NULLPTR);
+ virtual ~Voice();
+
+ //enumerate agents:
+ Q_INVOKABLE void scan();
+ //obtain code based login params:
+ Q_INVOKABLE void getCBLpair(QString id);
+
+ private:
+ MessageEngine *m_loop;
+ VoiceAgentRegistry *m_var;
+
+ void subscribeAgentToVshlEvents(QString id);
+ void unsubscribeAgentFromVshlEvents(QString id);
+ void triggerCBLProcess(QString id);
+ void parseAgentsList(QJsonArray agents);
+ void processVshlEvent(VoiceMessage *vmsg);
+ void processLoginEvent(VoiceMessage *vmsg);
+
+ void processEvent(VoiceMessage *vmsg);
+ void processReply(ResponseMessage *rmsg);
+
+ // slots
+ void onConnected();
+ void onDisconnected();
+ void onMessageReceived(MessageType type, Message *msg);
+
+ const QStringList vshl_events {
+ "voice_authstate_event",
+ "voice_dialogstate_event",
+ "voice_connectionstate_event",
+ "voice_cbl_codepair_received_event",
+ "voice_cbl_codepair_expired_event",
+ };
+};
+
+#endif // VOICE_H
diff --git a/voice/voiceagentmodel.cpp b/voice/voiceagentmodel.cpp
new file mode 100644
index 0000000..3f4f50d
--- /dev/null
+++ b/voice/voiceagentmodel.cpp
@@ -0,0 +1,220 @@
+/*
+ * Copyright (C) 2019 Konsulko Group
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "voiceagentmodel.h"
+#include "voiceagentprofile.h"
+#include <QVector>
+#include <QDebug>
+
+VoiceAgentModel::VoiceAgentModel(QObject *parent)
+ : QAbstractListModel(parent)
+{
+}
+
+QVariant VoiceAgentModel::data(const QModelIndex &index, int role) const
+{
+ QVariant ret;
+
+ if (!index.isValid())
+ return ret;
+
+ if (index.row() < 0 || index.row() >= m_agents.count())
+ return ret;
+
+ const VoiceAgentProfile *vap = m_agents[index.row()];
+ switch (role) {
+ case IdRole:
+ return vap->vaid();
+ case NameRole:
+ return vap->name();
+ case WuwRole:
+ return vap->activewuw();
+ case AuthStateRole:
+ return vap->authstate();
+ case ConnStateRole:
+ return vap->connstate();
+ case DialogStateRole:
+ return vap->dialogstate();
+ case LoginParamsRole:
+ return readLoginParams(index);
+ case ActiveRole:
+ return vap->isactive()? "active" : "inactive";
+ }
+ return ret;
+}
+
+int VoiceAgentModel::rowCount(const QModelIndex &parent) const
+{
+ Q_UNUSED(parent);
+ return m_agents.count();
+}
+
+QVariantList VoiceAgentModel::readLoginParams(const QModelIndex &index) const
+{
+ QVariantList ret;
+
+ if (!index.isValid())
+ return ret;
+
+ if (index.row() < 0 || index.row() >= this->m_agents.count())
+ return ret;
+
+ const VoiceAgentProfile *vap = this->m_agents[index.row()];
+ ret.append(vap->logincode());
+ ret.append(vap->loginurl());
+ ret.append(vap->isloginpairexpired()? "expired" : "valid");
+ return ret;
+}
+
+void VoiceAgentModel::addAgent(VoiceAgentProfile *vap)
+{
+ beginInsertRows(QModelIndex(), rowCount(), rowCount());
+ m_agents.insert(rowCount(), vap);
+ endInsertRows();
+}
+
+void VoiceAgentModel::removeAgent(VoiceAgentProfile *vap)
+{
+ if (m_agents.isEmpty())
+ return;
+
+ int row = m_agents.indexOf(vap);
+ beginRemoveRows(QModelIndex(), row, row);
+ m_agents.removeAt(row);
+ endRemoveRows();
+ delete vap;
+}
+
+void VoiceAgentModel::removeAll()
+{
+ if (m_agents.isEmpty())
+ return;
+
+ beginRemoveRows(QModelIndex(), 0, m_agents.count() -1);
+ qDeleteAll(m_agents.begin(), m_agents.end());
+ endRemoveRows();
+ m_agents.clear();
+}
+
+bool VoiceAgentModel::agentExists(QString name, QString id, QString api) const
+{
+ VoiceAgentProfile *vap = getAgentFromName(name);
+ if (!vap)
+ return false;
+ bool sameid = id == vap->vaid();
+ bool sameapi = api == vap->vaapi();
+ return sameapi && (sameid || id != "UNKNOWN");
+}
+
+VoiceAgentProfile* VoiceAgentModel::getAgentFromName(QString name) const
+{
+ if (m_agents.isEmpty())
+ return nullptr;
+
+ for (auto agent : m_agents) {
+ if (agent->name() == name)
+ return agent;
+ }
+ return nullptr;
+}
+
+VoiceAgentProfile* VoiceAgentModel::getAgentFromId(QString id) const
+{
+ if (m_agents.isEmpty())
+ return nullptr;
+
+ for (auto agent : m_agents) {
+ if (agent->vaid() == id)
+ return agent;
+ }
+ return nullptr;
+}
+
+void VoiceAgentModel::updateAgentProperties(QString name, QString id, QString api,
+ bool active, QString wuw)
+{
+ QVector<int> vroles;
+ VoiceAgentProfile *vap = getAgentFromName(name);
+ if (!vap) {
+ qWarning() << "Unknown agent";
+ return;
+ }
+ if ((vap->vaapi() == api) && (vap->vaid() != id) && (id != "UNKNOWN")) {
+ vap->setVaid(id);
+ vroles.push_back(IdRole);
+ }
+ vap->setActive(active);
+ vroles.push_back(ActiveRole);
+ if (!wuw.isEmpty()) {
+ vap->setWuw(wuw);
+ vroles.push_back(WuwRole);
+ }
+ if (!vroles.isEmpty())
+ emit dataChanged(indexOf(vap), indexOf(vap), vroles);
+}
+
+void VoiceAgentModel::updateAgentState(QString id)
+{
+ QVector<int> vroles;
+ VoiceAgentProfile *vap = getAgentFromId(id);
+
+ if (!vap) {
+ qWarning() << "Unknown agent";
+ return;
+ }
+
+ vroles.push_back(AuthStateRole);
+ vroles.push_back(ConnStateRole);
+ vroles.push_back(DialogStateRole);
+
+ if (!vroles.isEmpty())
+ emit dataChanged(indexOf(vap), indexOf(vap), vroles);
+}
+
+void VoiceAgentModel::updateAgentLoginData(QString id)
+{
+ QVector<int> vroles;
+ VoiceAgentProfile *vap = getAgentFromId(id);
+
+ if (!vap) {
+ qWarning() << "Unknown agent";
+ return;
+ }
+
+ vroles.push_back(LoginParamsRole);
+ if (!vroles.isEmpty())
+ emit dataChanged(indexOf(vap), indexOf(vap), vroles);
+}
+
+QModelIndex VoiceAgentModel::indexOf(VoiceAgentProfile *vap)
+{
+ int row = m_agents.indexOf(vap);
+ return index(row);
+}
+
+QHash<int, QByteArray> VoiceAgentModel::roleNames() const
+{
+ QHash<int, QByteArray> roles;
+ roles[NameRole] = "name";
+ roles[IdRole] = "id";
+ roles[WuwRole] = "wuw";
+ roles[AuthStateRole] = "authstate";
+ roles[ConnStateRole] = "connstate";
+ roles[DialogStateRole] = "dialogstate";
+ roles[LoginParamsRole] = "usrauth";
+ roles[ActiveRole] = "active";
+ return roles;
+}
diff --git a/voice/voiceagentmodel.h b/voice/voiceagentmodel.h
new file mode 100644
index 0000000..3cd84e6
--- /dev/null
+++ b/voice/voiceagentmodel.h
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 2019 Konsulko Group
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef VOICEAGENTMODEL_H
+#define VOICEAGENTMODEL_H
+
+#include <QAbstractListModel>
+#include <QStringList>
+#include <QtQml/QQmlContext>
+#include <QJsonObject>
+
+#include "voiceagentprofile.h"
+
+class VoiceAgentModel : public QAbstractListModel
+{
+ Q_OBJECT
+
+ public:
+ enum VoiceAgentRoles {
+ IdRole = Qt::UserRole + 1,
+ NameRole,
+ WuwRole,
+ AuthStateRole,
+ ConnStateRole,
+ DialogStateRole,
+ LoginParamsRole,
+ ActiveRole,
+ };
+
+ VoiceAgentModel(QObject *parent = Q_NULLPTR);
+
+ QVariant data(const QModelIndex &index,
+ int role = Qt::DisplayRole) const;
+ int rowCount(const QModelIndex &parent = QModelIndex()) const;
+ QVariantList readLoginParams(const QModelIndex &index) const;
+ void addAgent(VoiceAgentProfile *vap);
+ void removeAgent(VoiceAgentProfile* vap);
+ void removeAll();
+ bool agentExists(QString name, QString id, QString api) const;
+ VoiceAgentProfile *getAgentFromName(QString name) const;
+ VoiceAgentProfile *getAgentFromId(QString id) const;
+ void updateAgentProperties(QString name, QString id,
+ QString api, bool active, QString wuw);
+ void updateAgentState(QString id);
+ void updateAgentLoginData(QString id);
+
+ private:
+ QList<VoiceAgentProfile *> m_agents;
+ QModelIndex indexOf(VoiceAgentProfile *agent);
+ QHash<int, QByteArray> roleNames() const;
+};
+#endif // VOICEAGENTMODEL_H
diff --git a/voice/voiceagentprofile.cpp b/voice/voiceagentprofile.cpp
new file mode 100644
index 0000000..05e3839
--- /dev/null
+++ b/voice/voiceagentprofile.cpp
@@ -0,0 +1,142 @@
+/*
+ * Copyright (C) 2019 Konsulko Group
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "voiceagentprofile.h"
+
+VoiceAgentProfile::VoiceAgentProfile(const QString &name,
+ const QString &id,
+ const QString &api,
+ bool active,
+ const QString &wuw,
+ const QString &vendor,
+ const QString &wuws)
+ : m_name(name), m_vaid(id), m_vaapi(api), m_active(active),
+ m_activewuw(wuw), m_vendor(vendor), m_wuws(wuws),
+ m_authstate("UNITIALIZED"), m_connstate("DISCONNECTED"),
+ m_dialogstate("MICROPHONEOFF"), m_logincode(QString()),
+ m_loginurl(QString()), m_expired(true)
+{
+}
+
+QString VoiceAgentProfile::name() const
+{
+ return m_name;
+}
+
+QString VoiceAgentProfile::vaid() const
+{
+ return m_vaid;
+}
+
+QString VoiceAgentProfile::vaapi() const
+{
+ return m_vaapi;
+}
+
+bool VoiceAgentProfile::isactive() const
+{
+ return m_active;
+}
+
+QString VoiceAgentProfile::activewuw() const
+{
+ return m_activewuw;
+}
+
+QString VoiceAgentProfile::vendor() const
+{
+ return m_vendor;
+}
+
+QString VoiceAgentProfile::wuws() const
+{
+ return m_wuws;
+}
+
+QString VoiceAgentProfile::authstate() const
+{
+ return m_authstate;
+}
+
+QString VoiceAgentProfile::connstate() const
+{
+ return m_connstate;
+}
+
+QString VoiceAgentProfile::dialogstate() const
+{
+ return m_dialogstate;
+}
+
+QString VoiceAgentProfile::logincode() const
+{
+ return m_logincode;
+}
+
+QString VoiceAgentProfile::loginurl() const
+{
+ return m_loginurl;
+}
+
+bool VoiceAgentProfile::isloginpairexpired() const
+{
+ return m_expired;
+}
+
+void VoiceAgentProfile::setVaid(const QString id)
+{
+ m_vaid = id;
+}
+
+void VoiceAgentProfile::setActive(bool active)
+{
+ m_active = active;
+}
+
+void VoiceAgentProfile::setAuthState(const QString state)
+{
+ m_authstate = state;
+}
+
+void VoiceAgentProfile::setConnState(const QString state)
+{
+ m_connstate = state;
+}
+
+void VoiceAgentProfile::setDialogState(const QString state)
+{
+ m_dialogstate = state;
+}
+
+void VoiceAgentProfile::setLoginCode(const QString usrcode)
+{
+ m_logincode = usrcode;
+}
+
+void VoiceAgentProfile::setLoginUrl(const QString usrurl)
+{
+ m_loginurl = usrurl;
+}
+
+void VoiceAgentProfile::setLoginPairExpired(bool expired)
+{
+ m_expired = expired;
+}
+
+void VoiceAgentProfile::setWuw(const QString newwuw)
+{
+ m_activewuw = newwuw;
+}
diff --git a/voice/voiceagentprofile.h b/voice/voiceagentprofile.h
new file mode 100644
index 0000000..dda96c5
--- /dev/null
+++ b/voice/voiceagentprofile.h
@@ -0,0 +1,78 @@
+/*
+ * Copyright (C) 2019 Konsulko Group
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef VOICEAGENTPROFILE_H
+#define VOICEAGENTPROFILE_H
+
+#include <QString>
+
+class VoiceAgentProfile
+{
+ public:
+ VoiceAgentProfile(const QString &name,
+ const QString &id,
+ const QString &api,
+ bool active,
+ const QString &wuw,
+ const QString &vendor,
+ const QString &wuws);
+
+ QString name() const;
+ QString vaid() const;
+ QString vaapi() const;
+ bool isactive() const;
+ QString activewuw() const;
+ QString vendor() const;
+ QString wuws() const;
+ QString authstate() const;
+ QString connstate() const;
+ QString dialogstate() const;
+ QString logincode() const;
+ QString loginurl() const;
+ bool isloginpairexpired() const;
+
+ void setVaid(const QString newid);
+ void setActive(bool activemode);
+ void setAuthState(const QString newauthstate);
+ void setConnState(const QString newconnstate);
+ void setDialogState(const QString newdialogstate);
+ void setLoginCode(const QString newtoken);
+ void setLoginUrl(const QString newurl);
+ void setLoginPairExpired(bool expired);
+ void setWuw(const QString newwuw);
+
+ bool operator==(const VoiceAgentProfile& rhs) {
+ return (m_name == rhs.name() &&
+ m_vaid == rhs.vaid() &&
+ m_vaapi == rhs.vaapi()); };
+
+ private:
+ QString m_name;
+ QString m_vaid;
+ QString m_vaapi;
+ bool m_active;
+ QString m_activewuw;
+ QString m_vendor;
+ QString m_wuws;
+ QString m_authstate;
+ QString m_connstate;
+ QString m_dialogstate;
+ QString m_logincode;
+ QString m_loginurl;
+ bool m_expired;
+};
+
+#endif // VOICEAGENTPROFILE_H
diff --git a/voice/voiceagentregistry.cpp b/voice/voiceagentregistry.cpp
new file mode 100644
index 0000000..62e8cd6
--- /dev/null
+++ b/voice/voiceagentregistry.cpp
@@ -0,0 +1,154 @@
+/*
+ * Copyright (C) 2019 Konsulko Group
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <QMetaEnum>
+#include <QSortFilterProxyModel>
+#include <QtQml/QQmlEngine>
+
+#include "voice.h"
+#include "voiceagentregistry.h"
+#include "voiceagentmodel.h"
+#include "voiceagentprofile.h"
+
+VoiceAgentRegistry::VoiceAgentRegistry(Voice *voice, QQmlContext *context, QObject *parent) :
+ QObject(parent),
+ m_model(nullptr),
+ vc(voice)
+{
+ m_model = new VoiceAgentModel();
+ QSortFilterProxyModel *model = new QSortFilterProxyModel();
+ model->setSourceModel(m_model);
+ model->setSortRole(VoiceAgentModel::VoiceAgentRoles::IdRole);
+ model->setSortCaseSensitivity(Qt::CaseInsensitive);
+ model->sort(0);
+
+ context->setContextProperty("VoiceAgentModel", m_model);
+ context->setContextProperty("VoiceAgent", this);
+}
+
+VoiceAgentRegistry::~VoiceAgentRegistry()
+{
+ delete m_model;
+}
+
+QString VoiceAgentRegistry::addAgent(QJsonObject va)
+{
+ bool active = va.value("active").toBool();
+ QString wuw = va.value("activewakeword").toString();
+ QString api = va.value("api").toString();
+ QString desc = va.value("description").toString();
+ QString id = va.value("id").toString();
+ QString name = va.value("name").toString();
+ QString vendor = va.value("vendor").toString();
+ QString wuws = va.value("wakewords").toString();
+
+ if (!m_model->agentExists(name, id, api)) {
+ VoiceAgentProfile *vap = new VoiceAgentProfile(name, id, api,
+ active, wuw,
+ vendor, wuws);
+ m_model->addAgent(vap);
+ m_regids.append(id);
+ }
+ else
+ m_model->updateAgentProperties(name, id, api, active, wuw);
+ return id;
+}
+
+bool VoiceAgentRegistry::removeAgent(QString id)
+{
+ VoiceAgentProfile *vap = m_model->getAgentFromId(id);
+ if (!vap)
+ return false;
+ m_model->removeAgent(vap);
+ return true;
+}
+
+void VoiceAgentRegistry::clearRegistry()
+{
+ m_default_aid.clear();
+ m_regids.clear();
+ m_model->removeAll();
+}
+
+QStringList VoiceAgentRegistry::getAgentsListById() const
+{
+ return m_regids;
+}
+
+QString VoiceAgentRegistry::getDefaultId() const
+{
+ return m_default_aid.isEmpty()? "UNKNOWN" : m_default_aid;
+}
+void VoiceAgentRegistry::setDefaultId(QString id)
+{
+ m_default_aid = id;
+}
+
+void VoiceAgentRegistry::setAuthState(QString id, ServiceAuthState state)
+{
+ QMetaEnum metaEnum = QMetaEnum::fromType<VoiceAgentRegistry::ServiceAuthState>();
+ auto stateStr = metaEnum.valueToKey(state);
+ VoiceAgentProfile *vap = m_model->getAgentFromId(id);
+ if (vap) {
+ vap->setAuthState(stateStr);
+ m_model->updateAgentState(id);
+ }
+}
+
+void VoiceAgentRegistry::setConnectionState(QString id, AgentConnectionState state)
+{
+ QMetaEnum metaEnum = QMetaEnum::fromType<VoiceAgentRegistry::AgentConnectionState>();
+ auto stateStr = metaEnum.valueToKey(state);
+
+ VoiceAgentProfile *vap = m_model->getAgentFromId(id);
+ if (vap) {
+ vap->setConnState(stateStr);
+ m_model->updateAgentState(id);
+ }
+}
+
+void VoiceAgentRegistry::setDialogState(QString id, VoiceDialogState state)
+{
+ QMetaEnum metaEnum = QMetaEnum::fromType<VoiceAgentRegistry::VoiceDialogState>();
+ auto stateStr = metaEnum.valueToKey(state);
+
+ VoiceAgentProfile *vap = m_model->getAgentFromId(id);
+ if (vap) {
+ vap->setDialogState(stateStr);
+ m_model->updateAgentState(id);
+ }
+}
+
+void VoiceAgentRegistry::updateLoginData(QString id, QString code, QString url,
+ bool expired)
+{
+ VoiceAgentProfile *vap = m_model->getAgentFromId(id);
+ if (vap) {
+ vap->setLoginCode(url);
+ vap->setLoginUrl(code);
+ vap->setLoginPairExpired(expired);
+ m_model->updateAgentLoginData(id);
+ };
+}
+
+int VoiceAgentRegistry::stringToEnum(const QString key, const QString enumtype)
+{
+ const QMetaObject *metaObject = VoiceAgentRegistry::metaObject();
+ int enumIndex = metaObject->indexOfEnumerator(enumtype.toUtf8().constData());
+ QMetaEnum metaEnum = metaObject->enumerator(enumIndex);
+ int value = metaEnum.keyToValue(key.toUtf8().constData());
+ return (value < 0)? 0 : value;
+}
diff --git a/voice/voiceagentregistry.h b/voice/voiceagentregistry.h
new file mode 100644
index 0000000..cd7dc2c
--- /dev/null
+++ b/voice/voiceagentregistry.h
@@ -0,0 +1,76 @@
+/*
+ * Copyright (C) 2019 Konsulko Group
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef VOICEAGENTREGISTRY_H
+#define VOICEAGENTREGISTRY_H
+
+#include <QDebug>
+#include <QObject>
+#include <QJsonArray>
+#include <QtQml/QQmlContext>
+
+class Voice;
+class VoiceAgentModel;
+
+class VoiceAgentRegistry : public QObject
+{
+ Q_OBJECT
+ public:
+ explicit VoiceAgentRegistry(Voice *voice, QQmlContext *context,
+ QObject *parent);
+ virtual ~VoiceAgentRegistry();
+
+ enum AgentConnectionState {
+ DISCONNECTED = 0,
+ CONNECTED,
+ };
+ Q_ENUM(AgentConnectionState)
+
+ enum VoiceDialogState {
+ IDLE = 0,
+ LISTENING,
+ THINKING,
+ SPEAKING,
+ MICROPHONEOFF,
+ };
+ Q_ENUM(VoiceDialogState)
+
+ enum ServiceAuthState {
+ UNINITIALIZED = 0,
+ REFRESHED,
+ };
+ Q_ENUM(ServiceAuthState)
+
+ QString addAgent(QJsonObject va);
+ bool removeAgent(QString id);
+ void clearRegistry();
+ QStringList getAgentsListById() const;
+ QString getDefaultId() const;
+ void setDefaultId(QString id);
+ void setAuthState(QString id, ServiceAuthState state);
+ void setConnectionState(QString id, AgentConnectionState state);
+ void setDialogState(QString id, VoiceDialogState state);
+ void updateLoginData(QString id, QString code, QString url,
+ bool expired);
+ int stringToEnum(QString value, QString enumtype);
+ private:
+ VoiceAgentModel *m_model;
+ Voice *vc;
+ QString m_default_aid;
+ QStringList m_regids;
+};
+
+#endif // VOICEAGENTREGISTRY_H
diff --git a/voice/voicemessage.cpp b/voice/voicemessage.cpp
new file mode 100644
index 0000000..493b04e
--- /dev/null
+++ b/voice/voicemessage.cpp
@@ -0,0 +1,115 @@
+/*
+ * Copyright (C) 2019 Konsulko Group
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <QDebug>
+#include <QJsonArray>
+#include <QJsonDocument>
+#include <QJsonObject>
+
+#include "voicemessage.h"
+
+bool VoiceMessage::createRequest(QString verb, QJsonObject parameter)
+{
+ if (!verbs.contains(verb))
+ return false;
+ return Message::createRequest("vshl-core", verb, parameter);
+}
+
+bool VoiceMessage::fromJDoc(QJsonDocument jdoc)
+{
+ // Validate message is array
+ if (!jdoc.isArray()) {
+ qWarning("Invalid appfw message: not an array");
+ return false;
+ }
+ QJsonArray msg = jdoc.array();
+
+ // Validate array is proper length
+ if ((msg.size() < 3) || (msg.size() > 4)) {
+ qWarning("Invalid appfw message: invalid array size");
+ return false;
+ }
+
+ // Validate msgid type
+ double msgid;
+ if (msg[0].isDouble()) {
+ msgid = msg[0].toDouble();
+ } else {
+ qWarning("Invalid appfw message: invalid msgid type");
+ return false;
+ }
+
+ // Validate msgid element
+ if ((msgid < Call) || (msgid > Event)) {
+ qWarning("Invalid appfw message: msgid out of range");
+ return false;
+ }
+
+ // Validate that the payload has a request object
+ QJsonObject payload;
+ if (msg[2].isObject()) {
+ payload = msg[2].toObject();
+ } else {
+ qWarning("Invalid appfw payload: no JSON object");
+ return false;
+ }
+
+ if ((msgid == RetOk) || (msgid == RetErr)) {
+ auto request_iter = payload.find("request");
+ auto request = request_iter.value().toObject();
+ if (request.empty()) {
+ qWarning("Invalid appfw reply message: empty request data");
+ return false;
+ }
+ auto status_iter = request.find("status");
+ auto info_iter = request.find("info");
+ auto response_iter = payload.find("response");
+ auto response = response_iter.value().toObject();
+ m_reply_status = status_iter.value().toString();
+ m_reply_info = info_iter.value().toString();
+ m_reply_data = response;
+ m_reply = true;
+ } else if (msgid == Event) {
+ // If event, save data object
+ auto data_iter = payload.find("data");
+ auto data = data_iter.value().toObject();
+ auto data_string = data_iter.value().toString();
+ if (!data_string.isEmpty())
+ data_string.remove('\n');
+
+ QJsonDocument datadoc = QJsonDocument::fromJson(data_string.toUtf8());
+ m_event_data = datadoc.object();
+
+ auto event_iter = payload.find("event");
+ auto event_string = event_iter.value().toString();
+ if (event_string.isEmpty()) {
+ qWarning("Invalid appfw event message: empty event name");
+ return false;
+ }
+ QStringList event_strings = event_string.split(QRegExp("/"));
+ if (event_strings.size() != 2) {
+ qWarning("Invalid appfw event message: malformed event name");
+ return false;
+ }
+ m_event_api = event_strings[0];
+ m_event_name = event_strings[1];
+ m_event = true;
+ }
+
+ m_jdoc = jdoc;
+ m_init = true;
+ return m_init;
+}
diff --git a/voice/voicemessage.h b/voice/voicemessage.h
new file mode 100644
index 0000000..712631e
--- /dev/null
+++ b/voice/voicemessage.h
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2019 Konsulko Group
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef VOICE_MESSAGE_H
+#define VOICE_MESSAGE_H
+
+#include "message.h"
+
+class VoiceMessage : public Message
+{
+ Q_OBJECT
+ public:
+ virtual ~VoiceMessage() {};
+ bool fromJDoc(QJsonDocument jdocData) override;
+
+ bool isAuthStateEvent() const {
+ return (this->eventName().contains("voice_authstate_event")); };
+ bool isConnectionStateEvent() const {
+ return (this->eventName().contains("voice_connectionstate_event")); };
+ bool isDialogStateEvent() const {
+ return (this->eventName().contains("voice_dialogstate_event")); };
+ bool isCblEvent() const {
+ return (this->eventName().contains("cbl")); };
+ bool createRequest(QString verb, QJsonObject parameter);
+
+ private:
+ QStringList verbs {
+ "startListening",
+ "cancelListening",
+ "subscribe",
+ "unsubscribe",
+ "enumerateVoiceAgents",
+ "setDefaultVoiceAgent",
+ "subscribeToLoginEvents",
+ };
+ QStringList events {
+ "voice_authstate_event",
+ "voice_dialogstate_event",
+ "voice_connectionstate_event",
+ "voice_cbl_codepair_received_event",
+ "voice_cbl_codepair_expired_event",
+ };
+};
+
+
+#endif // VOICE_MESSAGE_H