diff --git a/bin/dbus/cx.ring.Ring.PluginManagerInterface.xml b/bin/dbus/cx.ring.Ring.PluginManagerInterface.xml index bdfaedd989d4678fda2d95aa392d86abdb92f755..2e6e32be131dd9bdfb8e0c0cb3ebb10377dabb84 100644 --- a/bin/dbus/cx.ring.Ring.PluginManagerInterface.xml +++ b/bin/dbus/cx.ring.Ring.PluginManagerInterface.xml @@ -19,14 +19,6 @@ </arg> </method> - <method name="togglePlugin" tp:name-for-bindings="togglePlugin"> - <tp:added version="9.2.0"/> - <arg type="s" name="path" direction="in"> - </arg> - <arg type="b" name="toggle" direction="in"> - </arg> - </method> - <method name="getPluginDetails" tp:name-for-bindings="getPluginDetails"> <annotation name="org.qtproject.QtDBus.QtTypeName.Out0" value="MapStringString"/> <tp:added version="9.2.0"/> @@ -77,14 +69,14 @@ </arg> </method> - <method name="listAvailablePlugins" tp:name-for-bindings="listAvailablePlugins"> - <tp:added version="9.2.0"/> + <method name="getInstalledPlugins" tp:name-for-bindings="getInstalledPlugins"> + <tp:added version="9.9.0"/> <arg type="as" name="availablePlugins" direction="out"> </arg> </method> - <method name="listLoadedPlugins" tp:name-for-bindings="listLoadedPlugins"> - <tp:added version="9.2.0"/> + <method name="getLoadedPlugins" tp:name-for-bindings="getLoadedPlugins"> + <tp:added version="9.9.0"/> <arg type="as" name="LoadedPlugins" direction="out"> </arg> </method> @@ -107,9 +99,15 @@ </arg> </method> - <method name="listCallMediaHandlers" tp:name-for-bindings="listCallMediaHandlers"> - <tp:added version="9.2.0"/> - <arg type="as" name="listCallMediaHandlers" direction="out"> + <method name="getCallMediaHandlers" tp:name-for-bindings="getCallMediaHandlers"> + <tp:added version="9.9.0"/> + <arg type="as" name="getCallMediaHandlers" direction="out"> + </arg> + </method> + + <method name="getChatHandlers" tp:name-for-bindings="getChatHandlers"> + <tp:added version="9.9.0"/> + <arg type="as" name="getChatHandlers" direction="out"> </arg> </method> @@ -123,6 +121,18 @@ </arg> </method> + <method name="toggleChatHandler" tp:name-for-bindings="toggleChatHandler"> + <tp:added version="9.9.0"/> + <arg type="s" name="chatHandlerId" direction="in"> + </arg> + <arg type="s" name="accountId" direction="in"> + </arg> + <arg type="s" name="peerId" direction="in"> + </arg> + <arg type="b" name="toggle" direction="in"> + </arg> + </method> + <method name="getCallMediaHandlerDetails" tp:name-for-bindings="getCallMediaHandlerDetails"> <annotation name="org.qtproject.QtDBus.QtTypeName.Out0" value="MapStringString"/> <tp:added version="9.2.0"/> @@ -133,6 +143,38 @@ </arg> </method> + <method name="getCallMediaHandlerStatus" tp:name-for-bindings="getCallMediaHandlerStatus"> + <annotation name="org.qtproject.QtDBus.QtTypeName.Out0" value="VectorString"/> + <tp:added version="9.3.0"/> + <arg type="s" name="callId" direction="in"> + </arg> + <annotation name="org.qtproject.QtDBus.QtTypeName.Out0" value="VectorString"/> + <arg type="as" name="getCallMediaHandlerStatus" direction="out"> + </arg> + </method> + + <method name="getChatHandlerDetails" tp:name-for-bindings="getChatHandlerDetails"> + <annotation name="org.qtproject.QtDBus.QtTypeName.Out0" value="MapStringString"/> + <tp:added version="9.9.0"/> + <arg type="s" name="chatHandlerId" direction="in"> + </arg> + <annotation name="org.qtproject.QtDBus.QtTypeName.Out0" value="MapStringString"/> + <arg type="a{ss}" name="ChatHandlerDetails" direction="out"> + </arg> + </method> + + <method name="getChatHandlerStatus" tp:name-for-bindings="getChatHandlerStatus"> + <annotation name="org.qtproject.QtDBus.QtTypeName.Out0" value="VectorString"/> + <tp:added version="9.9.0"/> + <arg type="s" name="accountId" direction="in"> + </arg> + <arg type="s" name="peerId" direction="in"> + </arg> + <annotation name="org.qtproject.QtDBus.QtTypeName.Out0" value="VectorString"/> + <arg type="as" name="getChatHandlerStatus" direction="out"> + </arg> + </method> + <method name="getPluginsEnabled" tp:name-for-bindings="getPluginsEnabled"> <annotation name="org.qtproject.QtDBus.QtTypeName.Out0" value="Bool"/> <tp:added version="9.3.0"/> @@ -148,15 +190,5 @@ </arg> </method> - <method name="getCallMediaHandlerStatus" tp:name-for-bindings="getCallMediaHandlerStatus"> - <annotation name="org.qtproject.QtDBus.QtTypeName.Out0" value="MapStringVectorString"/> - <tp:added version="9.3.0"/> - <arg type="s" name="callId" direction="in"> - </arg> - <annotation name="org.qtproject.QtDBus.QtTypeName.Out0" value="MapStringVectorString"/> - <arg type="a{sas}" name="getCallMediaHandlerStatus" direction="out"> - </arg> - </method> - </interface> </node> diff --git a/bin/dbus/dbuspluginmanagerinterface.cpp b/bin/dbus/dbuspluginmanagerinterface.cpp index af648739bf67fba17daa53aa60bc754c8efadb04..94d12a40d273e7a1029de419b61cc971259ddedc 100644 --- a/bin/dbus/dbuspluginmanagerinterface.cpp +++ b/bin/dbus/dbuspluginmanagerinterface.cpp @@ -37,12 +37,6 @@ DBusPluginManagerInterface::unloadPlugin(const std::string& path) return DRing::unloadPlugin(path); } -void -DBusPluginManagerInterface::togglePlugin(const std::string& path, const bool& toggle) -{ - DRing::togglePlugin(path, toggle); -} - std::map<std::string, std::string> DBusPluginManagerInterface::getPluginDetails(const std::string& path) { @@ -76,15 +70,15 @@ DBusPluginManagerInterface::resetPluginPreferencesValues(const std::string& path } auto -DBusPluginManagerInterface::listAvailablePlugins() -> decltype(DRing::listAvailablePlugins()) +DBusPluginManagerInterface::getInstalledPlugins() -> decltype(DRing::getInstalledPlugins()) { - return DRing::listAvailablePlugins(); + return DRing::getInstalledPlugins(); } auto -DBusPluginManagerInterface::listLoadedPlugins() -> decltype(DRing::listLoadedPlugins()) +DBusPluginManagerInterface::getLoadedPlugins() -> decltype(DRing::getLoadedPlugins()) { - return DRing::listLoadedPlugins(); + return DRing::getLoadedPlugins(); } int @@ -100,9 +94,15 @@ DBusPluginManagerInterface::uninstallPlugin(const std::string& pluginRootPath) } auto -DBusPluginManagerInterface::listCallMediaHandlers() -> decltype(DRing::listCallMediaHandlers()) +DBusPluginManagerInterface::getCallMediaHandlers() -> decltype(DRing::getCallMediaHandlers()) +{ + return DRing::getCallMediaHandlers(); +} + +auto +DBusPluginManagerInterface::getChatHandlers() -> decltype(DRing::getChatHandlers()) { - return DRing::listCallMediaHandlers(); + return DRing::getChatHandlers(); } void @@ -113,12 +113,40 @@ DBusPluginManagerInterface::toggleCallMediaHandler(const std::string& mediaHandl DRing::toggleCallMediaHandler(mediaHandlerId, callId, toggle); } +void +DBusPluginManagerInterface::toggleChatHandler(const std::string& chatHandlerId, + const std::string& accountId, + const std::string& peerId, + const bool& toggle) +{ + DRing::toggleChatHandler(chatHandlerId, accountId, peerId, toggle); +} + std::map<std::string, std::string> DBusPluginManagerInterface::getCallMediaHandlerDetails(const std::string& mediaHanlderId) { return DRing::getCallMediaHandlerDetails(mediaHanlderId); } +std::vector<std::string> +DBusPluginManagerInterface::getCallMediaHandlerStatus(const std::string& callId) +{ + return DRing::getCallMediaHandlerStatus(callId); +} + +std::map<std::string, std::string> +DBusPluginManagerInterface::getChatHandlerDetails(const std::string& chatHanlderId) +{ + return DRing::getChatHandlerDetails(chatHanlderId); +} + +std::vector<std::string> +DBusPluginManagerInterface::getChatHandlerStatus(const std::string& accountId, + const std::string& peerId) +{ + return DRing::getChatHandlerStatus(accountId, peerId); +} + bool DBusPluginManagerInterface::getPluginsEnabled() { @@ -130,9 +158,3 @@ DBusPluginManagerInterface::setPluginsEnabled(const bool& state) { DRing::setPluginsEnabled(state); } - -std::map<std::string, std::vector<std::string>> -DBusPluginManagerInterface::getCallMediaHandlerStatus(const std::string& callId) -{ - return DRing::getCallMediaHandlerStatus(callId); -} diff --git a/bin/dbus/dbuspluginmanagerinterface.h b/bin/dbus/dbuspluginmanagerinterface.h index 5474754ad198be51e7662afc1ed4e5a795a23744..681af59542508719f4a48431b12be0d167d6be3d 100644 --- a/bin/dbus/dbuspluginmanagerinterface.h +++ b/bin/dbus/dbuspluginmanagerinterface.h @@ -54,7 +54,6 @@ public: // Methods bool loadPlugin(const std::string& path); bool unloadPlugin(const std::string& path); - void togglePlugin(const std::string& path, const bool& toggle); std::map<std::string, std::string> getPluginDetails(const std::string& path); std::vector<std::map<std::string, std::string>> getPluginPreferences(const std::string& path); bool setPluginPreference(const std::string& path, @@ -62,18 +61,25 @@ public: const std::string& value); std::map<std::string, std::string> getPluginPreferencesValues(const std::string& path); bool resetPluginPreferencesValues(const std::string& path); - std::vector<std::string> listAvailablePlugins(); - std::vector<std::string> listLoadedPlugins(); + std::vector<std::string> getInstalledPlugins(); + std::vector<std::string> getLoadedPlugins(); int installPlugin(const std::string& jplPath, const bool& force); int uninstallPlugin(const std::string& pluginRootPath); - std::vector<std::string> listCallMediaHandlers(); + std::vector<std::string> getCallMediaHandlers(); + std::vector<std::string> getChatHandlers(); void toggleCallMediaHandler(const std::string& mediaHandlerId, const std::string& callId, const bool& toggle); + void toggleChatHandler(const std::string& chatHandlerId, + const std::string& accountId, + const std::string& peerId, + const bool& toggle); std::map<std::string, std::string> getCallMediaHandlerDetails(const std::string& mediaHandlerId); + std::vector<std::string> getCallMediaHandlerStatus(const std::string& callId); + std::map<std::string, std::string> getChatHandlerDetails(const std::string& chatHandlerId); + std::vector<std::string> getChatHandlerStatus(const std::string& accontId, + const std::string& peerId); bool getPluginsEnabled(); void setPluginsEnabled(const bool& state); - std::map<std::string, std::vector<std::string>> getCallMediaHandlerStatus( - const std::string& callId); }; diff --git a/bin/jni/plugin_manager_interface.i b/bin/jni/plugin_manager_interface.i index 4552457ea64b0c5321d3735ee0307596d5415c72..8f7086df6ca852bf2a232c4f23ace1c2d8f65244 100644 --- a/bin/jni/plugin_manager_interface.i +++ b/bin/jni/plugin_manager_interface.i @@ -26,20 +26,23 @@ namespace DRing { bool loadPlugin(const std::string& path); bool unloadPlugin(const std::string& path); -void togglePlugin(const std::string& path, bool toggle); std::map<std::string,std::string> getPluginDetails(const std::string& path); std::vector<std::map<std::string,std::string>> getPluginPreferences(const std::string& path); bool setPluginPreference(const std::string& path, const std::string& key, const std::string& value); std::map<std::string,std::string> getPluginPreferencesValues(const std::string& path); bool resetPluginPreferencesValues(const std::string& path); -std::vector<std::string> listAvailablePlugins(); -std::vector<std::string> listLoadedPlugins(); +std::vector<std::string> getInstalledPlugins(); +std::vector<std::string> getLoadedPlugins(); int installPlugin(const std::string& jplPath, bool force); int uninstallPlugin(const std::string& pluginRootPath); -std::vector<std::string> listCallMediaHandlers(); +std::vector<std::string> getCallMediaHandlers(); +std::vector<std::string> getChatHandlers(); void toggleCallMediaHandler(const std::string& mediaHandlerId, const std::string& callId, bool toggle); +void toggleChatHandler(const std::string& chatHandlerId, const std::string& accountId, const std::string& peerId, bool toggle); std::map<std::string,std::string> getCallMediaHandlerDetails(const std::string& mediaHandlerId); +std::vector<std::string> getCallMediaHandlerStatus(const std::string& callId); +std::map<std::string,std::string> getChatHandlerDetails(const std::string& chatHandlerId); +std::vector<std::string> getChatHandlerStatus(const std::string& accountId, const std::string& peerId); bool getPluginsEnabled(); void setPluginsEnabled(bool state); -std::map<std::string, std::vector<std::string>> getCallMediaHandlerStatus(const std::string& callId); } diff --git a/contrib/src/ffnvcodec/rules.mak b/contrib/src/ffnvcodec/rules.mak index 6c7ea15e31d2e4990b49c467a78c3c72949ad4f9..26dd855db2aeae9c96d457528e7cf51f10c4a8ca 100644 --- a/contrib/src/ffnvcodec/rules.mak +++ b/contrib/src/ffnvcodec/rules.mak @@ -1,5 +1,5 @@ # ffnvcodec -FFNVCODEC_VERSION := n10.0.26.0 +FFNVCODEC_VERSION := n11.0.10.0 FFNVCODEC_GITURL := https://git.videolan.org/git/ffmpeg/nv-codec-headers.git ifeq ($(call need_pkg,"ffnvcodec >= 8"),) diff --git a/meson.build b/meson.build index 86b0643e0939b7242fd342b9ecb79e1292d08451..f8e660811c7f807fb789b3833aafac532249afc8 100644 --- a/meson.build +++ b/meson.build @@ -1,5 +1,5 @@ project('jami-daemon', ['c', 'cpp'], - version: '9.6.0', + version: '9.9.0', license: 'GPL3+', default_options: ['cpp_std=gnu++17', 'buildtype=debugoptimized'], meson_version:'>= 0.54' diff --git a/src/call.cpp b/src/call.cpp index 757992842c48badd42c033b6e81ad2f2a0f06bab..556c20b03f3d00d7dfce9e18c61ce95924e088ed 100644 --- a/src/call.cpp +++ b/src/call.cpp @@ -23,6 +23,10 @@ #include "call.h" #include "account.h" #include "manager.h" +#ifdef ENABLE_PLUGIN +#include "plugin/jamipluginmanager.h" +#include "plugin/streamdata.h" +#endif #include "audio/ringbufferpool.h" #include "dring/call_const.h" #include "client/ring_signal.h" @@ -410,6 +414,14 @@ Call::onTextMessage(std::map<std::string, std::string>&& messages) return; } } +#ifdef ENABLE_PLUGIN + auto& pluginChatManager + = jami::Manager::instance().getJamiPluginManager().getChatServicesManager(); + std::shared_ptr<JamiMessage> cm = std::make_shared<JamiMessage>( + getAccountId(), getPeerNumber(), true, const_cast<std::map<std::string, std::string>&>(messages), false); + pluginChatManager.publishMessage(cm); + +#endif Manager::instance().incomingMessage(getCallId(), getPeerNumber(), messages); } diff --git a/src/client/plugin_manager_interface.cpp b/src/client/plugin_manager_interface.cpp index 5b7911fc8e11cc105ea6abf740da8bac15f1c184..0840725d21f1ac1b541e50e2a9e413cf6795ec35 100644 --- a/src/client/plugin_manager_interface.cpp +++ b/src/client/plugin_manager_interface.cpp @@ -45,12 +45,6 @@ unloadPlugin(const std::string& path) return status; } -void -togglePlugin(const std::string& path, bool toggle) -{ - jami::Manager::instance().getJamiPluginManager().togglePlugin(path, toggle); -} - std::map<std::string, std::string> getPluginDetails(const std::string& path) { @@ -81,15 +75,15 @@ resetPluginPreferencesValues(const std::string& path) } std::vector<std::string> -listAvailablePlugins() +getInstalledPlugins() { - return jami::Manager::instance().getJamiPluginManager().listAvailablePlugins(); + return jami::Manager::instance().getJamiPluginManager().getInstalledPlugins(); } std::vector<std::string> -listLoadedPlugins() +getLoadedPlugins() { - return jami::Manager::instance().getJamiPluginManager().listLoadedPlugins(); + return jami::Manager::instance().getJamiPluginManager().getLoadedPlugins(); } int @@ -105,12 +99,21 @@ uninstallPlugin(const std::string& pluginRootPath) } std::vector<std::string> -listCallMediaHandlers() +getCallMediaHandlers() { return jami::Manager::instance() .getJamiPluginManager() .getCallServicesManager() - .listCallMediaHandlers(); + .getCallMediaHandlers(); +} + +std::vector<std::string> +getChatHandlers() +{ + return jami::Manager::instance() + .getJamiPluginManager() + .getChatServicesManager() + .getChatHandlers(); } void @@ -122,6 +125,18 @@ toggleCallMediaHandler(const std::string& mediaHandlerId, const std::string& cal .toggleCallMediaHandler(mediaHandlerId, callId, toggle); } +void +toggleChatHandler(const std::string& chatHandlerId, + const std::string& accountId, + const std::string& peerId, + bool toggle) +{ + return jami::Manager::instance() + .getJamiPluginManager() + .getChatServicesManager() + .toggleChatHandler(chatHandlerId, accountId, peerId, toggle); +} + std::map<std::string, std::string> getCallMediaHandlerDetails(const std::string& mediaHandlerId) { @@ -131,6 +146,33 @@ getCallMediaHandlerDetails(const std::string& mediaHandlerId) .getCallMediaHandlerDetails(mediaHandlerId); } +std::vector<std::string> +getCallMediaHandlerStatus(const std::string& callId) +{ + return jami::Manager::instance() + .getJamiPluginManager() + .getCallServicesManager() + .getCallMediaHandlerStatus(callId); +} + +std::map<std::string, std::string> +getChatHandlerDetails(const std::string& chatHandlerId) +{ + return jami::Manager::instance() + .getJamiPluginManager() + .getChatServicesManager() + .getChatHandlerDetails(chatHandlerId); +} + +std::vector<std::string> +getChatHandlerStatus(const std::string& accountId, const std::string& peerId) +{ + return jami::Manager::instance() + .getJamiPluginManager() + .getChatServicesManager() + .getChatHandlerStatus(accountId, peerId); +} + bool getPluginsEnabled() { @@ -143,13 +185,4 @@ setPluginsEnabled(bool state) jami::Manager::instance().pluginPreferences.setPluginsEnabled(state); jami::Manager::instance().saveConfig(); } - -std::map<std::string, std::vector<std::string>> -getCallMediaHandlerStatus(const std::string& callId) -{ - return jami::Manager::instance() - .getJamiPluginManager() - .getCallServicesManager() - .getCallMediaHandlerStatus(callId); -} } // namespace DRing diff --git a/src/dring/plugin_manager_interface.h b/src/dring/plugin_manager_interface.h index 19bd8ade9a799138a02372772d9ef2d1e03d3cb4..6c91e57d5fee51e741cf3e162109112697498bc4 100644 --- a/src/dring/plugin_manager_interface.h +++ b/src/dring/plugin_manager_interface.h @@ -36,7 +36,6 @@ namespace DRing { DRING_PUBLIC bool loadPlugin(const std::string& path); DRING_PUBLIC bool unloadPlugin(const std::string& path); -DRING_PUBLIC void togglePlugin(const std::string& path, bool toggle); DRING_PUBLIC std::map<std::string, std::string> getPluginDetails(const std::string& path); DRING_PUBLIC std::vector<std::map<std::string, std::string>> getPluginPreferences( const std::string& path); @@ -45,18 +44,26 @@ DRING_PUBLIC bool setPluginPreference(const std::string& path, const std::string& value); DRING_PUBLIC std::map<std::string, std::string> getPluginPreferencesValues(const std::string& path); DRING_PUBLIC bool resetPluginPreferencesValues(const std::string& path); -DRING_PUBLIC std::vector<std::string> listAvailablePlugins(); -DRING_PUBLIC std::vector<std::string> listLoadedPlugins(); +DRING_PUBLIC std::vector<std::string> getInstalledPlugins(); +DRING_PUBLIC std::vector<std::string> getLoadedPlugins(); DRING_PUBLIC int installPlugin(const std::string& jplPath, bool force); DRING_PUBLIC int uninstallPlugin(const std::string& pluginRootPath); -DRING_PUBLIC std::vector<std::string> listCallMediaHandlers(); +DRING_PUBLIC std::vector<std::string> getCallMediaHandlers(); +DRING_PUBLIC std::vector<std::string> getChatHandlers(); DRING_PUBLIC void toggleCallMediaHandler(const std::string& mediaHandlerId, const std::string& callId, bool toggle); +DRING_PUBLIC void toggleChatHandler(const std::string& chatHandlerId, + const std::string& accountId, + const std::string& peerId, + bool toggle); DRING_PUBLIC std::map<std::string, std::string> getCallMediaHandlerDetails( const std::string& mediaHandlerId); +DRING_PUBLIC std::vector<std::string> getCallMediaHandlerStatus(const std::string& callId); +DRING_PUBLIC std::map<std::string, std::string> getChatHandlerDetails( + const std::string& chatHandlerId); +DRING_PUBLIC std::vector<std::string> getChatHandlerStatus(const std::string& accountId, + const std::string& peerId); DRING_PUBLIC bool getPluginsEnabled(); DRING_PUBLIC void setPluginsEnabled(bool state); -DRING_PUBLIC std::map<std::string, std::vector<std::string>> getCallMediaHandlerStatus( - const std::string& callId); } // namespace DRing diff --git a/src/jamidht/contact_list.cpp b/src/jamidht/contact_list.cpp index ad8ff44460f417ca1452cfe704c5bdc1081729ff..bb4b4ec8fcd98441a8a322cbfd79367e3615b7ab 100644 --- a/src/jamidht/contact_list.cpp +++ b/src/jamidht/contact_list.cpp @@ -20,6 +20,11 @@ #include "jamiaccount.h" #include "fileutils.h" +#ifdef ENABLE_PLUGIN +#include "manager.h" +#include "plugin/jamipluginmanager.h" +#endif + #include "account_const.h" #include <fstream> @@ -102,6 +107,16 @@ ContactList::removeContact(const dht::InfoHash& h, bool ban) if (ban and trustRequests_.erase(h) > 0) saveTrustRequests(); saveContacts(); +#ifdef ENABLE_PLUGIN + std::size_t found = path_.find_last_of(DIR_SEPARATOR_CH); + if (found != std::string::npos) { + auto filename = path_.substr(found + 1); + jami::Manager::instance() + .getJamiPluginManager() + .getChatServicesManager() + .cleanChatSubjects(filename, uri); + } +#endif callbacks_.contactRemoved(uri, ban); return true; } @@ -414,19 +429,20 @@ ContactList::foundAccountDevice(const std::shared_ptr<dht::crypto::Certificate>& name.c_str(), crt->getId().toString().c_str()); tls::CertificateStore::instance().pinCertificate(crt); - if (crt->ocspResponse){ + if (crt->ocspResponse) { unsigned int status = crt->ocspResponse->getCertificateStatus(); - if (status == GNUTLS_OCSP_CERT_GOOD){ + if (status == GNUTLS_OCSP_CERT_GOOD) { JAMI_DBG("Certificate %s has good OCSP status", crt->getId().to_c_str()); - trust_.setCertificateStatus(crt->getId().toString(), tls::TrustStore::PermissionStatus::ALLOWED); - } - else if (status == GNUTLS_OCSP_CERT_REVOKED){ + trust_.setCertificateStatus(crt->getId().toString(), + tls::TrustStore::PermissionStatus::ALLOWED); + } else if (status == GNUTLS_OCSP_CERT_REVOKED) { JAMI_ERR("Certificate %s has revoked OCSP status", crt->getId().to_c_str()); - trust_.setCertificateStatus(crt->getId().toString(), tls::TrustStore::PermissionStatus::BANNED); - } - else { + trust_.setCertificateStatus(crt->getId().toString(), + tls::TrustStore::PermissionStatus::BANNED); + } else { JAMI_ERR("Certificate %s has unknown OCSP status", crt->getId().to_c_str()); - trust_.setCertificateStatus(crt->getId().toString(), tls::TrustStore::PermissionStatus::UNDEFINED); + trust_.setCertificateStatus(crt->getId().toString(), + tls::TrustStore::PermissionStatus::UNDEFINED); } } saveKnownDevices(); diff --git a/src/jamidht/jamiaccount.cpp b/src/jamidht/jamiaccount.cpp index 1a03c9772cd81ef0528d0420ee93b7864f117264..a1357123d370a0b08ee30db43e4076e6a53c055f 100644 --- a/src/jamidht/jamiaccount.cpp +++ b/src/jamidht/jamiaccount.cpp @@ -61,6 +61,11 @@ #include "manager.h" #include "utf8_utils.h" +#ifdef ENABLE_PLUGIN +#include "plugin/jamipluginmanager.h" +#include "plugin/chatservicesmanager.h" +#endif + #ifdef ENABLE_VIDEO #include "libav_utils.h" #endif @@ -2570,6 +2575,10 @@ JamiAccount::doUnregister(std::function<void(bool)> released_cb) if (released_cb) released_cb(false); +#ifdef ENABLE_PLUGIN + jami::Manager::instance().getJamiPluginManager().getChatServicesManager().cleanChatSubjects( + getAccountID()); +#endif } void diff --git a/src/manager.cpp b/src/manager.cpp index c309bd6bfe8f6942eceddc7706e6dfdc5e59350b..3dbf5a87d5a9275010a4b4508822ce0911fc9fc2 100644 --- a/src/manager.cpp +++ b/src/manager.cpp @@ -68,6 +68,7 @@ using random_device = dht::crypto::random_device; #ifdef ENABLE_PLUGIN #include "plugin/jamipluginmanager.h" +#include "plugin/streamdata.h" #endif #ifdef ENABLE_VIDEO @@ -1708,8 +1709,8 @@ Manager::scheduleTask(std::function<void()>&& task, std::chrono::steady_clock::t return pimpl_->scheduler_.schedule(std::move(task), when); } -std::shared_ptr<Task> Manager::scheduleTaskIn(std::function<void()>&& task, - std::chrono::steady_clock::duration timeout) +std::shared_ptr<Task> +Manager::scheduleTaskIn(std::function<void()>&& task, std::chrono::steady_clock::duration timeout) { return pimpl_->scheduler_.scheduleIn(std::move(task), timeout); } @@ -3071,18 +3072,24 @@ Manager::isPasswordValid(const std::string& accountID, const std::string& passwo uint64_t Manager::sendTextMessage(const std::string& accountID, const std::string& to, - const std::map<std::string, std::string>& payloads) + const std::map<std::string, std::string>& payloads, + const bool fromPlugin) { if (const auto acc = getAccount(accountID)) { try { -#ifdef ENABLE_PLUGIN - auto& convManager - = jami::Manager::instance().getJamiPluginManager().getConversationServicesManager(); - std::shared_ptr<jami::ConversationMessage> cm - = std::make_shared<jami::ConversationMessage>( - accountID, to, const_cast<std::map<std::string, std::string>&>(payloads)); - convManager.sendTextMessage(cm); - return acc->sendTextMessage(cm->to_, cm->data_); +#ifdef ENABLE_PLUGIN // modifies send message + auto& pluginChatManager + = jami::Manager::instance().getJamiPluginManager().getChatServicesManager(); + std::shared_ptr<JamiMessage> cm + = std::make_shared<JamiMessage>(accountID, + to, + false, + const_cast<std::map<std::string, std::string>&>( + payloads), + fromPlugin); + if (!fromPlugin) + pluginChatManager.publishMessage(cm); + return acc->sendTextMessage(cm->peerId, cm->data); #else return acc->sendTextMessage(to, payloads); #endif // ENABLE_PLUGIN @@ -3257,7 +3264,9 @@ Manager::setModerator(const std::string& confId, const std::string& peerId, cons if (auto conf = getConferenceFromID(confId)) { conf->setModerator(peerId, state); } else - JAMI_WARN("Fail to change moderator %s, conference %s not found", peerId.c_str(), confId.c_str()); + JAMI_WARN("Fail to change moderator %s, conference %s not found", + peerId.c_str(), + confId.c_str()); } void diff --git a/src/manager.h b/src/manager.h index b4a62f3b487c021a60e77f5fa085898827e7b83b..60012200fa2895dabcf0f9362cf0cdde38e292cd 100644 --- a/src/manager.h +++ b/src/manager.h @@ -415,7 +415,8 @@ public: uint64_t sendTextMessage(const std::string& accountID, const std::string& to, - const std::map<std::string, std::string>& payloads); + const std::map<std::string, std::string>& payloads, + const bool fromPlugin = false); int getMessageStatus(uint64_t id) const; int getMessageStatus(const std::string& accountID, uint64_t id) const; @@ -894,7 +895,7 @@ public: std::shared_ptr<Task> scheduleTask(std::function<void()>&& task, std::chrono::steady_clock::time_point when); std::shared_ptr<Task> scheduleTaskIn(std::function<void()>&& task, - std::chrono::steady_clock::duration timeout); + std::chrono::steady_clock::duration timeout); std::map<std::string, std::string> getNearbyPeers(const std::string& accountID); diff --git a/src/meson.build b/src/meson.build index 82a31297f600718972b8107e19f4ddb8ee1d8d97..5a873190509443822efe0aba73e255e9aaebee2d 100644 --- a/src/meson.build +++ b/src/meson.build @@ -273,7 +273,8 @@ if conf.get('ENABLE_PLUGIN') 'client/plugin_manager_interface.cpp', 'plugin/jamipluginmanager.cpp', 'plugin/pluginloaderdl.cpp', - 'plugin/pluginmanager.cpp' + 'plugin/pluginmanager.cpp', + 'plugin/pluginpreferencesutils.cpp' ) libjami_dependencies += [deplibarchive, depdl] endif diff --git a/src/plugin/CMakeLists.txt b/src/plugin/CMakeLists.txt index 25224bd81d552f14c63faf80632fd7dd61e09775..65a18b391803860d92a9dc9911328dcc49a31d95 100644 --- a/src/plugin/CMakeLists.txt +++ b/src/plugin/CMakeLists.txt @@ -5,14 +5,18 @@ list (APPEND Source_Files__plugin "${CMAKE_CURRENT_SOURCE_DIR}/jamipluginmanager.cpp" "${CMAKE_CURRENT_SOURCE_DIR}/pluginloaderdl.cpp" "${CMAKE_CURRENT_SOURCE_DIR}/pluginmanager.cpp" + "${CMAKE_CURRENT_SOURCE_DIR}/pluginpreferencesutils.cpp" "${CMAKE_CURRENT_SOURCE_DIR}/callservicesmanager.h" - "${CMAKE_CURRENT_SOURCE_DIR}/conversationservicesmanager.h" - "${CMAKE_CURRENT_SOURCE_DIR}/conversationhandler.h" + "${CMAKE_CURRENT_SOURCE_DIR}/callservicesmanager.cpp" + "${CMAKE_CURRENT_SOURCE_DIR}/chatservicesmanager.h" + "${CMAKE_CURRENT_SOURCE_DIR}/chatservicesmanager.cpp" + "${CMAKE_CURRENT_SOURCE_DIR}/chathandler.h" "${CMAKE_CURRENT_SOURCE_DIR}/jamiplugin.h" "${CMAKE_CURRENT_SOURCE_DIR}/jamipluginmanager.h" "${CMAKE_CURRENT_SOURCE_DIR}/mediahandler.h" "${CMAKE_CURRENT_SOURCE_DIR}/pluginloader.h" "${CMAKE_CURRENT_SOURCE_DIR}/pluginmanager.h" + "${CMAKE_CURRENT_SOURCE_DIR}/pluginpreferencesutils.h" "${CMAKE_CURRENT_SOURCE_DIR}/streamdata.h" ) diff --git a/src/plugin/Makefile.am b/src/plugin/Makefile.am index b528b290233286609d1c7661ab52506851d0a882..b02cadf6fdb9d0e9bf6dc12d7726437c9434f776 100644 --- a/src/plugin/Makefile.am +++ b/src/plugin/Makefile.am @@ -4,19 +4,23 @@ noinst_LTLIBRARIES = libplugin.la noinst_HEADERS = \ callservicesmanager.h \ - conversationhandler.h \ - conversationservicesmanager.h \ + chathandler.h \ + chatservicesmanager.h \ jamiplugin.h \ jamipluginmanager.h \ mediahandler.h \ pluginloader.h \ pluginmanager.h \ + pluginpreferencesutils.h \ streamdata.h libplugin_la_SOURCES = \ jamipluginmanager.cpp \ pluginloaderdl.cpp \ - pluginmanager.cpp + pluginmanager.cpp \ + pluginpreferencesutils.cpp \ + chatservicesmanager.cpp \ + callservicesmanager.cpp libplugin_la_LIBADD = @ARCHIVE_LIBS@ diff --git a/src/plugin/callservicesmanager.cpp b/src/plugin/callservicesmanager.cpp new file mode 100644 index 0000000000000000000000000000000000000000..6ab148663be84fc62e7cf215060e1295bcd753ac --- /dev/null +++ b/src/plugin/callservicesmanager.cpp @@ -0,0 +1,229 @@ +/** + * Copyright (C)2020-2021 Savoir-faire Linux Inc. + * + * Author: Aline Gondim Santos <aline.gondimsantos@savoirfairelinux.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include "callservicesmanager.h" +#include "logger.h" +#include "sip/sipcall.h" +#include "fileutils.h" +#include "pluginpreferencesutils.h" +#include "manager.h" + +namespace jami { + +CallServicesManager::CallServicesManager(PluginManager& pm) +{ + registerComponentsLifeCycleManagers(pm); +} + +CallServicesManager::~CallServicesManager() +{ + callMediaHandlers_.clear(); +} + +void +CallServicesManager::createAVSubject(const StreamData& data, AVSubjectSPtr subject) +{ + // This guarantees unicity of subjects by id + callAVsubjects_.emplace_back(data, subject); + + for (auto& callMediaHandler : callMediaHandlers_) { + std::size_t found = callMediaHandler->id().find_last_of(DIR_SEPARATOR_CH); + auto preferences = PluginPreferencesUtils::getPreferencesValuesMap(callMediaHandler->id().substr(0, found)); +#ifndef __ANDROID__ + if (preferences.at("always") == "1") + toggleCallMediaHandler((uintptr_t) callMediaHandler.get(), data.id, true); + else +#endif + for (const auto& toggledMediaHandler : mediaHandlerToggled_[data.id]) { + if (toggledMediaHandler == (uintptr_t) callMediaHandler.get()) { + toggleCallMediaHandler(toggledMediaHandler, data.id, true); + break; + } + } + } +} + +void +CallServicesManager::clearAVSubject(const std::string& callId) +{ + for (auto it = callAVsubjects_.begin(); it != callAVsubjects_.end();) { + if (it->first.id == callId) { + it = callAVsubjects_.erase(it); + } else { + ++it; + } + } +} + +void +CallServicesManager::registerComponentsLifeCycleManagers(PluginManager& pm) +{ + auto registerCallMediaHandler = [this](void* data) { + CallMediaHandlerPtr ptr {(static_cast<CallMediaHandler*>(data))}; + + if (!ptr) + return -1; + callMediaHandlers_.emplace_back(std::move(ptr)); + return 0; + }; + + auto unregisterMediaHandler = [this](void* data) { + for (auto it = callMediaHandlers_.begin(); it != callMediaHandlers_.end(); ++it) { + if (it->get() == data) { + callMediaHandlers_.erase(it); + break; + } + } + return 0; + }; + + pm.registerComponentManager("CallMediaHandlerManager", + registerCallMediaHandler, + unregisterMediaHandler); +} + +std::vector<std::string> +CallServicesManager::getCallMediaHandlers() +{ + std::vector<std::string> res; + res.reserve(callMediaHandlers_.size()); + for (const auto& mediaHandler : callMediaHandlers_) { + res.emplace_back(std::to_string((uintptr_t) mediaHandler.get())); + } + return res; +} + +void +CallServicesManager::toggleCallMediaHandler(const std::string& mediaHandlerId, + const std::string& callId, + const bool toggle) +{ + toggleCallMediaHandler(std::stoull(mediaHandlerId), callId, toggle); +} + +std::map<std::string, std::string> +CallServicesManager::getCallMediaHandlerDetails(const std::string& mediaHandlerIdStr) +{ + auto mediaHandlerId = std::stoull(mediaHandlerIdStr); + for (auto& mediaHandler : callMediaHandlers_) { + if ((uintptr_t) mediaHandler.get() == mediaHandlerId) { + return mediaHandler->getCallMediaHandlerDetails(); + } + } + return {}; +} + +bool +CallServicesManager::isVideoType(const CallMediaHandlerPtr& mediaHandler) +{ + const auto& details = mediaHandler->getCallMediaHandlerDetails(); + const auto& it = details.find("dataType"); + if (it != details.end()) { + bool status; + std::istringstream(it->second) >> status; + return status; + } + return true; +} + +bool +CallServicesManager::isAttached(const CallMediaHandlerPtr& mediaHandler) +{ + const auto& details = mediaHandler->getCallMediaHandlerDetails(); + const auto& it = details.find("attached"); + if (it != details.end()) { + bool status; + std::istringstream(it->second) >> status; + return status; + } + return true; +} + +std::vector<std::string> +CallServicesManager::getCallMediaHandlerStatus(const std::string& callId) +{ + std::vector<std::string> ret; + const auto& it = mediaHandlerToggled_.find(callId); + if (it != mediaHandlerToggled_.end()) { + ret.reserve(it->second.size()); + for (const auto& mediaHandlerId : it->second) + ret.emplace_back(std::to_string(mediaHandlerId)); + } + return ret; +} + +void +CallServicesManager::setPreference(const std::string& key, const std::string& value, const std::string& scopeStr) +{ + for (auto& mediaHandler : callMediaHandlers_) { + if (scopeStr.find(mediaHandler->getCallMediaHandlerDetails()["name"]) + != std::string::npos) { + mediaHandler->setPreferenceAttribute(key, value); + } + } +} + +void +CallServicesManager::notifyAVSubject(CallMediaHandlerPtr& callMediaHandlerPtr, + const StreamData& data, + AVSubjectSPtr& subject) +{ + if (auto soSubject = subject.lock()) + callMediaHandlerPtr->notifyAVFrameSubject(data, soSubject); +} + +void +CallServicesManager::toggleCallMediaHandler(const uintptr_t mediaHandlerId, + const std::string& callId, + const bool toggle) +{ + auto& handlers = mediaHandlerToggled_[callId]; + + bool applyRestart = false; + + for (auto subject : callAVsubjects_) { + if (subject.first.id == callId) { + + auto handlerIt = std::find_if(callMediaHandlers_.begin(), callMediaHandlers_.end(), + [mediaHandlerId](CallMediaHandlerPtr& handler) { + return ((uintptr_t) handler.get() == mediaHandlerId); + }); + + if (handlerIt != callMediaHandlers_.end()) { + if (toggle) { + notifyAVSubject((*handlerIt), subject.first, subject.second); + if (isAttached((*handlerIt)) + && handlers.find(mediaHandlerId) == handlers.end()) + handlers.insert(mediaHandlerId); + } else { + (*handlerIt)->detach(); + handlers.erase(mediaHandlerId); + } + if (subject.first.type == StreamType::video && isVideoType((*handlerIt))) + applyRestart = true; + } + } + } +#ifndef __ANDROID__ + if (applyRestart) + Manager::instance().callFactory.getCall<SIPCall>(callId)->getVideoRtp().restartSender(); +#endif +} +} // namespace jami diff --git a/src/plugin/callservicesmanager.h b/src/plugin/callservicesmanager.h index 38c3a7de1c260096601d05af48b7f2b4ad72df70..8ab1a5a62bf2b683d598682d4b2029ebce0428e2 100644 --- a/src/plugin/callservicesmanager.h +++ b/src/plugin/callservicesmanager.h @@ -19,16 +19,11 @@ */ #pragma once -// Utils + #include "noncopyable.h" -#include "logger.h" -#include "manager.h" -#include "sip/sipcall.h" -// Plugin Manager #include "pluginmanager.h" #include "streamdata.h" #include "mediahandler.h" -// STL #include <list> #include <set> #include <tuple> @@ -41,205 +36,71 @@ using AVSubjectSPtr = std::weak_ptr<Observable<AVFrame*>>; class CallServicesManager { public: - CallServicesManager(PluginManager& pm) { registerComponentsLifeCycleManagers(pm); } + CallServicesManager(PluginManager& pm); /** * unload all media handlers **/ - ~CallServicesManager() { callMediaHandlers.clear(); } + ~CallServicesManager(); NON_COPYABLE(CallServicesManager); -public: /** * @brief createAVSubject * @param data * Creates an av frame subject with properties StreamData */ - void createAVSubject(const StreamData& data, AVSubjectSPtr subject) - { - // This guarantees unicity of subjects by id - callAVsubjects.push_back(std::make_pair(data, subject)); - for (const auto& toggledMediaHandler : mediaHandlerToggled_[data.id]) { - toggleCallMediaHandler(toggledMediaHandler, data.id, true); - } - } + void createAVSubject(const StreamData& data, AVSubjectSPtr subject); - void clearAVSubject(const std::string& callId) - { - for (auto it = callAVsubjects.begin(); it != callAVsubjects.end();) { - if (it->first.id == callId) { - it = callAVsubjects.erase(it); - } else { - ++it; - } - } - } + void clearAVSubject(const std::string& callId); /** * @brief registerComponentsLifeCycleManagers * Exposes components life cycle managers to the main API */ - void registerComponentsLifeCycleManagers(PluginManager& pm) - { - auto registerCallMediaHandler = [this](void* data) { - CallMediaHandlerPtr ptr {(static_cast<CallMediaHandler*>(data))}; - - if (ptr) { - callMediaHandlers.emplace_back(std::move(ptr)); - } - return 0; - }; - - auto unregisterMediaHandler = [this](void* data) { - for (auto it = callMediaHandlers.begin(); it != callMediaHandlers.end(); ++it) { - if (it->get() == data) { - callMediaHandlers.erase(it); - break; - } - } - return 0; - }; - - pm.registerComponentManager("CallMediaHandlerManager", - registerCallMediaHandler, - unregisterMediaHandler); - } + void registerComponentsLifeCycleManagers(PluginManager& pm); /** - * @brief listCallMediaHandlers + * @brief getCallMediaHandlers * List all call media handlers * @return */ - std::vector<std::string> listCallMediaHandlers() - { - std::vector<std::string> res; - for (const auto& mediaHandler : callMediaHandlers) { - res.emplace_back(getCallHandlerId(mediaHandler)); - } - return res; - } + std::vector<std::string> getCallMediaHandlers(); /** * @brief toggleCallMediaHandler * Toggle CallMediaHandler, if on, notify with new subjects * if off, detach it - * @param id + * @param mediaHandler ID handler ID + * @param callId call ID + * @param toggle notify with new subjects if true, detach if false. + * + * In the case when the mediaHandler receives a hardware format + * frame and converts it to main memory, we need to restart the + * sender to unlink ours encoder and decoder. + * + * When we deactivate a mediaHandler, we try to relink the encoder + * and decoder by restarting the sender. */ void toggleCallMediaHandler(const std::string& mediaHandlerId, const std::string& callId, - const bool toggle) - { - if (mediaHandlerId.empty() || callId.empty()) - return; - - auto find = mediaHandlerToggled_.find(callId); - if (find == mediaHandlerToggled_.end()) - mediaHandlerToggled_[callId] = {}; - bool applyRestart = false; - for (auto it = callAVsubjects.begin(); it != callAVsubjects.end(); ++it) { - if (it->first.id == callId) { - for (auto& mediaHandler : callMediaHandlers) { - if (getCallHandlerId(mediaHandler) == mediaHandlerId) { - if (toggle) { - notifyAVSubject(mediaHandler, it->first, it->second); - if (isAttached(mediaHandler) - && mediaHandlerToggled_[callId].find(mediaHandlerId) - == mediaHandlerToggled_[callId].end()) - mediaHandlerToggled_[callId].insert(mediaHandlerId); - } else { - mediaHandler->detach(); - if (mediaHandlerToggled_[callId].find(mediaHandlerId) - != mediaHandlerToggled_[callId].end()) - mediaHandlerToggled_[callId].erase(mediaHandlerId); - } - if (it->first.type == StreamType::video && isVideoType(mediaHandler)) - applyRestart = true; - break; - } - } - } - } - - /* In the case when the mediaHandler receives a hardware format - * frame and converts it to main memory, we need to restart the - * sender to unlink ours encoder and decoder. - * - * When we deactivate a mediaHandler, we try to relink the encoder - * and decoder by restarting the sender. - */ - if (applyRestart) - Manager::instance().callFactory.getCall<SIPCall>(callId)->getVideoRtp().restartSender(); - } + const bool toggle); /** * @brief getCallMediaHandlerDetails * @param id of the call media handler * @return map of Call Media Handler Details */ - std::map<std::string, std::string> getCallMediaHandlerDetails(const std::string& mediaHandlerId) - { - for (auto& mediaHandler : callMediaHandlers) { - if (getCallHandlerId(mediaHandler) == mediaHandlerId) { - return mediaHandler->getCallMediaHandlerDetails(); - } - } - return {}; - } + std::map<std::string, std::string> getCallMediaHandlerDetails( + const std::string& mediaHandlerIdStr); - bool isVideoType(const CallMediaHandlerPtr& mediaHandler) - { - const auto& details = mediaHandler->getCallMediaHandlerDetails(); - const auto& it = details.find("dataType"); - if (it != details.end()) { - JAMI_INFO() << "type: "; - bool status; - std::istringstream(it->second) >> status; - JAMI_INFO() << status; - return status; - } - JAMI_INFO() << "dataType not found"; - return true; - } + bool isVideoType(const CallMediaHandlerPtr& mediaHandler); - bool isAttached(const CallMediaHandlerPtr& mediaHandler) - { - const auto& details = mediaHandler->getCallMediaHandlerDetails(); - const auto& it = details.find("attached"); - if (it != details.end()) { - JAMI_INFO() << "status: "; - bool status; - std::istringstream(it->second) >> status; - JAMI_INFO() << status; - return status; - } - JAMI_INFO() << "attached not found"; - return true; - } + bool isAttached(const CallMediaHandlerPtr& mediaHandler); - std::map<std::string, std::vector<std::string>> getCallMediaHandlerStatus( - const std::string& callId) - { - const auto& it = mediaHandlerToggled_.find(callId); - if (it != mediaHandlerToggled_.end()) { - std::vector<std::string> ret; - for (const auto& mediaHandlerId : it->second) - ret.push_back(mediaHandlerId); - return {{callId, ret}}; - } + std::vector<std::string> getCallMediaHandlerStatus(const std::string& callId); - return {{callId, {}}}; - } - - void setPreference(const std::string& key, const std::string& value, const std::string& scopeStr) - { - for (auto& mediaHandler : callMediaHandlers) { - if (scopeStr.find(mediaHandler->getCallMediaHandlerDetails()["name"]) - != std::string::npos) { - mediaHandler->setPreferenceAttribute(key, value); - } - } - } + void setPreference(const std::string& key, const std::string& value, const std::string& scopeStr); private: /** @@ -250,61 +111,34 @@ private: */ void notifyAVSubject(CallMediaHandlerPtr& callMediaHandlerPtr, const StreamData& data, - AVSubjectSPtr& subject) - { - if (auto soSubject = subject.lock()) - callMediaHandlerPtr->notifyAVFrameSubject(data, soSubject); - } - - /** - * @brief listAvailableSubjects - * @param callMediaHandlerPtr - * This functions lets the call media handler component know which subjects are available - */ - void listAvailableSubjects(const std::string& callID, CallMediaHandlerPtr& callMediaHandlerPtr) - { - for (auto it = callAVsubjects.begin(); it != callAVsubjects.end(); ++it) { - if (it->first.id == callID) - notifyAVSubject(callMediaHandlerPtr, it->first, it->second); - } - } + AVSubjectSPtr& subject); - /** - * @brief getCallHandlerId - * Returns the callMediaHandler id from a callMediaHandler pointer - * @param callMediaHandler - * @return string id - */ - std::string getCallHandlerId(const CallMediaHandlerPtr& callMediaHandler) - { - if (callMediaHandler) { - std::ostringstream callHandlerIdStream; - callHandlerIdStream << callMediaHandler.get(); - return callHandlerIdStream.str(); - } - return ""; - } + void toggleCallMediaHandler(const uintptr_t mediaHandlerId, + const std::string& callId, + const bool toggle); -private: /** - * @brief callMediaHandlers + * @brief callMediaHandlers_ * Components that a plugin can register through registerCallMediaHandler service * These objects can then be notified with notifySubject * whenever there is a new CallAVSubject like a video receive */ - std::list<CallMediaHandlerPtr> callMediaHandlers; + std::list<CallMediaHandlerPtr> callMediaHandlers_; /** - * @brief callAVsubjects - * When there is a SIPCall, CallAVSubjects are created there + * @brief callAVsubjects_ + * When there is a SIPCall, CallAVSubjects_ are created there * Here we keep a reference to them in order to make them interact with - * CallMediaHandlers + * CallMediaHandlers_ * It is pushed to this list list */ - std::list<std::pair<const StreamData, AVSubjectSPtr>> callAVsubjects; - // std::map<std::string, std::tuple<const StreamData, AVSubjectSPtr>> callAVsubjects; + std::list<std::pair<const StreamData, AVSubjectSPtr>> callAVsubjects_; - std::map<std::string, std::set<std::string>> mediaHandlerToggled_; + /** + * @brief mediaHandlerToggled_ + * A map of callId and list of mediaHandlers pointers str + */ + std::map<std::string, std::set<uintptr_t>> mediaHandlerToggled_; // callId, list of mediaHandlers }; } // namespace jami diff --git a/src/plugin/chathandler.h b/src/plugin/chathandler.h new file mode 100644 index 0000000000000000000000000000000000000000..411f10019d4acda02728657435a7f520706babe1 --- /dev/null +++ b/src/plugin/chathandler.h @@ -0,0 +1,55 @@ +/* + * Copyright (C) 2020 Savoir-faire Linux Inc. + * + * Author: Aline Gondim Santos <aline.gondimsantos@savoirfairelinux.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#pragma once + +#include "observer.h" +#include "streamdata.h" +#include <string> +#include <map> + +namespace jami { + +using pluginMessagePtr = std::shared_ptr<JamiMessage>; +using chatSubjectPtr = std::shared_ptr<PublishObservable<pluginMessagePtr>>; + +class ChatHandler +{ +public: + virtual void notifyChatSubject(std::pair<std::string, std::string>& subjectConnection, + chatSubjectPtr subject) + = 0; + virtual std::map<std::string, std::string> getChatHandlerDetails() = 0; + virtual void detach(chatSubjectPtr subject) = 0; + virtual void setPreferenceAttribute(const std::string& key, const std::string& value) = 0; + virtual bool preferenceMapHasKey(const std::string& key) = 0; + + /** + * @brief id + * The id is the path of the plugin that created this MediaHandler + * @return + */ + std::string id() const { return id_; } + virtual void setId(const std::string& id) final { id_ = id; } + +private: + std::string id_; +}; +} // namespace jami diff --git a/src/plugin/chatservicesmanager.cpp b/src/plugin/chatservicesmanager.cpp new file mode 100644 index 0000000000000000000000000000000000000000..28f6ae1703e6cc9a5d1e2c7ad9f522c2adb9bc91 --- /dev/null +++ b/src/plugin/chatservicesmanager.cpp @@ -0,0 +1,208 @@ +/* + * Copyright (C) 2021 Savoir-faire Linux Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include "chatservicesmanager.h" +#include "pluginpreferencesutils.h" +#include "logger.h" +#include "manager.h" +#include "fileutils.h" + +namespace jami { + +ChatServicesManager::ChatServicesManager(PluginManager& pm) +{ + registerComponentsLifeCycleManagers(pm); + registerChatService(pm); +} + +void +ChatServicesManager::registerComponentsLifeCycleManagers(PluginManager& pm) +{ + auto registerChatHandler = [this](void* data) { + ChatHandlerPtr ptr {(static_cast<ChatHandler*>(data))}; + + if (!ptr) + return -1; + chatHandlers_.emplace_back(std::move(ptr)); + return 0; + }; + + auto unregisterChatHandler = [this](void* data) { + auto handlerIt = std::find_if(chatHandlers_.begin(), chatHandlers_.end(), + [data](ChatHandlerPtr& handler) { + return (handler.get() == data); + }); + + if (handlerIt != chatHandlers_.end()) { + for (auto& toggledList: chatHandlerToggled_) { + auto handlerId = std::find_if(toggledList.second.begin(), toggledList.second.end(), + [this, handlerIt](uintptr_t handlerId) { + return (handlerId == (uintptr_t) handlerIt->get()); + }); + if (handlerId != toggledList.second.end()) { + handlerId = toggledList.second.erase(handlerId); + (*handlerIt)->detach(chatSubjects_[toggledList.first]); + } + } + chatHandlers_.erase(handlerIt); + } + return 0; + }; + + pm.registerComponentManager("ChatHandlerManager", + registerChatHandler, + unregisterChatHandler); +} + +void +ChatServicesManager::registerChatService(PluginManager& pm) +{ + auto sendTextMessage = [this](const DLPlugin*, void* data) { + auto cm = static_cast<JamiMessage*>(data); + jami::Manager::instance().sendTextMessage(cm->accountId, cm->peerId, cm->data, true); + return 0; + }; + + pm.registerService("sendTextMessage", sendTextMessage); +} + +std::vector<std::string> +ChatServicesManager::getChatHandlers() +{ + std::vector<std::string> res; + res.reserve(chatHandlers_.size()); + for (const auto& chatHandler : chatHandlers_) { + res.emplace_back(std::to_string((uintptr_t) chatHandler.get())); + } + return res; +} + +void +ChatServicesManager::publishMessage(pluginMessagePtr& cm) +{ + if (cm->fromPlugin) + return; + std::pair<std::string, std::string> mPair(cm->accountId, cm->peerId); + auto& handlers = chatHandlerToggled_[mPair]; + for (auto& chatHandler : chatHandlers_) { + std::size_t found = chatHandler->id().find_last_of(DIR_SEPARATOR_CH); + auto preferences = PluginPreferencesUtils::getPreferencesValuesMap( + chatHandler->id().substr(0, found)); + bool toggled = false; + if (handlers.find((uintptr_t) chatHandler.get()) != handlers.end()) + toggled = true; + if (preferences.at("always") == "1" || toggled) { + chatSubjects_.emplace(mPair, std::make_shared<PublishObservable<pluginMessagePtr>>()); + if (!toggled) { + handlers.insert((uintptr_t) chatHandler.get()); + chatHandler->notifyChatSubject(mPair, chatSubjects_[mPair]); + } + chatSubjects_[mPair]->publish(cm); + } + } +} + +void +ChatServicesManager::cleanChatSubjects(const std::string& accountId, const std::string& peerId) +{ + std::pair<std::string, std::string> mPair(accountId, peerId); + for (auto it = chatSubjects_.begin(); it != chatSubjects_.end();) { + if (peerId.empty() && it->first.first == accountId) + it = chatSubjects_.erase(it); + else if (!peerId.empty() && it->first == mPair) + it = chatSubjects_.erase(it); + else + ++it; + } +} + +void +ChatServicesManager::toggleChatHandler(const std::string& chatHandlerId, + const std::string& accountId, + const std::string& peerId, + const bool toggle) +{ + toggleChatHandler(std::stoull(chatHandlerId), accountId, peerId, toggle); +} + +std::vector<std::string> +ChatServicesManager::getChatHandlerStatus(const std::string& accountId, + const std::string& peerId) +{ + std::pair<std::string, std::string> mPair(accountId, peerId); + const auto& it = chatHandlerToggled_.find(mPair); + std::vector<std::string> ret; + if (it != chatHandlerToggled_.end()) { + ret.reserve(it->second.size()); + for (const auto& chatHandlerId : it->second) + ret.emplace_back(std::to_string(chatHandlerId)); + return ret; + } + + return ret; +} + +std::map<std::string, std::string> +ChatServicesManager::getChatHandlerDetails(const std::string& chatHandlerIdStr) +{ + auto chatHandlerId = std::stoull(chatHandlerIdStr); + for (auto& chatHandler : chatHandlers_) { + if ((uintptr_t) chatHandler.get() == chatHandlerId) { + return chatHandler->getChatHandlerDetails(); + } + } + return {}; +} + +void +ChatServicesManager::setPreference(const std::string& key, const std::string& value, const std::string& scopeStr) +{ + for (auto& chatHandler : chatHandlers_) { + if (scopeStr.find(chatHandler->getChatHandlerDetails()["name"]) != std::string::npos) { + chatHandler->setPreferenceAttribute(key, value); + } + } +} + +void +ChatServicesManager::toggleChatHandler(const uintptr_t chatHandlerId, + const std::string& accountId, + const std::string& peerId, + const bool toggle) +{ + std::pair<std::string, std::string> mPair(accountId, peerId); + auto& handlers = chatHandlerToggled_[mPair]; + chatSubjects_.emplace(mPair, std::make_shared<PublishObservable<pluginMessagePtr>>()); + + auto chatHandlerIt = std::find_if(chatHandlers_.begin(), chatHandlers_.end(), + [chatHandlerId](ChatHandlerPtr& handler) { + return ((uintptr_t) handler.get() == chatHandlerId); + }); + + if (chatHandlerIt != chatHandlers_.end()) { + if (toggle) { + (*chatHandlerIt)->notifyChatSubject(mPair, chatSubjects_[mPair]); + if (handlers.find(chatHandlerId) == handlers.end()) + handlers.insert(chatHandlerId); + } else { + (*chatHandlerIt)->detach(chatSubjects_[mPair]); + handlers.erase(chatHandlerId); + } + } +} +} // namespace jami diff --git a/src/plugin/chatservicesmanager.h b/src/plugin/chatservicesmanager.h new file mode 100644 index 0000000000000000000000000000000000000000..de4bceb9ce5cde84ee6cb1a6158494c6a9658164 --- /dev/null +++ b/src/plugin/chatservicesmanager.h @@ -0,0 +1,74 @@ +/* + * Copyright (C) 2021 Savoir-faire Linux Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +#pragma once + +#include "noncopyable.h" +#include "pluginmanager.h" +#include "chathandler.h" + +namespace jami { + +using ChatHandlerPtr = std::unique_ptr<ChatHandler>; + +class ChatServicesManager +{ +public: + ChatServicesManager(PluginManager& pm); + + NON_COPYABLE(ChatServicesManager); + + void registerComponentsLifeCycleManagers(PluginManager& pm); + + void registerChatService(PluginManager& pm); + + std::vector<std::string> getChatHandlers(); + + void publishMessage(pluginMessagePtr& cm); + + void cleanChatSubjects(const std::string& accountId, const std::string& peerId = ""); + + void toggleChatHandler(const std::string& chatHandlerId, + const std::string& accountId, + const std::string& peerId, + const bool toggle); + + std::vector<std::string> getChatHandlerStatus(const std::string& accountId, + const std::string& peerId); + + /** + * @brief getChatHandlerDetails + * @param chatHandlerIdStr of the chat handler + * @return map of Chat Handler Details + */ + std::map<std::string, std::string> getChatHandlerDetails(const std::string& chatHandlerIdStr); + + void setPreference(const std::string& key, const std::string& value, const std::string& scopeStr); + +private: + void toggleChatHandler(const uintptr_t chatHandlerId, + const std::string& accountId, + const std::string& peerId, + const bool toggle); + + std::list<ChatHandlerPtr> chatHandlers_; + std::map<std::pair<std::string, std::string>, std::set<uintptr_t>> + chatHandlerToggled_; // {account,peer}, list of chatHandlers + + std::map<std::pair<std::string, std::string>, chatSubjectPtr> chatSubjects_; +}; +} // namespace jami diff --git a/src/plugin/conversationhandler.h b/src/plugin/conversationhandler.h deleted file mode 100644 index 86c36fb79890e48915b3caa86825c63942029436..0000000000000000000000000000000000000000 --- a/src/plugin/conversationhandler.h +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Copyright (C) 2004-2019 Savoir-faire Linux Inc. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - */ -#pragma once -#include "observer.h" -#include <string> -#include <map> - -namespace jami { -struct ConversationMessage -{ - ConversationMessage(const std::string& author, - const std::string& to, - std::map<std::string, std::string>& dataMap) - : author_ {author} - , to_ {to} - , data_ {dataMap} - {} - std::string author_; - std::string to_; - std::map<std::string, std::string> data_; -}; - -using ConvMsgPtr = std::shared_ptr<ConversationMessage>; - -using strMapSubjectPtr = std::shared_ptr<PublishObservable<ConvMsgPtr>>; - -class ConversationHandler -{ -public: - virtual ~ConversationHandler() = default; - virtual void notifyStrMapSubject(const bool direction, strMapSubjectPtr subject) = 0; -}; -} // namespace jami diff --git a/src/plugin/conversationservicesmanager.h b/src/plugin/conversationservicesmanager.h deleted file mode 100644 index a4df61096ff8f12ca368ac29b987a0a700847b5d..0000000000000000000000000000000000000000 --- a/src/plugin/conversationservicesmanager.h +++ /dev/null @@ -1,108 +0,0 @@ -/* - * Copyright (C) 2004-2019 Savoir-faire Linux Inc. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - */ -#pragma once -// Utils -#include "noncopyable.h" -// Plugin Manager -#include "pluginmanager.h" -#include "conversationhandler.h" -#include "logger.h" -// Manager -#include "manager.h" - -namespace jami { - -using ConversationHandlerPtr = std::unique_ptr<ConversationHandler>; - -class ConversationServicesManager -{ -public: - ConversationServicesManager(PluginManager& pm) - { - registerComponentsLifeCycleManagers(pm); - - auto sendTextMessage = [this](const DLPlugin* plugin, void* data) { - auto cm = static_cast<ConversationMessage*>(data); - jami::Manager::instance().sendTextMessage(cm->author_, cm->to_, cm->data_); - return 0; - }; - - pm.registerService("sendTextMessage", sendTextMessage); - } - NON_COPYABLE(ConversationServicesManager); - -public: - void registerComponentsLifeCycleManagers(PluginManager& pm) - { - auto registerConversationHandler = [this](void* data) { - ConversationHandlerPtr ptr {(static_cast<ConversationHandler*>(data))}; - - if (ptr) { - conversationHandlers.push_back(std::make_pair(false, std::move(ptr))); - if (!conversationHandlers.empty()) { - listAvailableSubjects(conversationHandlers.back().second); - } - } - - return 0; - }; - - auto unregisterConversationHandler = [this](void* data) { - for (auto it = conversationHandlers.begin(); it != conversationHandlers.end(); ++it) { - if (it->second.get() == data) { - conversationHandlers.erase(it); - break; - } - } - return 0; - }; - - pm.registerComponentManager("ConversationHandlerManager", - registerConversationHandler, - unregisterConversationHandler); - } - - void onTextMessage(std::shared_ptr<ConversationMessage>& cm) - { - if (!conversationHandlers.empty()) { - receiveSubject->publish(cm); - } - } - - void sendTextMessage(std::shared_ptr<ConversationMessage>& cm) - { - if (!conversationHandlers.empty()) { - sendSubject->publish(cm); - } - } - -private: - void listAvailableSubjects(ConversationHandlerPtr& plugin) - { - plugin->notifyStrMapSubject(false, sendSubject); - plugin->notifyStrMapSubject(true, receiveSubject); - } - -private: - std::list<std::pair<bool, ConversationHandlerPtr>> conversationHandlers; - strMapSubjectPtr sendSubject - = std::make_shared<PublishObservable<std::shared_ptr<ConversationMessage>>>(); - strMapSubjectPtr receiveSubject - = std::make_shared<PublishObservable<std::shared_ptr<ConversationMessage>>>(); -}; -} // namespace jami diff --git a/src/plugin/jamipluginmanager.cpp b/src/plugin/jamipluginmanager.cpp index 2f080318fd11f9fe831a144434b488404f4d20a5..267a2d4bbaa83684bf5a5afbdd315f700825d593 100644 --- a/src/plugin/jamipluginmanager.cpp +++ b/src/plugin/jamipluginmanager.cpp @@ -25,8 +25,7 @@ #include <fstream> #include <regex> #include <stdexcept> - -// Manager +#include <msgpack.hpp> #include "manager.h" #include "preferences.h" @@ -34,9 +33,6 @@ extern "C" { #include <archive.h> } -#include <json/json.h> -#include <msgpack.hpp> - #if defined(__arm__) #if defined(__ARM_ARCH_7A__) #define ABI "armeabi-v7a" @@ -147,46 +143,6 @@ uncompressJplFunction(const std::string& relativeFileName) return std::make_pair(false, std::string {""}); } -std::string -convertArrayToString(const Json::Value& jsonArray) -{ - std::string stringArray = ""; - - if (jsonArray.size()) { - for (unsigned i = 0; i < jsonArray.size() - 1; i++) { - if (jsonArray[i].isString()) { - stringArray += jsonArray[i].asString() + ","; - } else if (jsonArray[i].isArray()) { - stringArray += convertArrayToString(jsonArray[i]) + ","; - } - } - - unsigned lastIndex = jsonArray.size() - 1; - if (jsonArray[lastIndex].isString()) { - stringArray += jsonArray[lastIndex].asString(); - } - } - - return stringArray; -} - -std::map<std::string, std::string> -parsePreferenceConfig(const Json::Value& jsonPreference, const std::string& type) -{ - std::map<std::string, std::string> preferenceMap; - const auto& members = jsonPreference.getMemberNames(); - // Insert other fields - for (const auto& member : members) { - const Json::Value& value = jsonPreference[member]; - if (value.isString()) { - preferenceMap.emplace(member, jsonPreference[member].asString()); - } else if (value.isArray()) { - preferenceMap.emplace(member, convertArrayToString(jsonPreference[member])); - } - } - return preferenceMap; -} - std::map<std::string, std::string> JamiPluginManager::getPluginDetails(const std::string& rootPath) { @@ -206,7 +162,7 @@ JamiPluginManager::getPluginDetails(const std::string& rootPath) } std::vector<std::string> -JamiPluginManager::listAvailablePlugins() +JamiPluginManager::getInstalledPlugins() { std::string pluginsPath = fileutils::get_data_dir() + DIR_SEPARATOR_CH + "plugins"; std::vector<std::string> pluginsPaths = fileutils::readDirectory(pluginsPath); @@ -329,30 +285,10 @@ JamiPluginManager::unloadPlugin(const std::string& rootPath) return false; } -void -JamiPluginManager::togglePlugin(const std::string& rootPath, bool toggle) -{ - // This function should not be used as is - // One should modify it to perform plugin install followed by load - // rootPath should be the jplpath! - try { - std::string soPath = getPluginDetails(rootPath).at("soPath"); - // remove the previous plugin object if it was registered - pm_.destroyPluginComponents(soPath); - // If toggle, register a new instance of the plugin - // function - if (toggle) { - pm_.callPluginInitFunction(soPath); - } - } catch (const std::exception& e) { - JAMI_ERR() << e.what(); - } -} - std::vector<std::string> -JamiPluginManager::listLoadedPlugins() const +JamiPluginManager::getLoadedPlugins() const { - std::vector<std::string> loadedSoPlugins = pm_.listLoadedPlugins(); + std::vector<std::string> loadedSoPlugins = pm_.getLoadedPlugins(); std::vector<std::string> loadedPlugins {}; loadedPlugins.reserve(loadedSoPlugins.size()); std::transform(loadedSoPlugins.begin(), @@ -365,81 +301,13 @@ JamiPluginManager::listLoadedPlugins() const std::vector<std::map<std::string, std::string>> JamiPluginManager::getPluginPreferences(const std::string& rootPath) { - const std::string preferenceFilePath = getPreferencesConfigFilePath(rootPath); - std::ifstream file(preferenceFilePath); - Json::Value root; - Json::CharReaderBuilder rbuilder; - rbuilder["collectComments"] = false; - std::string errs; - std::set<std::string> keys; - std::vector<std::map<std::string, std::string>> preferences; - if (file) { - bool ok = Json::parseFromStream(rbuilder, file, &root, &errs); - if (ok && root.isArray()) { - for (unsigned i = 0; i < root.size(); i++) { - const Json::Value& jsonPreference = root[i]; - std::string category = jsonPreference.get("category", "NoCategory").asString(); - std::string type = jsonPreference.get("type", "None").asString(); - std::string key = jsonPreference.get("key", "None").asString(); - if (type != "None" && key != "None") { - if (keys.find(key) == keys.end()) { - auto preferenceAttributes = parsePreferenceConfig(jsonPreference, type); - // If the parsing of the attributes was successful, commit the map and the keys - auto defaultValue = preferenceAttributes.find("defaultValue"); - if (type == "Path" && defaultValue != preferenceAttributes.end()) { - defaultValue->second = rootPath + DIR_SEPARATOR_STR - + defaultValue->second; - } - - if (!preferenceAttributes.empty()) { - preferences.push_back(std::move(preferenceAttributes)); - keys.insert(key); - } - } - } - } - } else { - JAMI_ERR() << "PluginPreferencesParser:: Failed to parse preferences.json for plugin: " - << preferenceFilePath; - } - } - - return preferences; + return PluginPreferencesUtils::getPreferences(rootPath); } std::map<std::string, std::string> JamiPluginManager::getPluginUserPreferencesValuesMap(const std::string& rootPath) { - const std::string preferencesValuesFilePath = pluginPreferencesValuesFilePath(rootPath); - std::ifstream file(preferencesValuesFilePath, std::ios::binary); - std::map<std::string, std::string> rmap; - - // If file is accessible - if (file.good()) { - std::lock_guard<std::mutex> guard(fileutils::getFileLock(preferencesValuesFilePath)); - // Get file size - std::string str; - file.seekg(0, std::ios::end); - size_t fileSize = static_cast<size_t>(file.tellg()); - // If not empty - if (fileSize > 0) { - // Read whole file content and put it in the string str - str.reserve(static_cast<size_t>(file.tellg())); - file.seekg(0, std::ios::beg); - str.assign((std::istreambuf_iterator<char>(file)), std::istreambuf_iterator<char>()); - file.close(); - try { - // Unpack the string - msgpack::object_handle oh = msgpack::unpack(str.data(), str.size()); - // Deserialized object is valid during the msgpack::object_handle instance is alive. - msgpack::object deserialized = oh.get(); - deserialized.convert(rmap); - } catch (const std::exception& e) { - JAMI_ERR() << e.what(); - } - } - } - return rmap; + return PluginPreferencesUtils::getUserPreferencesValuesMap(rootPath); } bool @@ -447,23 +315,26 @@ JamiPluginManager::setPluginPreference(const std::string& rootPath, const std::string& key, const std::string& value) { - std::map<std::string, std::string> pluginUserPreferencesMap = getPluginUserPreferencesValuesMap( - rootPath); - std::map<std::string, std::string> pluginPreferencesMap = getPluginPreferencesValuesMap( + std::map<std::string, std::string> pluginUserPreferencesMap + = PluginPreferencesUtils::getUserPreferencesValuesMap(rootPath); + std::map<std::string, std::string> pluginPreferencesMap = PluginPreferencesUtils::getPreferencesValuesMap( rootPath); auto find = pluginPreferencesMap.find(key); if (find != pluginPreferencesMap.end()) { - std::vector<std::map<std::string, std::string>> preferences = getPluginPreferences(rootPath); + std::vector<std::map<std::string, std::string>> preferences = PluginPreferencesUtils::getPreferences( + rootPath); for (auto& preference : preferences) { if (!preference["key"].compare(key)) { - csm_.setPreference(key, value, preference["scope"]); + callsm_.setPreference(key, value, preference["scope"]); + chatsm_.setPreference(key, value, preference["scope"]); break; } } pluginUserPreferencesMap[key] = value; - const std::string preferencesValuesFilePath = pluginPreferencesValuesFilePath(rootPath); + const std::string preferencesValuesFilePath = PluginPreferencesUtils::valuesFilePath( + rootPath); std::ofstream fs(preferencesValuesFilePath, std::ios::binary); if (!fs.good()) { return false; @@ -483,39 +354,13 @@ JamiPluginManager::setPluginPreference(const std::string& rootPath, std::map<std::string, std::string> JamiPluginManager::getPluginPreferencesValuesMap(const std::string& rootPath) { - std::map<std::string, std::string> rmap; - - std::vector<std::map<std::string, std::string>> preferences = getPluginPreferences(rootPath); - for (auto& preference : preferences) { - rmap[preference["key"]] = preference["defaultValue"]; - } - - for (const auto& pair : getPluginUserPreferencesValuesMap(rootPath)) { - rmap[pair.first] = pair.second; - } - return rmap; + return PluginPreferencesUtils::getPreferencesValuesMap(rootPath); } bool JamiPluginManager::resetPluginPreferencesValuesMap(const std::string& rootPath) { - bool returnValue = true; - std::map<std::string, std::string> pluginPreferencesMap {}; - - const std::string preferencesValuesFilePath = pluginPreferencesValuesFilePath(rootPath); - std::ofstream fs(preferencesValuesFilePath, std::ios::binary); - if (!fs.good()) { - return false; - } - try { - std::lock_guard<std::mutex> guard(fileutils::getFileLock(preferencesValuesFilePath)); - msgpack::pack(fs, pluginPreferencesMap); - } catch (const std::exception& e) { - returnValue = false; - JAMI_ERR() << e.what(); - } - - return returnValue; + return PluginPreferencesUtils::resetPreferencesValuesMap(rootPath); } std::map<std::string, std::string> diff --git a/src/plugin/jamipluginmanager.h b/src/plugin/jamipluginmanager.h index 3083050ac776327e00c45fd78618508ddfd94cee..8f44beeaf2cb146a9a733d04910b820e829a0619 100644 --- a/src/plugin/jamipluginmanager.h +++ b/src/plugin/jamipluginmanager.h @@ -23,10 +23,11 @@ #include "fileutils.h" #include "archiver.h" #include "pluginmanager.h" +#include "pluginpreferencesutils.h" // Services #include "callservicesmanager.h" -#include "conversationservicesmanager.h" +#include "chatservicesmanager.h" #include <vector> #include <map> @@ -39,8 +40,8 @@ class JamiPluginManager { public: JamiPluginManager() - : csm_ {pm_} - , convsm_ {pm_} + : callsm_ {pm_} + , chatsm_ {pm_} { registerServices(); } @@ -59,11 +60,11 @@ public: std::map<std::string, std::string> getPluginDetails(const std::string& rootPath); /** - * @brief listAvailablePlugins + * @brief getInstalledPlugins * Lists available plugins with valid manifest files * @return list of plugin directory names */ - std::vector<std::string> listAvailablePlugins(); + std::vector<std::string> getInstalledPlugins(); /** * @brief installPlugin @@ -102,19 +103,10 @@ public: bool unloadPlugin(const std::string& rootPath); /** - * @brief togglePlugin - * @param rootPath of the plugin folder - * @param toggle: if true, register a new instance of the plugin - * else, remove the existing instance - * N.B: before adding a new instance, remove any existing one - */ - void togglePlugin(const std::string& rootPath, bool toggle); - - /** - * @brief listLoadedPlugins + * @brief getLoadedPlugins * @return vector of rootpaths of the loaded plugins */ - std::vector<std::string> listLoadedPlugins() const; + std::vector<std::string> getLoadedPlugins() const; std::vector<std::map<std::string, std::string>> getPluginPreferences(const std::string& rootPath); @@ -126,10 +118,9 @@ public: bool resetPluginPreferencesValuesMap(const std::string& rootPath); -public: - CallServicesManager& getCallServicesManager() { return csm_; } + CallServicesManager& getCallServicesManager() { return callsm_; } - ConversationServicesManager& getConversationServicesManager() { return convsm_; } + ChatServicesManager& getChatServicesManager() { return chatsm_; } private: NON_COPYABLE(JamiPluginManager); @@ -191,7 +182,7 @@ private: */ std::string getPreferencesConfigFilePath(const std::string& rootPath) const { - return rootPath + DIR_SEPARATOR_CH + "data" + DIR_SEPARATOR_CH + "preferences.json"; + return PluginPreferencesUtils::getPreferencesConfigFilePath(rootPath); } /** @@ -203,18 +194,16 @@ private: */ std::string pluginPreferencesValuesFilePath(const std::string& rootPath) const { - return rootPath + DIR_SEPARATOR_CH + "preferences.msgpack"; + return PluginPreferencesUtils::valuesFilePath(rootPath); } void registerServices(); -private: PluginManager pm_; std::map<std::string, std::map<std::string, std::string>> pluginDetailsMap_; // Services -private: - CallServicesManager csm_; - ConversationServicesManager convsm_; + CallServicesManager callsm_; + ChatServicesManager chatsm_; }; } // namespace jami diff --git a/src/plugin/mediahandler.h b/src/plugin/mediahandler.h index 7a25457da3f8e03981ecf6663b05b702a5b0b6b2..81cb2c3685b2b5c60d1f8b2239687cde6034a67e 100644 --- a/src/plugin/mediahandler.h +++ b/src/plugin/mediahandler.h @@ -1,5 +1,7 @@ /* - * Copyright (C) 2004-2019 Savoir-faire Linux Inc. + * Copyright (C) 2020 Savoir-faire Linux Inc. + * + * Author: Aline Gondim Santos <aline.gondimsantos@savoirfairelinux.com> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -15,7 +17,9 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ + #pragma once + #include "streamdata.h" #include "observer.h" #include <libavutil/frame.h> diff --git a/src/plugin/pluginmanager.cpp b/src/plugin/pluginmanager.cpp index e63ad5c132a49bb6942e7c4e7273aafcfda932b3..56a740665a6e35cd7595ec37903e6a17f966466d 100644 --- a/src/plugin/pluginmanager.cpp +++ b/src/plugin/pluginmanager.cpp @@ -79,7 +79,7 @@ PluginManager::load(const std::string& path) bool PluginManager::unload(const std::string& path) { - bool returnValue {false}; + bool returnValue{false}; destroyPluginComponents(path); PluginMap::iterator it = dynPluginMap_.find(path); if (it != dynPluginMap_.end()) { @@ -97,7 +97,7 @@ PluginManager::checkLoadedPlugin(const std::string& rootPath) const } std::vector<std::string> -PluginManager::listLoadedPlugins() const +PluginManager::getLoadedPlugins() const { std::vector<std::string> res {}; for (const auto& pair : dynPluginMap_) { @@ -375,5 +375,4 @@ PluginManager::registerObjectFactory_(const JAMI_PluginAPI* api, const char* typ const auto factory = reinterpret_cast<JAMI_PluginObjectFactory*>(data); return manager->registerObjectFactory(type, *factory) ? 0 : -1; } - } // namespace jami diff --git a/src/plugin/pluginmanager.h b/src/plugin/pluginmanager.h index f2bcb408f2385d24abdcbb9f221bb7ea949cdcd9..582bc6c994b6126d252c9402ba380046028ea16b 100644 --- a/src/plugin/pluginmanager.h +++ b/src/plugin/pluginmanager.h @@ -85,10 +85,10 @@ public: bool unload(const std::string& path); /** - * @brief listLoadedPlugins + * @brief getLoadedPlugins * @return vector of strings of so files of the loaded plugins */ - std::vector<std::string> listLoadedPlugins() const; + std::vector<std::string> getLoadedPlugins() const; /** * @brief checkLoadedPlugin @@ -195,5 +195,4 @@ private: // references to plugins components, used for cleanup PluginComponentsMap pluginComponentsMap_ {}; }; - } // namespace jami diff --git a/src/plugin/pluginpreferencesutils.cpp b/src/plugin/pluginpreferencesutils.cpp new file mode 100644 index 0000000000000000000000000000000000000000..2b48131914ae65694a66d7e5da697fafe560edc3 --- /dev/null +++ b/src/plugin/pluginpreferencesutils.cpp @@ -0,0 +1,205 @@ +/* + * Copyright (C) 2020 Savoir-faire Linux Inc. + * + * Author: Aline Gondim Santos <aline.gondimsantos@savoirfairelinux.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 + * USA. + */ + +#include "pluginpreferencesutils.h" + +#include <msgpack.hpp> +#include <sstream> +#include <fstream> +#include "logger.h" +#include "fileutils.h" + +namespace jami { + +std::string +PluginPreferencesUtils::getPreferencesConfigFilePath(const std::string& rootPath) +{ + return rootPath + DIR_SEPARATOR_CH + "data" + DIR_SEPARATOR_CH + "preferences.json"; +} + +std::string +PluginPreferencesUtils::valuesFilePath(const std::string& rootPath) +{ + return rootPath + DIR_SEPARATOR_CH + "preferences.msgpack"; +} + +std::string +PluginPreferencesUtils::convertArrayToString(const Json::Value& jsonArray) +{ + std::string stringArray{}; + + if (jsonArray.size()) { + for (unsigned i = 0; i < jsonArray.size() - 1; i++) { + if (jsonArray[i].isString()) { + stringArray += jsonArray[i].asString() + ","; + } else if (jsonArray[i].isArray()) { + stringArray += convertArrayToString(jsonArray[i]) + ","; + } + } + + unsigned lastIndex = jsonArray.size() - 1; + if (jsonArray[lastIndex].isString()) { + stringArray += jsonArray[lastIndex].asString(); + } + } + + return stringArray; +} + +std::map<std::string, std::string> +PluginPreferencesUtils::parsePreferenceConfig(const Json::Value& jsonPreference, const std::string& type) +{ + std::map<std::string, std::string> preferenceMap; + const auto& members = jsonPreference.getMemberNames(); + // Insert other fields + for (const auto& member : members) { + const Json::Value& value = jsonPreference[member]; + if (value.isString()) { + preferenceMap.emplace(member, jsonPreference[member].asString()); + } else if (value.isArray()) { + preferenceMap.emplace(member, convertArrayToString(jsonPreference[member])); + } + } + return preferenceMap; +} + +std::vector<std::map<std::string, std::string>> +PluginPreferencesUtils::getPreferences(const std::string& rootPath) +{ + const std::string preferenceFilePath = getPreferencesConfigFilePath(rootPath); + std::ifstream file(preferenceFilePath); + Json::Value root; + Json::CharReaderBuilder rbuilder; + rbuilder["collectComments"] = false; + std::string errs; + std::set<std::string> keys; + std::vector<std::map<std::string, std::string>> preferences; + if (file) { + bool ok = Json::parseFromStream(rbuilder, file, &root, &errs); + if (ok && root.isArray()) { + for (unsigned i = 0; i < root.size(); i++) { + const Json::Value& jsonPreference = root[i]; + std::string category = jsonPreference.get("category", "NoCategory").asString(); + std::string type = jsonPreference.get("type", "None").asString(); + std::string key = jsonPreference.get("key", "None").asString(); + if (type != "None" && key != "None") { + if (keys.find(key) == keys.end()) { + auto preferenceAttributes = parsePreferenceConfig(jsonPreference, type); + // If the parsing of the attributes was successful, commit the map and the keys + auto defaultValue = preferenceAttributes.find("defaultValue"); + if (type == "Path" && defaultValue != preferenceAttributes.end()) { + defaultValue->second = rootPath + DIR_SEPARATOR_STR + + defaultValue->second; + } + + if (!preferenceAttributes.empty()) { + preferences.push_back(std::move(preferenceAttributes)); + keys.insert(key); + } + } + } + } + } else { + JAMI_ERR() << "PluginPreferencesParser:: Failed to parse preferences.json for plugin: " + << preferenceFilePath; + } + } + + return preferences; +} + +std::map<std::string, std::string> +PluginPreferencesUtils::getUserPreferencesValuesMap(const std::string& rootPath) +{ + const std::string preferencesValuesFilePath = valuesFilePath(rootPath); + std::ifstream file(preferencesValuesFilePath, std::ios::binary); + std::map<std::string, std::string> rmap; + + // If file is accessible + if (file.good()) { + std::lock_guard<std::mutex> guard(fileutils::getFileLock(preferencesValuesFilePath)); + // Get file size + std::string str; + file.seekg(0, std::ios::end); + size_t fileSize = static_cast<size_t>(file.tellg()); + // If not empty + if (fileSize > 0) { + // Read whole file content and put it in the string str + str.reserve(static_cast<size_t>(file.tellg())); + file.seekg(0, std::ios::beg); + str.assign((std::istreambuf_iterator<char>(file)), std::istreambuf_iterator<char>()); + file.close(); + try { + // Unpack the string + msgpack::object_handle oh = msgpack::unpack(str.data(), str.size()); + // Deserialized object is valid during the msgpack::object_handle instance is alive. + msgpack::object deserialized = oh.get(); + deserialized.convert(rmap); + } catch (const std::exception& e) { + JAMI_ERR() << e.what(); + } + } + } + return rmap; +} + +std::map<std::string, std::string> +PluginPreferencesUtils::getPreferencesValuesMap(const std::string& rootPath) +{ + std::map<std::string, std::string> rmap; + + std::vector<std::map<std::string, std::string>> preferences = getPreferences( + rootPath); + for (auto& preference : preferences) { + rmap[preference["key"]] = preference["defaultValue"]; + } + + for (const auto& pair : getUserPreferencesValuesMap(rootPath)) { + rmap[pair.first] = pair.second; + } + + rmap.emplace("always", "0"); + + return rmap; +} + +bool +PluginPreferencesUtils::resetPreferencesValuesMap(const std::string& rootPath) +{ + bool returnValue = true; + std::map<std::string, std::string> pluginPreferencesMap {}; + + const std::string preferencesValuesFilePath = valuesFilePath(rootPath); + std::ofstream fs(preferencesValuesFilePath, std::ios::binary); + if (!fs.good()) { + return false; + } + try { + std::lock_guard<std::mutex> guard(fileutils::getFileLock(preferencesValuesFilePath)); + msgpack::pack(fs, pluginPreferencesMap); + } catch (const std::exception& e) { + returnValue = false; + JAMI_ERR() << e.what(); + } + + return returnValue; +} +} // namespace jami diff --git a/src/plugin/pluginpreferencesutils.h b/src/plugin/pluginpreferencesutils.h new file mode 100644 index 0000000000000000000000000000000000000000..9a7ce1a98b65d90f657d048ce495756af2f796c3 --- /dev/null +++ b/src/plugin/pluginpreferencesutils.h @@ -0,0 +1,53 @@ +/* + * Copyright (C) 2020 Savoir-faire Linux Inc. + * + * Author: Aline Gondim Santos <aline.gondimsantos@savoirfairelinux.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 + * USA. + */ + +#pragma once + +#include <json/json.h> +#include <string> + +namespace jami { + +class PluginPreferencesUtils { +public: + static std::string getPreferencesConfigFilePath(const std::string& rootPath); + + static std::string valuesFilePath(const std::string& rootPath); + + static std::string convertArrayToString(const Json::Value& jsonArray); + + static std::map<std::string, std::string> parsePreferenceConfig(const Json::Value& jsonPreference, + const std::string& type); + + static std::vector<std::map<std::string, std::string>> getPreferences( + const std::string& rootPath); + + static std::map<std::string, std::string> getUserPreferencesValuesMap( + const std::string& rootPath); + + static std::map<std::string, std::string> getPreferencesValuesMap(const std::string& rootPath); + + static bool resetPreferencesValuesMap(const std::string& rootPath); +private: + PluginPreferencesUtils() {} + ~PluginPreferencesUtils() {} +}; +} // namespace jami diff --git a/src/plugin/streamdata.h b/src/plugin/streamdata.h index 522a67b3ee23d83294becf71a0da062022761ab8..9746bf428c355f496ead9747cfaa486088c579c4 100644 --- a/src/plugin/streamdata.h +++ b/src/plugin/streamdata.h @@ -1,5 +1,7 @@ /* - * Copyright (C) 2004-2019 Savoir-faire Linux Inc. + * Copyright (C) 2020 Savoir-faire Linux Inc. + * + * Author: Aline Gondim Santos <aline.gondimsantos@savoirfairelinux.com> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -17,10 +19,11 @@ */ #pragma once #include <string> +#include <map> enum class StreamType { audio, video }; -struct StreamData +struct StreamData // for calls { StreamData(const std::string& i, bool d, StreamType&& t, const std::string& s) : id {std::move(i)} @@ -33,3 +36,24 @@ struct StreamData const StreamType type; const std::string source; }; + +struct JamiMessage // for chat +{ + JamiMessage(const std::string& accId, + const std::string& pId, + bool direction, + std::map<std::string, std::string>& dataMap, + bool pPlugin) + : accountId {accId} + , peerId {pId} + , direction {direction} + , data {dataMap} + , fromPlugin {pPlugin} + {} + + std::string accountId; // accountID + std::string peerId; // peer + const bool direction; // 0 -> send; 1 -> received + std::map<std::string, std::string> data; + bool fromPlugin; +}; \ No newline at end of file diff --git a/src/sip/sipaccountbase.cpp b/src/sip/sipaccountbase.cpp index 9f6983d2e3b7b115b4b672b06e7429d25858a4ae..3749b37fdb9616f726b486c5ab5ef82a0bee3af7 100644 --- a/src/sip/sipaccountbase.cpp +++ b/src/sip/sipaccountbase.cpp @@ -51,6 +51,7 @@ #include "manager.h" #ifdef ENABLE_PLUGIN #include "plugin/jamipluginmanager.h" +#include "plugin/streamdata.h" #endif namespace jami { @@ -562,16 +563,16 @@ SIPAccountBase::onTextMessage(const std::string& id, } #ifdef ENABLE_PLUGIN - auto& convManager - = jami::Manager::instance().getJamiPluginManager().getConversationServicesManager(); - std::shared_ptr<ConversationMessage> cm = std::make_shared<ConversationMessage>( - from, accountID_, const_cast<std::map<std::string, std::string>&>(payloads)); - convManager.onTextMessage(cm); - emitSignal<DRing::ConfigurationSignal::IncomingAccountMessage>(accountID_, id, from, cm->data_); + auto& pluginChatManager + = jami::Manager::instance().getJamiPluginManager().getChatServicesManager(); + std::shared_ptr<JamiMessage> cm = std::make_shared<JamiMessage>( + accountID_, from, true, const_cast<std::map<std::string, std::string>&>(payloads), false); + pluginChatManager.publishMessage(cm); + emitSignal<DRing::ConfigurationSignal::IncomingAccountMessage>(accountID_, id, from, cm->data); DRing::Message message; - message.from = cm->author_; - message.payloads = cm->data_; + message.from = from; + message.payloads = cm->data; #else emitSignal<DRing::ConfigurationSignal::IncomingAccountMessage>(accountID_, id, from, payloads); diff --git a/src/sip/sipcall.cpp b/src/sip/sipcall.cpp index 3cb910f42c7436dfc9f24d42968585044e4111e2..7ff93c7bcf8ac16fff54d778b582a86ef7932df3 100644 --- a/src/sip/sipcall.cpp +++ b/src/sip/sipcall.cpp @@ -140,14 +140,14 @@ SIPCall::createCallAVStreams() // Preview if (auto& localAudio = avformatrtp_->getAudioLocal()) { auto previewSubject = std::make_shared<MediaStreamSubject>(audioMap); - StreamData microStreamData {getCallId(), 0, StreamType::audio, getPeerNumber()}; + StreamData microStreamData {getCallId(), false, StreamType::audio, getPeerNumber()}; createCallAVStream(microStreamData, *localAudio, previewSubject); } // Receive if (auto& audioReceive = avformatrtp_->getAudioReceive()) { auto receiveSubject = std::make_shared<MediaStreamSubject>(audioMap); - StreamData phoneStreamData {getCallId(), 1, StreamType::audio, getPeerNumber()}; + StreamData phoneStreamData {getCallId(), true, StreamType::audio, getPeerNumber()}; createCallAVStream(phoneStreamData, (AVMediaStream&) *audioReceive, receiveSubject); } #ifdef ENABLE_VIDEO @@ -162,14 +162,14 @@ SIPCall::createCallAVStreams() // Preview if (auto& videoPreview = videortp_->getVideoLocal()) { auto previewSubject = std::make_shared<MediaStreamSubject>(videoMap); - StreamData previewStreamData {getCallId(), 0, StreamType::video, getPeerNumber()}; + StreamData previewStreamData {getCallId(), false, StreamType::video, getPeerNumber()}; createCallAVStream(previewStreamData, *videoPreview, previewSubject); } // Receive if (auto& videoReceive = videortp_->getVideoReceive()) { auto receiveSubject = std::make_shared<MediaStreamSubject>(videoMap); - StreamData receiveStreamData {getCallId(), 1, StreamType::video, getPeerNumber()}; + StreamData receiveStreamData {getCallId(), true, StreamType::video, getPeerNumber()}; createCallAVStream(receiveStreamData, *videoReceive, receiveSubject); } }