diff --git a/bin/dbus/dbuscallmanager.hpp b/bin/dbus/dbuscallmanager.hpp
index fcddfb5ee3466bb4164fdca7833e928f56488830..897b17a9101ba17d3913bdfada17f1baa35aaa96 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<libjami::CallbackWrapperBase>;
 
         const std::map<std::string, SharedCallback> callEvHandlers
-            = {exportable_callback<CallSignal::StateChange>(
+            = {exportable_serialized_callback<CallSignal::StateChange>(
                     std::bind(&DBusCallManager::emitCallStateChanged, this, _1, _2, _3, _4)),
-                exportable_callback<CallSignal::TransferFailed>(
+                exportable_serialized_callback<CallSignal::TransferFailed>(
                     std::bind(&DBusCallManager::emitTransferFailed, this)),
-                exportable_callback<CallSignal::TransferSucceeded>(
+                exportable_serialized_callback<CallSignal::TransferSucceeded>(
                     std::bind(&DBusCallManager::emitTransferSucceeded, this)),
-                exportable_callback<CallSignal::RecordPlaybackStopped>(
+                exportable_serialized_callback<CallSignal::RecordPlaybackStopped>(
                     std::bind(&DBusCallManager::emitRecordPlaybackStopped, this, _1)),
-                exportable_callback<CallSignal::VoiceMailNotify>(
+                exportable_serialized_callback<CallSignal::VoiceMailNotify>(
                     std::bind(&DBusCallManager::emitVoiceMailNotify, this, _1, _2, _3, _4)),
-                exportable_callback<CallSignal::IncomingMessage>(
+                exportable_serialized_callback<CallSignal::IncomingMessage>(
                     std::bind(&DBusCallManager::emitIncomingMessage, this, _1, _2, _3, _4)),
-                exportable_callback<CallSignal::IncomingCall>(
+                exportable_serialized_callback<CallSignal::IncomingCall>(
                     std::bind(&DBusCallManager::emitIncomingCall, this, _1, _2, _3)),
-                exportable_callback<CallSignal::IncomingCallWithMedia>(
+                exportable_serialized_callback<CallSignal::IncomingCallWithMedia>(
                     std::bind(&DBusCallManager::emitIncomingCallWithMedia, this, _1, _2, _3, _4)),
-                exportable_callback<CallSignal::MediaChangeRequested>(
+                exportable_serialized_callback<CallSignal::MediaChangeRequested>(
                     std::bind(&DBusCallManager::emitMediaChangeRequested, this, _1, _2, _3)),
-                exportable_callback<CallSignal::RecordPlaybackFilepath>(
+                exportable_serialized_callback<CallSignal::RecordPlaybackFilepath>(
                     std::bind(&DBusCallManager::emitRecordPlaybackFilepath, this, _1, _2)),
-                exportable_callback<CallSignal::ConferenceCreated>(
+                exportable_serialized_callback<CallSignal::ConferenceCreated>(
                     std::bind(&DBusCallManager::emitConferenceCreated, this, _1, _2)),
-                exportable_callback<CallSignal::ConferenceChanged>(
+                exportable_serialized_callback<CallSignal::ConferenceChanged>(
                     std::bind(&DBusCallManager::emitConferenceChanged, this, _1, _2, _3)),
-                exportable_callback<CallSignal::UpdatePlaybackScale>(
+                exportable_serialized_callback<CallSignal::UpdatePlaybackScale>(
                     std::bind(&DBusCallManager::emitUpdatePlaybackScale, this, _1, _2, _3)),
-                exportable_callback<CallSignal::ConferenceRemoved>(
+                exportable_serialized_callback<CallSignal::ConferenceRemoved>(
                     std::bind(&DBusCallManager::emitConferenceRemoved, this, _1, _2)),
-                exportable_callback<CallSignal::RecordingStateChanged>(
+                exportable_serialized_callback<CallSignal::RecordingStateChanged>(
                     std::bind(&DBusCallManager::emitRecordingStateChanged, this, _1, _2)),
-                exportable_callback<CallSignal::RtcpReportReceived>(
+                exportable_serialized_callback<CallSignal::RtcpReportReceived>(
                     std::bind(&DBusCallManager::emitOnRtcpReportReceived, this, _1, _2)),
-                exportable_callback<CallSignal::OnConferenceInfosUpdated>(
+                exportable_serialized_callback<CallSignal::OnConferenceInfosUpdated>(
                     std::bind(&DBusCallManager::emitOnConferenceInfosUpdated, this, _1, _2)),
-                exportable_callback<CallSignal::PeerHold>(
+                exportable_serialized_callback<CallSignal::PeerHold>(
                     std::bind(&DBusCallManager::emitPeerHold, this, _1, _2)),
-                exportable_callback<CallSignal::AudioMuted>(
+                exportable_serialized_callback<CallSignal::AudioMuted>(
                     std::bind(&DBusCallManager::emitAudioMuted, this, _1, _2)),
-                exportable_callback<CallSignal::VideoMuted>(
+                exportable_serialized_callback<CallSignal::VideoMuted>(
                     std::bind(&DBusCallManager::emitVideoMuted, this, _1, _2)),
-                exportable_callback<CallSignal::SmartInfo>(
+                exportable_serialized_callback<CallSignal::SmartInfo>(
                     std::bind(&DBusCallManager::emitSmartInfo, this, _1)),
-                exportable_callback<CallSignal::RemoteRecordingChanged>(
+                exportable_serialized_callback<CallSignal::RemoteRecordingChanged>(
                     std::bind(&DBusCallManager::emitRemoteRecordingChanged, this, _1, _2, _3)),
-                exportable_callback<CallSignal::MediaNegotiationStatus>(
+                exportable_serialized_callback<CallSignal::MediaNegotiationStatus>(
                     std::bind(&DBusCallManager::emitMediaNegotiationStatus, this, _1, _2, _3))
             };
 
diff --git a/bin/dbus/dbusconfigurationmanager.hpp b/bin/dbus/dbusconfigurationmanager.hpp
index a33e79844027f92913bdeb2835642cad909e109e..48157d4b3fc62158b2aaf4dacb0f13dcaff57977 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<std::string, SharedCallback> configEvHandlers = {
-            exportable_callback<ConfigurationSignal::VolumeChanged>(
+            exportable_serialized_callback<ConfigurationSignal::VolumeChanged>(
                 std::bind(&DBusConfigurationManager::emitVolumeChanged, this, _1, _2)),
-            exportable_callback<ConfigurationSignal::AccountsChanged>(
+            exportable_serialized_callback<ConfigurationSignal::AccountsChanged>(
                 std::bind(&DBusConfigurationManager::emitAccountsChanged, this)),
-            exportable_callback<ConfigurationSignal::AccountDetailsChanged>(
+            exportable_serialized_callback<ConfigurationSignal::AccountDetailsChanged>(
                 std::bind(&DBusConfigurationManager::emitAccountDetailsChanged, this, _1, _2)),
-            exportable_callback<ConfigurationSignal::StunStatusFailed>(
+            exportable_serialized_callback<ConfigurationSignal::StunStatusFailed>(
                 std::bind(&DBusConfigurationManager::emitStunStatusFailure, this, _1)),
-            exportable_callback<ConfigurationSignal::RegistrationStateChanged>(
+            exportable_serialized_callback<ConfigurationSignal::RegistrationStateChanged>(
                 std::bind(&DBusConfigurationManager::emitRegistrationStateChanged, this, _1, _2, _3, _4)),
-            exportable_callback<ConfigurationSignal::VolatileDetailsChanged>(
+            exportable_serialized_callback<ConfigurationSignal::VolatileDetailsChanged>(
                 std::bind(&DBusConfigurationManager::emitVolatileAccountDetailsChanged, this, _1, _2)),
-            exportable_callback<ConfigurationSignal::Error>(
+            exportable_serialized_callback<ConfigurationSignal::Error>(
                 std::bind(&DBusConfigurationManager::emitErrorAlert, this, _1)),
-            exportable_callback<ConfigurationSignal::IncomingAccountMessage>(
+            exportable_serialized_callback<ConfigurationSignal::IncomingAccountMessage>(
                 std::bind(&DBusConfigurationManager::emitIncomingAccountMessage, this, _1, _2, _3, _4)),
-            exportable_callback<ConfigurationSignal::AccountMessageStatusChanged>(
+            exportable_serialized_callback<ConfigurationSignal::AccountMessageStatusChanged>(
                 std::bind(&DBusConfigurationManager::emitAccountMessageStatusChanged, this, _1, _2, _3, _4, _5)),
-            exportable_callback<ConfigurationSignal::ProfileReceived>(
+            exportable_serialized_callback<ConfigurationSignal::ProfileReceived>(
                 std::bind(&DBusConfigurationManager::emitProfileReceived, this, _1, _2, _3)),
-            exportable_callback<ConfigurationSignal::ActiveCallsChanged>(
+            exportable_serialized_callback<ConfigurationSignal::ActiveCallsChanged>(
                 std::bind(&DBusConfigurationManager::emitActiveCallsChanged, this, _1, _2, _3)),
-            exportable_callback<ConfigurationSignal::ComposingStatusChanged>(
+            exportable_serialized_callback<ConfigurationSignal::ComposingStatusChanged>(
                 std::bind(&DBusConfigurationManager::emitComposingStatusChanged, this, _1, _2, _3, _4)),
-            exportable_callback<ConfigurationSignal::IncomingTrustRequest>(
+            exportable_serialized_callback<ConfigurationSignal::IncomingTrustRequest>(
                 std::bind(&DBusConfigurationManager::emitIncomingTrustRequest, this, _1, _2, _3, _4, _5)),
-            exportable_callback<ConfigurationSignal::ContactAdded>(
+            exportable_serialized_callback<ConfigurationSignal::ContactAdded>(
                 std::bind(&DBusConfigurationManager::emitContactAdded, this, _1, _2, _3)),
-            exportable_callback<ConfigurationSignal::ContactRemoved>(
+            exportable_serialized_callback<ConfigurationSignal::ContactRemoved>(
                 std::bind(&DBusConfigurationManager::emitContactRemoved, this, _1, _2, _3)),
-            exportable_callback<ConfigurationSignal::ExportOnRingEnded>(
+            exportable_serialized_callback<ConfigurationSignal::ExportOnRingEnded>(
                 std::bind(&DBusConfigurationManager::emitExportOnRingEnded, this, _1, _2, _3)),
-            exportable_callback<ConfigurationSignal::KnownDevicesChanged>(
+            exportable_serialized_callback<ConfigurationSignal::KnownDevicesChanged>(
                 std::bind(&DBusConfigurationManager::emitKnownDevicesChanged, this, _1, _2)),
-            exportable_callback<ConfigurationSignal::NameRegistrationEnded>(
+            exportable_serialized_callback<ConfigurationSignal::NameRegistrationEnded>(
                 std::bind(&DBusConfigurationManager::emitNameRegistrationEnded, this, _1, _2, _3)),
-            exportable_callback<ConfigurationSignal::UserSearchEnded>(
+            exportable_serialized_callback<ConfigurationSignal::UserSearchEnded>(
                 std::bind(&DBusConfigurationManager::emitUserSearchEnded, this, _1, _2, _3, _4)),
-            exportable_callback<ConfigurationSignal::RegisteredNameFound>(
+            exportable_serialized_callback<ConfigurationSignal::RegisteredNameFound>(
                 std::bind(&DBusConfigurationManager::emitRegisteredNameFound, this, _1, _2, _3, _4)),
-            exportable_callback<ConfigurationSignal::DeviceRevocationEnded>(
+            exportable_serialized_callback<ConfigurationSignal::DeviceRevocationEnded>(
                 std::bind(&DBusConfigurationManager::emitDeviceRevocationEnded, this, _1, _2, _3)),
-            exportable_callback<ConfigurationSignal::AccountProfileReceived>(
+            exportable_serialized_callback<ConfigurationSignal::AccountProfileReceived>(
                 std::bind(&DBusConfigurationManager::emitAccountProfileReceived, this, _1, _2, _3)),
-            exportable_callback<ConfigurationSignal::CertificatePinned>(
+            exportable_serialized_callback<ConfigurationSignal::CertificatePinned>(
                 std::bind(&DBusConfigurationManager::emitCertificatePinned, this, _1)),
-            exportable_callback<ConfigurationSignal::CertificatePathPinned>(
+            exportable_serialized_callback<ConfigurationSignal::CertificatePathPinned>(
                 std::bind(&DBusConfigurationManager::emitCertificatePathPinned, this, _1, _2)),
-            exportable_callback<ConfigurationSignal::CertificateExpired>(
+            exportable_serialized_callback<ConfigurationSignal::CertificateExpired>(
                 std::bind(&DBusConfigurationManager::emitCertificateExpired, this, _1)),
-            exportable_callback<ConfigurationSignal::CertificateStateChanged>(
+            exportable_serialized_callback<ConfigurationSignal::CertificateStateChanged>(
                 std::bind(&DBusConfigurationManager::emitCertificateStateChanged, this, _1, _2, _3)),
-            exportable_callback<ConfigurationSignal::MediaParametersChanged>(
+            exportable_serialized_callback<ConfigurationSignal::MediaParametersChanged>(
                 std::bind(&DBusConfigurationManager::emitMediaParametersChanged, this, _1)),
-            exportable_callback<ConfigurationSignal::MigrationEnded>(
+            exportable_serialized_callback<ConfigurationSignal::MigrationEnded>(
                 std::bind(&DBusConfigurationManager::emitMigrationEnded, this, _1, _2)),
-            exportable_callback<ConfigurationSignal::HardwareDecodingChanged>(
+            exportable_serialized_callback<ConfigurationSignal::HardwareDecodingChanged>(
                 std::bind(&DBusConfigurationManager::emitHardwareDecodingChanged, this, _1)),
-            exportable_callback<ConfigurationSignal::HardwareEncodingChanged>(
+            exportable_serialized_callback<ConfigurationSignal::HardwareEncodingChanged>(
                 std::bind(&DBusConfigurationManager::emitHardwareEncodingChanged, this, _1)),
-            exportable_callback<ConfigurationSignal::MessageSend>(
+            exportable_serialized_callback<ConfigurationSignal::MessageSend>(
                 std::bind(&DBusConfigurationManager::emitMessageSend, this, _1)),
         };
 
         // Audio event handlers
         const std::map<std::string, SharedCallback> audioEvHandlers = {
-            exportable_callback<AudioSignal::DeviceEvent>(
+            exportable_serialized_callback<AudioSignal::DeviceEvent>(
                 std::bind(&DBusConfigurationManager::emitAudioDeviceEvent, this)),
-            exportable_callback<AudioSignal::AudioMeter>(
+            exportable_serialized_callback<AudioSignal::AudioMeter>(
                 std::bind(&DBusConfigurationManager::emitAudioMeter, this, _1, _2)),
         };
 
         const std::map<std::string, SharedCallback> dataXferEvHandlers = {
-            exportable_callback<DataTransferSignal::DataTransferEvent>(
+            exportable_serialized_callback<DataTransferSignal::DataTransferEvent>(
                 std::bind(&DBusConfigurationManager::emitDataTransferEvent, this, _1, _2, _3, _4, _5)),
         };
 
         const std::map<std::string, SharedCallback> convEvHandlers = {
-            exportable_callback<ConversationSignal::ConversationLoaded>(
+            exportable_serialized_callback<ConversationSignal::ConversationLoaded>(
                 std::bind(&DBusConfigurationManager::emitConversationLoaded, this, _1, _2, _3, _4)),
-            exportable_callback<ConversationSignal::MessagesFound>(
+            exportable_serialized_callback<ConversationSignal::MessagesFound>(
                 std::bind(&DBusConfigurationManager::emitMessagesFound, this, _1, _2, _3, _4)),
-            exportable_callback<ConversationSignal::MessageReceived>(
+            exportable_serialized_callback<ConversationSignal::MessageReceived>(
                 std::bind(&DBusConfigurationManager::emitMessageReceived, this, _1, _2, _3)),
-            exportable_callback<ConversationSignal::ConversationProfileUpdated>(
+            exportable_serialized_callback<ConversationSignal::ConversationProfileUpdated>(
                 std::bind(&DBusConfigurationManager::emitConversationProfileUpdated, this, _1, _2, _3)),
-            exportable_callback<ConversationSignal::ConversationRequestReceived>(
+            exportable_serialized_callback<ConversationSignal::ConversationRequestReceived>(
                 std::bind(&DBusConfigurationManager::emitConversationRequestReceived, this, _1, _2, _3)),
-            exportable_callback<ConversationSignal::ConversationRequestDeclined>(
+            exportable_serialized_callback<ConversationSignal::ConversationRequestDeclined>(
                 std::bind(&DBusConfigurationManager::emitConversationRequestDeclined, this, _1, _2)),
-            exportable_callback<ConversationSignal::ConversationReady>(
+            exportable_serialized_callback<ConversationSignal::ConversationReady>(
                 std::bind(&DBusConfigurationManager::emitConversationReady, this, _1, _2)),
-            exportable_callback<ConversationSignal::ConversationRemoved>(
+            exportable_serialized_callback<ConversationSignal::ConversationRemoved>(
                 std::bind(&DBusConfigurationManager::emitConversationRemoved, this, _1, _2)),
-            exportable_callback<ConversationSignal::ConversationMemberEvent>(
+            exportable_serialized_callback<ConversationSignal::ConversationMemberEvent>(
                 std::bind(&DBusConfigurationManager::emitConversationMemberEvent, this, _1, _2, _3, _4)),
-            exportable_callback<ConversationSignal::OnConversationError>(
+            exportable_serialized_callback<ConversationSignal::OnConversationError>(
                 std::bind(&DBusConfigurationManager::emitOnConversationError, this, _1, _2, _3, _4)),
-            exportable_callback<ConversationSignal::ConversationPreferencesUpdated>(
+            exportable_serialized_callback<ConversationSignal::ConversationPreferencesUpdated>(
                 std::bind(&DBusConfigurationManager::emitConversationPreferencesUpdated, this, _1, _2, _3)),
         };
 
diff --git a/bin/dbus/dbuspluginmanagerinterface.hpp b/bin/dbus/dbuspluginmanagerinterface.hpp
index 8fed62b1793e517d234009ca4de95f1fc70c7132..370438221ed3a03dd21a8902b02556153b4cb23b 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<libjami::CallbackWrapperBase>;
 
         const std::map<std::string, SharedCallback> pluginEvHandlers = {
-            exportable_callback<libjami::PluginSignal::WebViewMessageReceived>(
+            exportable_serialized_callback<libjami::PluginSignal::WebViewMessageReceived>(
                 std::bind(&DBusPluginManagerInterface::emitWebViewMessageReceived, this, _1, _2, _3, _4)),
         };
 
diff --git a/bin/dbus/dbuspresencemanager.hpp b/bin/dbus/dbuspresencemanager.hpp
index 53427fcf6e3ef3b818249f50e7210a28132e8c0b..3e4339144b6479427506bbc78c6b9a9e374b6c3f 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<libjami::CallbackWrapperBase>;
 
         const std::map<std::string, SharedCallback> presEvHandlers = {
-            exportable_callback<PresenceSignal::NewServerSubscriptionRequest>(
+            exportable_serialized_callback<PresenceSignal::NewServerSubscriptionRequest>(
                 std::bind(&DBusPresenceManager::emitNewServerSubscriptionRequest, this, _1)),
-            exportable_callback<PresenceSignal::ServerError>(
+            exportable_serialized_callback<PresenceSignal::ServerError>(
                 std::bind(&DBusPresenceManager::emitServerError, this, _1, _2, _3)),
-            exportable_callback<PresenceSignal::NewBuddyNotification>(
+            exportable_serialized_callback<PresenceSignal::NewBuddyNotification>(
                 std::bind(&DBusPresenceManager::emitNewBuddyNotification, this, _1, _2, _3, _4)),
-            exportable_callback<PresenceSignal::NearbyPeerNotification>(
+            exportable_serialized_callback<PresenceSignal::NearbyPeerNotification>(
                 std::bind(&DBusPresenceManager::emitNearbyPeerNotification, this, _1, _2, _3, _4)),
-            exportable_callback<PresenceSignal::SubscriptionStateChanged>(
+            exportable_serialized_callback<PresenceSignal::SubscriptionStateChanged>(
                 std::bind(&DBusPresenceManager::emitSubscriptionStateChanged, this, _1, _2, _3)),
         };
 
diff --git a/bin/dbus/dbusvideomanager.hpp b/bin/dbus/dbusvideomanager.hpp
index f420bfcd6e692a6faec547bd2a71ab7490991107..ab3cd647aa0a9026a6f3b0cc86651ff129e254bf 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<libjami::CallbackWrapperBase>;
 
         const std::map<std::string, SharedCallback> videoEvHandlers = {
-            exportable_callback<VideoSignal::DeviceEvent>(
+            exportable_serialized_callback<VideoSignal::DeviceEvent>(
                 std::bind(&DBusVideoManager::emitDeviceEvent, this)),
-            exportable_callback<VideoSignal::DecodingStarted>(
+            exportable_serialized_callback<VideoSignal::DecodingStarted>(
                 std::bind(&DBusVideoManager::emitDecodingStarted, this, _1, _2, _3, _4, _5)),
-            exportable_callback<VideoSignal::DecodingStopped>(
+            exportable_serialized_callback<VideoSignal::DecodingStopped>(
                 std::bind(&DBusVideoManager::emitDecodingStopped, this, _1, _2, _3)),
         };
 
diff --git a/src/jami/jami.h b/src/jami/jami.h
index 6c88ae1d428842bb8e6de11aabbcab1b57952f76..08bcfc2ada621eea707cc65e95035af27c957772 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<void()> 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<bool>(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<typename TProto>
+class SerializedCallbackWrapper : public CallbackWrapperBase
+{
+private:
+    using TFunc = std::function<TProto>;
+    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 <typename TCallback>
+    auto ioContextWrapper(TCallback&& fun)
+    {
+        return [this, fun{std::move(fun)}](auto&&... args) -> decltype(fun(std::forward<decltype(args)>(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<CallbackWrapperBase>& p) noexcept
+    {
+        if (p) {
+            auto other = (CallbackWrapper<TProto>*) 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<bool>(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<typename Ts::cb_type>&& func,
                               std::forward<std::function<typename Ts::cb_type>>(func), file, linum));
 }
 
+template<typename Ts>
+std::pair<std::string, std::shared_ptr<CallbackWrapperBase>>
+exportable_serialized_callback(std::function<typename Ts::cb_type>&& func,
+                    const char* file = CURRENT_FILENAME(),
+                    uint32_t linum = CURRENT_LINE())
+{
+    return std::make_pair((const std::string&) Ts::name,
+                          std::make_shared<SerializedCallbackWrapper<typename Ts::cb_type>>(
+                              std::forward<std::function<typename Ts::cb_type>>(func), file, linum));
+}
+
 LIBJAMI_PUBLIC void registerSignalHandlers(
     const std::map<std::string, std::shared_ptr<CallbackWrapperBase>>&);
 LIBJAMI_PUBLIC void unregisterSignalHandlers();
diff --git a/src/ring_api.cpp b/src/ring_api.cpp
index 74a94da5fbb9c2c5cb55943b152d748aa8392abe..4f9dcddecf5571f0f8cc7ad9a98c2301f288fa07 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 <asio.hpp>
 #include <string>
 #include <vector>
 #include <map>
@@ -121,4 +122,10 @@ logging(const std::string& whom, const std::string& action) noexcept
     }
 }
 
+void
+CallbackWrapperBase::post(std::function<void()> cb)
+{
+    jami::Manager::instance().ioContext()->post(std::move(cb));
+}
+
 } // namespace libjami