diff --git a/bin/dbus/dbuscallmanager.hpp b/bin/dbus/dbuscallmanager.hpp index fcddfb5ee..897b17a91 100644 --- a/bin/dbus/dbuscallmanager.hpp +++ b/bin/dbus/dbuscallmanager.hpp @@ -463,56 +463,56 @@ private: { using namespace std::placeholders; - using libjami::exportable_callback; + using libjami::exportable_serialized_callback; using libjami::CallSignal; using SharedCallback = std::shared_ptr; const std::map callEvHandlers - = {exportable_callback( + = {exportable_serialized_callback( std::bind(&DBusCallManager::emitCallStateChanged, this, _1, _2, _3, _4)), - exportable_callback( + exportable_serialized_callback( std::bind(&DBusCallManager::emitTransferFailed, this)), - exportable_callback( + exportable_serialized_callback( std::bind(&DBusCallManager::emitTransferSucceeded, this)), - exportable_callback( + exportable_serialized_callback( std::bind(&DBusCallManager::emitRecordPlaybackStopped, this, _1)), - exportable_callback( + exportable_serialized_callback( std::bind(&DBusCallManager::emitVoiceMailNotify, this, _1, _2, _3, _4)), - exportable_callback( + exportable_serialized_callback( std::bind(&DBusCallManager::emitIncomingMessage, this, _1, _2, _3, _4)), - exportable_callback( + exportable_serialized_callback( std::bind(&DBusCallManager::emitIncomingCall, this, _1, _2, _3)), - exportable_callback( + exportable_serialized_callback( std::bind(&DBusCallManager::emitIncomingCallWithMedia, this, _1, _2, _3, _4)), - exportable_callback( + exportable_serialized_callback( std::bind(&DBusCallManager::emitMediaChangeRequested, this, _1, _2, _3)), - exportable_callback( + exportable_serialized_callback( std::bind(&DBusCallManager::emitRecordPlaybackFilepath, this, _1, _2)), - exportable_callback( + exportable_serialized_callback( std::bind(&DBusCallManager::emitConferenceCreated, this, _1, _2)), - exportable_callback( + exportable_serialized_callback( std::bind(&DBusCallManager::emitConferenceChanged, this, _1, _2, _3)), - exportable_callback( + exportable_serialized_callback( std::bind(&DBusCallManager::emitUpdatePlaybackScale, this, _1, _2, _3)), - exportable_callback( + exportable_serialized_callback( std::bind(&DBusCallManager::emitConferenceRemoved, this, _1, _2)), - exportable_callback( + exportable_serialized_callback( std::bind(&DBusCallManager::emitRecordingStateChanged, this, _1, _2)), - exportable_callback( + exportable_serialized_callback( std::bind(&DBusCallManager::emitOnRtcpReportReceived, this, _1, _2)), - exportable_callback( + exportable_serialized_callback( std::bind(&DBusCallManager::emitOnConferenceInfosUpdated, this, _1, _2)), - exportable_callback( + exportable_serialized_callback( std::bind(&DBusCallManager::emitPeerHold, this, _1, _2)), - exportable_callback( + exportable_serialized_callback( std::bind(&DBusCallManager::emitAudioMuted, this, _1, _2)), - exportable_callback( + exportable_serialized_callback( std::bind(&DBusCallManager::emitVideoMuted, this, _1, _2)), - exportable_callback( + exportable_serialized_callback( std::bind(&DBusCallManager::emitSmartInfo, this, _1)), - exportable_callback( + exportable_serialized_callback( std::bind(&DBusCallManager::emitRemoteRecordingChanged, this, _1, _2, _3)), - exportable_callback( + exportable_serialized_callback( std::bind(&DBusCallManager::emitMediaNegotiationStatus, this, _1, _2, _3)) }; diff --git a/bin/dbus/dbusconfigurationmanager.hpp b/bin/dbus/dbusconfigurationmanager.hpp index a33e79844..48157d4b3 100644 --- a/bin/dbus/dbusconfigurationmanager.hpp +++ b/bin/dbus/dbusconfigurationmanager.hpp @@ -1019,7 +1019,7 @@ private: { using namespace std::placeholders; - using libjami::exportable_callback; + using libjami::exportable_serialized_callback; using libjami::ConfigurationSignal; using libjami::AudioSignal; using libjami::DataTransferSignal; @@ -1028,105 +1028,105 @@ private: // Configuration event handlers const std::map configEvHandlers = { - exportable_callback( + exportable_serialized_callback( std::bind(&DBusConfigurationManager::emitVolumeChanged, this, _1, _2)), - exportable_callback( + exportable_serialized_callback( std::bind(&DBusConfigurationManager::emitAccountsChanged, this)), - exportable_callback( + exportable_serialized_callback( std::bind(&DBusConfigurationManager::emitAccountDetailsChanged, this, _1, _2)), - exportable_callback( + exportable_serialized_callback( std::bind(&DBusConfigurationManager::emitStunStatusFailure, this, _1)), - exportable_callback( + exportable_serialized_callback( std::bind(&DBusConfigurationManager::emitRegistrationStateChanged, this, _1, _2, _3, _4)), - exportable_callback( + exportable_serialized_callback( std::bind(&DBusConfigurationManager::emitVolatileAccountDetailsChanged, this, _1, _2)), - exportable_callback( + exportable_serialized_callback( std::bind(&DBusConfigurationManager::emitErrorAlert, this, _1)), - exportable_callback( + exportable_serialized_callback( std::bind(&DBusConfigurationManager::emitIncomingAccountMessage, this, _1, _2, _3, _4)), - exportable_callback( + exportable_serialized_callback( std::bind(&DBusConfigurationManager::emitAccountMessageStatusChanged, this, _1, _2, _3, _4, _5)), - exportable_callback( + exportable_serialized_callback( std::bind(&DBusConfigurationManager::emitProfileReceived, this, _1, _2, _3)), - exportable_callback( + exportable_serialized_callback( std::bind(&DBusConfigurationManager::emitActiveCallsChanged, this, _1, _2, _3)), - exportable_callback( + exportable_serialized_callback( std::bind(&DBusConfigurationManager::emitComposingStatusChanged, this, _1, _2, _3, _4)), - exportable_callback( + exportable_serialized_callback( std::bind(&DBusConfigurationManager::emitIncomingTrustRequest, this, _1, _2, _3, _4, _5)), - exportable_callback( + exportable_serialized_callback( std::bind(&DBusConfigurationManager::emitContactAdded, this, _1, _2, _3)), - exportable_callback( + exportable_serialized_callback( std::bind(&DBusConfigurationManager::emitContactRemoved, this, _1, _2, _3)), - exportable_callback( + exportable_serialized_callback( std::bind(&DBusConfigurationManager::emitExportOnRingEnded, this, _1, _2, _3)), - exportable_callback( + exportable_serialized_callback( std::bind(&DBusConfigurationManager::emitKnownDevicesChanged, this, _1, _2)), - exportable_callback( + exportable_serialized_callback( std::bind(&DBusConfigurationManager::emitNameRegistrationEnded, this, _1, _2, _3)), - exportable_callback( + exportable_serialized_callback( std::bind(&DBusConfigurationManager::emitUserSearchEnded, this, _1, _2, _3, _4)), - exportable_callback( + exportable_serialized_callback( std::bind(&DBusConfigurationManager::emitRegisteredNameFound, this, _1, _2, _3, _4)), - exportable_callback( + exportable_serialized_callback( std::bind(&DBusConfigurationManager::emitDeviceRevocationEnded, this, _1, _2, _3)), - exportable_callback( + exportable_serialized_callback( std::bind(&DBusConfigurationManager::emitAccountProfileReceived, this, _1, _2, _3)), - exportable_callback( + exportable_serialized_callback( std::bind(&DBusConfigurationManager::emitCertificatePinned, this, _1)), - exportable_callback( + exportable_serialized_callback( std::bind(&DBusConfigurationManager::emitCertificatePathPinned, this, _1, _2)), - exportable_callback( + exportable_serialized_callback( std::bind(&DBusConfigurationManager::emitCertificateExpired, this, _1)), - exportable_callback( + exportable_serialized_callback( std::bind(&DBusConfigurationManager::emitCertificateStateChanged, this, _1, _2, _3)), - exportable_callback( + exportable_serialized_callback( std::bind(&DBusConfigurationManager::emitMediaParametersChanged, this, _1)), - exportable_callback( + exportable_serialized_callback( std::bind(&DBusConfigurationManager::emitMigrationEnded, this, _1, _2)), - exportable_callback( + exportable_serialized_callback( std::bind(&DBusConfigurationManager::emitHardwareDecodingChanged, this, _1)), - exportable_callback( + exportable_serialized_callback( std::bind(&DBusConfigurationManager::emitHardwareEncodingChanged, this, _1)), - exportable_callback( + exportable_serialized_callback( std::bind(&DBusConfigurationManager::emitMessageSend, this, _1)), }; // Audio event handlers const std::map audioEvHandlers = { - exportable_callback( + exportable_serialized_callback( std::bind(&DBusConfigurationManager::emitAudioDeviceEvent, this)), - exportable_callback( + exportable_serialized_callback( std::bind(&DBusConfigurationManager::emitAudioMeter, this, _1, _2)), }; const std::map dataXferEvHandlers = { - exportable_callback( + exportable_serialized_callback( std::bind(&DBusConfigurationManager::emitDataTransferEvent, this, _1, _2, _3, _4, _5)), }; const std::map convEvHandlers = { - exportable_callback( + exportable_serialized_callback( std::bind(&DBusConfigurationManager::emitConversationLoaded, this, _1, _2, _3, _4)), - exportable_callback( + exportable_serialized_callback( std::bind(&DBusConfigurationManager::emitMessagesFound, this, _1, _2, _3, _4)), - exportable_callback( + exportable_serialized_callback( std::bind(&DBusConfigurationManager::emitMessageReceived, this, _1, _2, _3)), - exportable_callback( + exportable_serialized_callback( std::bind(&DBusConfigurationManager::emitConversationProfileUpdated, this, _1, _2, _3)), - exportable_callback( + exportable_serialized_callback( std::bind(&DBusConfigurationManager::emitConversationRequestReceived, this, _1, _2, _3)), - exportable_callback( + exportable_serialized_callback( std::bind(&DBusConfigurationManager::emitConversationRequestDeclined, this, _1, _2)), - exportable_callback( + exportable_serialized_callback( std::bind(&DBusConfigurationManager::emitConversationReady, this, _1, _2)), - exportable_callback( + exportable_serialized_callback( std::bind(&DBusConfigurationManager::emitConversationRemoved, this, _1, _2)), - exportable_callback( + exportable_serialized_callback( std::bind(&DBusConfigurationManager::emitConversationMemberEvent, this, _1, _2, _3, _4)), - exportable_callback( + exportable_serialized_callback( std::bind(&DBusConfigurationManager::emitOnConversationError, this, _1, _2, _3, _4)), - exportable_callback( + exportable_serialized_callback( std::bind(&DBusConfigurationManager::emitConversationPreferencesUpdated, this, _1, _2, _3)), }; diff --git a/bin/dbus/dbuspluginmanagerinterface.hpp b/bin/dbus/dbuspluginmanagerinterface.hpp index 8fed62b17..370438221 100644 --- a/bin/dbus/dbuspluginmanagerinterface.hpp +++ b/bin/dbus/dbuspluginmanagerinterface.hpp @@ -208,11 +208,11 @@ private: { using namespace std::placeholders; - using libjami::exportable_callback; + using libjami::exportable_serialized_callback; using SharedCallback = std::shared_ptr; const std::map pluginEvHandlers = { - exportable_callback( + exportable_serialized_callback( std::bind(&DBusPluginManagerInterface::emitWebViewMessageReceived, this, _1, _2, _3, _4)), }; diff --git a/bin/dbus/dbuspresencemanager.hpp b/bin/dbus/dbuspresencemanager.hpp index 53427fcf6..3e4339144 100644 --- a/bin/dbus/dbuspresencemanager.hpp +++ b/bin/dbus/dbuspresencemanager.hpp @@ -76,20 +76,20 @@ private: { using namespace std::placeholders; - using libjami::exportable_callback; + using libjami::exportable_serialized_callback; using libjami::PresenceSignal; using SharedCallback = std::shared_ptr; const std::map presEvHandlers = { - exportable_callback( + exportable_serialized_callback( std::bind(&DBusPresenceManager::emitNewServerSubscriptionRequest, this, _1)), - exportable_callback( + exportable_serialized_callback( std::bind(&DBusPresenceManager::emitServerError, this, _1, _2, _3)), - exportable_callback( + exportable_serialized_callback( std::bind(&DBusPresenceManager::emitNewBuddyNotification, this, _1, _2, _3, _4)), - exportable_callback( + exportable_serialized_callback( std::bind(&DBusPresenceManager::emitNearbyPeerNotification, this, _1, _2, _3, _4)), - exportable_callback( + exportable_serialized_callback( std::bind(&DBusPresenceManager::emitSubscriptionStateChanged, this, _1, _2, _3)), }; diff --git a/bin/dbus/dbusvideomanager.hpp b/bin/dbus/dbusvideomanager.hpp index f420bfcd6..ab3cd647a 100644 --- a/bin/dbus/dbusvideomanager.hpp +++ b/bin/dbus/dbusvideomanager.hpp @@ -158,16 +158,16 @@ private: { using namespace std::placeholders; - using libjami::exportable_callback; + using libjami::exportable_serialized_callback; using libjami::VideoSignal; using SharedCallback = std::shared_ptr; const std::map videoEvHandlers = { - exportable_callback( + exportable_serialized_callback( std::bind(&DBusVideoManager::emitDeviceEvent, this)), - exportable_callback( + exportable_serialized_callback( std::bind(&DBusVideoManager::emitDecodingStarted, this, _1, _2, _3, _4, _5)), - exportable_callback( + exportable_serialized_callback( std::bind(&DBusVideoManager::emitDecodingStopped, this, _1, _2, _3)), }; diff --git a/src/jami/jami.h b/src/jami/jami.h index 6c88ae1d4..08bcfc2ad 100644 --- a/src/jami/jami.h +++ b/src/jami/jami.h @@ -106,7 +106,13 @@ LIBJAMI_PUBLIC void logging(const std::string& whom, const std::string& action) * See CallbackWrapper template for details. */ class LIBJAMI_PUBLIC CallbackWrapperBase -{}; +{ +protected: + // Because post() needs Manager, it should be defined in a .cpp + // so not in a templated class. + // Also we do not want this method to be public in the API. + void post(std::function cb); +}; /* Concrete class of CallbackWrapperBase. * This class wraps callbacks of a specific signature. @@ -160,6 +166,74 @@ public: constexpr explicit operator bool() const noexcept { return static_cast(cb_); } }; +/* Concrete class of CallbackWrapperBase. + * This class wraps callbacks of a specific signature. + * Used to retrigger callbacks on a io context to avoid lock if signals cannot + * be emitted while a method is called. + * Also used to obtain the user callback from a CallbackWrapperBase shared ptr. + * + * This class is CopyConstructible, CopyAssignable, MoveConstructible + * and MoveAssignable. + */ +template +class SerializedCallbackWrapper : public CallbackWrapperBase +{ +private: + using TFunc = std::function; + TFunc cb_; // The user-callback + + // This is quite a ugly method used to transmit templated TFunc with their arguments in the + // ioContext of the manager to avoid locks for signals. + template + auto ioContextWrapper(TCallback&& fun) + { + return [this, fun{std::move(fun)}](auto&&... args) -> decltype(fun(std::forward(args)...)) + { + post([fun{std::move(fun)}, forwardArgs=std::make_tuple(std::move(args)...)]() mutable { + std::apply(std::move(fun), std::move(forwardArgs)); + }); + }; + } + +public: + const char* file_; + uint32_t linum_; + + // Empty wrapper: no callback associated. + // Used to initialize internal callback arrays. + SerializedCallbackWrapper() noexcept {} + + // Create and initialize a wrapper to given callback. + SerializedCallbackWrapper(TFunc&& func, const char* filename, uint32_t linum) noexcept + : file_(filename) + , linum_(linum) + { + cb_ = ioContextWrapper(func); + } + + // Create and initialize a wrapper from a generic CallbackWrapperBase + // shared pointer. + // Note: the given callback is copied into internal storage. + SerializedCallbackWrapper(const std::shared_ptr& p) noexcept + { + if (p) { + auto other = (CallbackWrapper*) p.get(); + + cb_ = ioContextWrapper(other.cb_); + file_ = other->file_; + linum_ = other->linum_; + } + } + + // Return user-callback reference. + // The returned std::function can be null-initialized if no callback + // has been set. + constexpr const TFunc& operator*() const noexcept { return cb_; } + + // Return boolean true value if a non-null callback has been set + constexpr explicit operator bool() const noexcept { return static_cast(cb_); } +}; + /** * Return an exportable callback object. * This object is a std::pair of a string and a CallbackWrapperBase shared_ptr. @@ -177,6 +251,17 @@ exportable_callback(std::function&& func, std::forward>(func), file, linum)); } +template +std::pair> +exportable_serialized_callback(std::function&& func, + const char* file = CURRENT_FILENAME(), + uint32_t linum = CURRENT_LINE()) +{ + return std::make_pair((const std::string&) Ts::name, + std::make_shared>( + std::forward>(func), file, linum)); +} + LIBJAMI_PUBLIC void registerSignalHandlers( const std::map>&); LIBJAMI_PUBLIC void unregisterSignalHandlers(); diff --git a/src/ring_api.cpp b/src/ring_api.cpp index 74a94da5f..4f9dcddec 100644 --- a/src/ring_api.cpp +++ b/src/ring_api.cpp @@ -18,6 +18,7 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ +#include #include #include #include @@ -121,4 +122,10 @@ logging(const std::string& whom, const std::string& action) noexcept } } +void +CallbackWrapperBase::post(std::function cb) +{ + jami::Manager::instance().ioContext()->post(std::move(cb)); +} + } // namespace libjami