diff --git a/src/conference.cpp b/src/conference.cpp index 92cecdfe561f16208e563d5876f649f656b6b6e5..09bf7734a8a2f018408f7b255547e5e536d2dcbd 100644 --- a/src/conference.cpp +++ b/src/conference.cpp @@ -35,6 +35,10 @@ #include "video/video_mixer.h" #endif +#ifdef ENABLE_PLUGIN +#include "plugin/jamipluginmanager.h" +#endif + #include "call_factory.h" #include "logger.h" @@ -117,8 +121,8 @@ Conference::Conference() } // Add host in confInfo with audio and video muted if detached if (shared->getState() == State::ACTIVE_DETACHED) - newInfo.emplace_back(ParticipantInfo { - "", "", false, 0, 0, 0, 0, true, true, false, true}); + newInfo.emplace_back( + ParticipantInfo {"", "", false, 0, 0, 0, 0, true, true, false, true}); shared->updateConferenceInfo(std::move(newInfo)); }); @@ -164,6 +168,18 @@ Conference::~Conference() } } #endif // ENABLE_VIDEO +#ifdef ENABLE_PLUGIN + { + std::lock_guard<std::mutex> lk(avStreamsMtx_); + jami::Manager::instance() + .getJamiPluginManager() + .getCallServicesManager() + .clearCallHandlerMaps(getConfID()); + Manager::instance().getJamiPluginManager().getCallServicesManager().clearAVSubject( + getConfID()); + confAVStreams.clear(); + } +#endif // ENABLE_PLUGIN } Conference::State @@ -178,6 +194,64 @@ Conference::setState(State state) confState_ = state; } +#ifdef ENABLE_PLUGIN +void +Conference::createConfAVStreams() +{ + auto audioMap = [](const std::shared_ptr<jami::MediaFrame>& m) -> AVFrame* { + return std::static_pointer_cast<AudioFrame>(m)->pointer(); + }; + + // Preview and Received + if ((audioMixer_ = jami::getAudioInput(getConfID()))) { + auto audioSubject = std::make_shared<MediaStreamSubject>(audioMap); + StreamData previewStreamData {getConfID(), false, StreamType::audio, getConfID()}; + createConfAVStream(previewStreamData, *audioMixer_, audioSubject); + StreamData receivedStreamData {getConfID(), true, StreamType::audio, getConfID()}; + createConfAVStream(receivedStreamData, *audioMixer_, audioSubject); + } + +#ifdef ENABLE_VIDEO + + if (videoMixer_) { + // Review + auto receiveSubject = std::make_shared<MediaStreamSubject>(pluginVideoMap_); + StreamData receiveStreamData {getConfID(), true, StreamType::video, getConfID()}; + createConfAVStream(receiveStreamData, *videoMixer_, receiveSubject); + + // Preview + if (auto& videoPreview = videoMixer_->getVideoLocal()) { + auto previewSubject = std::make_shared<MediaStreamSubject>(pluginVideoMap_); + StreamData previewStreamData {getConfID(), false, StreamType::video, getConfID()}; + createConfAVStream(previewStreamData, *videoPreview, previewSubject); + } + } +#endif // ENABLE_VIDEO +} + +void +Conference::createConfAVStream(const StreamData& StreamData, + AVMediaStream& streamSource, + const std::shared_ptr<MediaStreamSubject>& mediaStreamSubject, + bool force) +{ + std::lock_guard<std::mutex> lk(avStreamsMtx_); + const std::string AVStreamId = StreamData.id + std::to_string(static_cast<int>(StreamData.type)) + + std::to_string(StreamData.direction); + auto it = confAVStreams.find(AVStreamId); + if (!force && it != confAVStreams.end()) + return; + + confAVStreams.erase(AVStreamId); + confAVStreams[AVStreamId] = mediaStreamSubject; + streamSource.attachPriorityObserver(mediaStreamSubject); + jami::Manager::instance() + .getJamiPluginManager() + .getCallServicesManager() + .createAVSubject(StreamData, mediaStreamSubject); +} +#endif // ENABLE_PLUGIN + void Conference::add(const std::string& participant_id) { @@ -228,6 +302,9 @@ Conference::add(const std::string& participant_id) } else JAMI_ERR("no call associate to participant %s", participant_id.c_str()); #endif // ENABLE_VIDEO +#ifdef ENABLE_PLUGIN + createConfAVStreams(); +#endif } } @@ -294,7 +371,7 @@ ConfInfo::toString() const for (const auto& info : *this) { jsonArray.append(info.toJson()); } - return Json::writeString(Json::StreamWriterBuilder{}, jsonArray); + return Json::writeString(Json::StreamWriterBuilder {}, jsonArray); } void @@ -310,19 +387,20 @@ Conference::sendConferenceInfos() if (!account) continue; - dht::ThreadPool::io().run([ - call, - confInfo = getConfInfoHostUri(account->getUsername()+ "@ring.dht", - call->getPeerNumber()), - from = account->getFromUri() - ] { + dht::ThreadPool::io().run([call, + confInfo = getConfInfoHostUri(account->getUsername() + + "@ring.dht", + call->getPeerNumber()), + from = account->getFromUri()] { call->sendTextMessage({{"application/confInfo+json", confInfo.toString()}}, from); }); } } // Inform client that layout has changed - jami::emitSignal<DRing::CallSignal::OnConferenceInfosUpdated>(id_, getConfInfoHostUri("", "").toVectorMapStringString()); + jami::emitSignal<DRing::CallSignal::OnConferenceInfosUpdated>(id_, + getConfInfoHostUri("", "") + .toVectorMapStringString()); } void @@ -395,7 +473,8 @@ Conference::detach() if (getState() == State::ACTIVE_ATTACHED) { for (const auto& p : participants_) { - Manager::instance().getRingBufferPool().unBindCallID(getCall(p)->getCallId(), RingBufferPool::DEFAULT_ID); + Manager::instance().getRingBufferPool().unBindCallID(getCall(p)->getCallId(), + RingBufferPool::DEFAULT_ID); } #ifdef ENABLE_VIDEO if (auto mixer = getVideoMixer()) { @@ -513,7 +592,17 @@ Conference::switchInput(const std::string& input) { #ifdef ENABLE_VIDEO mediaInput_ = input; - getVideoMixer()->switchInput(input); + if (auto mixer = getVideoMixer()) { + mixer->switchInput(input); +#ifdef ENABLE_PLUGIN + // Preview + if (auto& videoPreview = mixer->getVideoLocal()) { + auto previewSubject = std::make_shared<MediaStreamSubject>(pluginVideoMap_); + StreamData previewStreamData {getConfID(), false, StreamType::video, getConfID()}; + createConfAVStream(previewStreamData, *videoPreview, previewSubject, true); + } +#endif + } #endif } @@ -845,6 +934,17 @@ Conference::muteLocalHost(bool is_muted, const std::string& mediaType) } else { if (auto mixer = getVideoMixer()) { mixer->switchInput(mediaInput_); +#ifdef ENABLE_PLUGIN + // Preview + if (auto& videoPreview = mixer->getVideoLocal()) { + auto previewSubject = std::make_shared<MediaStreamSubject>(pluginVideoMap_); + StreamData previewStreamData {getConfID(), + false, + StreamType::video, + getConfID()}; + createConfAVStream(previewStreamData, *videoPreview, previewSubject, true); + } +#endif } } videoMuted_ = is_muted; @@ -892,7 +992,6 @@ Conference::resizeRemoteParticipant(const std::string& peerURI, ParticipantInfo& remoteCell.y = remoteCell.y / zoomY + localCell.y; remoteCell.w = remoteCell.w / zoomX; remoteCell.h = remoteCell.h / zoomY; - } std::string @@ -902,7 +1001,7 @@ Conference::confInfo2str(const ConfInfo& confInfo) for (const auto& info : confInfo) { jsonArray.append(info.toJson()); } - return Json::writeString(Json::StreamWriterBuilder{}, jsonArray); + return Json::writeString(Json::StreamWriterBuilder {}, jsonArray); } void diff --git a/src/conference.h b/src/conference.h index 76dc6ec0ea086a8ee100e088ab9920c51a7e18b6..928485c63e3d956320b109debce294f4b0440030 100644 --- a/src/conference.h +++ b/src/conference.h @@ -30,6 +30,7 @@ #include <vector> #include <string_view> #include <map> +#include <functional> #include "audio/audio_input.h" @@ -37,6 +38,10 @@ #include "recordable.h" +#ifdef ENABLE_PLUGIN +#include "plugin/streamdata.h" +#endif + namespace jami { class Call; @@ -110,18 +115,11 @@ struct ParticipantInfo friend bool operator==(const ParticipantInfo& p1, const ParticipantInfo& p2) { - return - p1.uri == p2.uri - and p1.device == p2.device - and p1.active == p2.active - and p1.x == p2.x - and p1.y == p2.y - and p1.w == p2.w - and p1.h == p2.h - and p1.videoMuted == p2.videoMuted - and p1.audioLocalMuted == p2.audioLocalMuted - and p1.audioModeratorMuted == p2.audioModeratorMuted - and p1.isModerator == p2.isModerator; + return p1.uri == p2.uri and p1.device == p2.device and p1.active == p2.active + and p1.x == p2.x and p1.y == p2.y and p1.w == p2.w and p1.h == p2.h + and p1.videoMuted == p2.videoMuted and p1.audioLocalMuted == p2.audioLocalMuted + and p1.audioModeratorMuted == p2.audioModeratorMuted + and p1.isModerator == p2.isModerator; } friend bool operator!=(const ParticipantInfo& p1, const ParticipantInfo& p2) @@ -138,8 +136,9 @@ struct ConfInfo : public std::vector<ParticipantInfo> friend bool operator==(const ConfInfo& c1, const ConfInfo& c2) { for (auto& p1 : c1) { - auto it = std::find_if(c2.begin(), c2.end(), - [p1] (const ParticipantInfo& p2) { return p1 == p2; }); + auto it = std::find_if(c2.begin(), c2.end(), [p1](const ParticipantInfo& p2) { + return p1 == p2; + }); if (it != c2.end()) continue; else @@ -148,14 +147,10 @@ struct ConfInfo : public std::vector<ParticipantInfo> return true; } - friend bool operator!=(const ConfInfo& c1, const ConfInfo& c2) - { - return !(c1 == c2); - } + friend bool operator!=(const ConfInfo& c1, const ConfInfo& c2) { return !(c1 == c2); } std::vector<std::map<std::string, std::string>> toVectorMapStringString() const; std::string toString() const; - }; using ParticipantSet = std::set<std::string>; @@ -345,6 +340,44 @@ private: std::map<std::string, ConfInfo> remoteHosts_; std::string confInfo2str(const ConfInfo& confInfo); std::string_view findHostforRemoteParticipant(std::string_view uri); + +#ifdef ENABLE_PLUGIN + /** + * Call Streams and some typedefs + */ + using AVMediaStream = Observable<std::shared_ptr<MediaFrame>>; + using MediaStreamSubject = PublishMapSubject<std::shared_ptr<MediaFrame>, AVFrame*>; + +#ifdef ENABLE_VIDEO + /** + * Map: maps the VideoFrame to an AVFrame + **/ + std::function<AVFrame*(const std::shared_ptr<jami::MediaFrame>&)> pluginVideoMap_ = + [](const std::shared_ptr<jami::MediaFrame>& m) -> AVFrame* { + return std::static_pointer_cast<VideoFrame>(m)->pointer(); + }; +#endif // ENABLE_VIDEO + + /** + * @brief createConfAVStream + * Creates a conf AV stream like video input, video receive, audio input or audio receive + * @param StreamData + * @param streamSource + * @param mediaStreamSubject + */ + void createConfAVStream(const StreamData& StreamData, + AVMediaStream& streamSource, + const std::shared_ptr<MediaStreamSubject>& mediaStreamSubject, + bool force = false); + /** + * @brief createConfAVStreams + * Creates all Conf AV Streams (2 if audio, 4 if audio video) + */ + void createConfAVStreams(); + + std::mutex avStreamsMtx_ {}; + std::map<std::string, std::shared_ptr<MediaStreamSubject>> confAVStreams; +#endif // ENABLE_PLUGIN }; } // namespace jami diff --git a/src/media/video/video_mixer.h b/src/media/video/video_mixer.h index c55b9225bcee9dc386f790813522ed2c9663081d..c1470c2af44801a071fafaf193c3f8f98a488a3c 100644 --- a/src/media/video/video_mixer.h +++ b/src/media/video/video_mixer.h @@ -85,7 +85,9 @@ public: void setOnSourcesUpdated(OnSourcesUpdatedCb&& cb) { onSourcesUpdated_ = std::move(cb); } - MediaStream getStream(const std::string& name) const; + MediaStream getStream(const std::string& name) const; + + std::shared_ptr<VideoFrameActiveWriter>& getVideoLocal() { return videoLocal_; } private: NON_COPYABLE(VideoMixer); diff --git a/src/media/video/video_rtp_session.cpp b/src/media/video/video_rtp_session.cpp index cb0e6c5ca939df950fc2691ec56305a2c2cb11c9..2dce08b767f43f07c78812705fad6fa150073fde 100644 --- a/src/media/video/video_rtp_session.cpp +++ b/src/media/video/video_rtp_session.cpp @@ -29,6 +29,10 @@ #include "socket_pair.h" #include "sip/sipvoiplink.h" // for enqueueKeyframeRequest #include "manager.h" +#ifdef ENABLE_PLUGIN +#include "plugin/streamdata.h" +#include "plugin/jamipluginmanager.h" +#endif #include "logger.h" #include "string_utils.h" #include "call.h" @@ -104,7 +108,8 @@ VideoRtpSession::startSender() if (not conference_) { videoLocal_ = getVideoCamera(); if (auto input = Manager::instance().getVideoManager().videoInput.lock()) { - std::static_pointer_cast<VideoInput>(videoLocal_)->setSuccessfulSetupCb(onSuccessfulSetup_); + std::static_pointer_cast<VideoInput>(videoLocal_) + ->setSuccessfulSetupCb(onSuccessfulSetup_); auto newParams = input->switchInput(input_); try { if (newParams.valid() @@ -146,21 +151,18 @@ VideoRtpSession::startSender() try { sender_.reset(); socketPair_->stopSendOp(false); - MediaStream ms = !conference_ ? - MediaStream("video sender", - AV_PIX_FMT_YUV420P, - 1 / static_cast<rational<int>>(localVideoParams_.framerate), - localVideoParams_.width, - localVideoParams_.height, - send_.bitrate, - static_cast<rational<int>>(localVideoParams_.framerate)) : - conference_->getVideoMixer()->getStream("Video Sender"); - sender_.reset(new VideoSender(getRemoteRtpUri(), - ms, - send_, - *socketPair_, - initSeqVal_ + 1, - mtu_)); + MediaStream ms + = !conference_ + ? MediaStream("video sender", + AV_PIX_FMT_YUV420P, + 1 / static_cast<rational<int>>(localVideoParams_.framerate), + localVideoParams_.width, + localVideoParams_.height, + send_.bitrate, + static_cast<rational<int>>(localVideoParams_.framerate)) + : conference_->getVideoMixer()->getStream("Video Sender"); + sender_.reset( + new VideoSender(getRemoteRtpUri(), ms, send_, *socketPair_, initSeqVal_ + 1, mtu_)); if (changeOrientationCallback_) sender_->setChangeOrientationCallback(changeOrientationCallback_); if (socketPair_) @@ -351,15 +353,15 @@ VideoRtpSession::enterConference(Conference* conference) // TODO is this correct? The video Mixer should be enabled for a detached conference even if we // are not sending values videoMixer_ = conference->getVideoMixer(); - auto conf_res = split_string_to_unsigned(jami::Manager::instance().videoPreferences.getConferenceResolution(), 'x'); + auto conf_res = split_string_to_unsigned(jami::Manager::instance() + .videoPreferences.getConferenceResolution(), + 'x'); if (conf_res.size() != 2 or conf_res[0] <= 0 or conf_res[1] <= 0) { JAMI_ERR("Conference resolution is invalid"); return; } #if defined(__APPLE__) && TARGET_OS_MAC - videoMixer_->setParameters(conf_res[0], - conf_res[1], - AV_PIX_FMT_NV12); + videoMixer_->setParameters(conf_res[0], conf_res[1], AV_PIX_FMT_NV12); #else videoMixer_->setParameters(conf_res[0], conf_res[1]); #endif @@ -760,6 +762,5 @@ VideoRtpSession::delayMonitor(int gradient, int deltaT) } } } - } // namespace video } // namespace jami diff --git a/src/media/video/video_rtp_session.h b/src/media/video/video_rtp_session.h index d4894a2b98944be633492015a1294b367efb5510..0243a0927c8ea070e305410ea3adf4c1dc38b06f 100644 --- a/src/media/video/video_rtp_session.h +++ b/src/media/video/video_rtp_session.h @@ -98,8 +98,12 @@ public: void initRecorder(std::shared_ptr<MediaRecorder>& rec) override; void deinitRecorder(std::shared_ptr<MediaRecorder>& rec) override; + bool hasConference() { return conference_; } + std::shared_ptr<VideoFrameActiveWriter>& getVideoLocal() { return videoLocal_; } + std::shared_ptr<VideoMixer>& getVideoMixer() { return videoMixer_; } + std::unique_ptr<VideoReceiveThread>& getVideoReceive() { return receiveThread_; } private: diff --git a/src/observer.h b/src/observer.h index a0daaa3bf6c0f829d30e6617b292bf860ec2cdd2..b6f2ba7c0d54eba95780621b786abfb5f106e8af 100644 --- a/src/observer.h +++ b/src/observer.h @@ -90,10 +90,12 @@ public: void detachPriorityObserver(Observer<T>* o) { std::lock_guard<std::mutex> lk(mutex_); - for (auto it = priority_observers_.begin(); it != priority_observers_.end(); ++it) { + for (auto it = priority_observers_.begin(); it != priority_observers_.end(); it++) { if (auto so = it->lock()) { if (so.get() == o) { + so->detached(this); priority_observers_.erase(it); + return; } } } @@ -121,9 +123,9 @@ protected: std::lock_guard<std::mutex> lk(mutex_); for (auto it = priority_observers_.begin(); it != priority_observers_.end();) { if (auto so = it->lock()) { + it++; try { so->update(this, data); - ++it; } catch (std::exception& e) { JAMI_ERR() << e.what(); } @@ -192,13 +194,7 @@ public: : map_ {f} {} - void update(Observable<T1>*, const T1& t) override - { - std::lock_guard<std::mutex> lk(this->mutex_); - for (const auto& observer : this->observers_) { - observer->update(this, map_(t)); - } - } + void update(Observable<T1>*, const T1& t) override { this->notify(map_(t)); } /** * @brief attached @@ -222,7 +218,11 @@ public: virtual void detached(Observable<T1>*) override { std::lock_guard<std::mutex> lk(this->mutex_); - JAMI_WARN() << "PublishMapSubject: detaching observers"; + for (auto& pobs : this->priority_observers_) { + if (auto so = pobs.lock()) { + so->detached(this); + } + } for (auto& o : this->observers_) o->detached(this); } @@ -232,11 +232,7 @@ public: * Detach all observers to avoid making them call this observable when * destroyed **/ - ~PublishMapSubject() - { - JAMI_WARN() << "~PublishMapSubject()"; - detached(nullptr); - } + ~PublishMapSubject() { detached(nullptr); } private: F map_; diff --git a/src/plugin/callservicesmanager.cpp b/src/plugin/callservicesmanager.cpp index 00f4f755f85a4a6763c9020f0d04eaaede657317..29a3424a60ab34a1c4f7ff57ac383da43502e5e4 100644 --- a/src/plugin/callservicesmanager.cpp +++ b/src/plugin/callservicesmanager.cpp @@ -45,6 +45,12 @@ CallServicesManager::~CallServicesManager() void CallServicesManager::createAVSubject(const StreamData& data, AVSubjectSPtr subject) { + auto predicate = [&data](std::pair<const StreamData, AVSubjectSPtr> item) { + return data.id == item.first.id && data.direction == item.first.direction + && data.type == item.first.type; + }; + callAVsubjects_[data.id].remove_if(predicate); + // callAVsubjects_ emplaces data and subject with callId key to easy of access // When call is ended, subjects from this call are erased. callAVsubjects_[data.id].emplace_back(data, subject); @@ -87,7 +93,8 @@ void CallServicesManager::registerComponentsLifeCycleManagers(PluginManager& pluginManager) { // registerMediaHandler may be called by the PluginManager upon loading a plugin. - auto registerMediaHandler = [this](void* data) { + auto registerMediaHandler = [this](void* data, std::mutex& pmMtx_) { + std::lock_guard<std::mutex> lk(pmMtx_); CallMediaHandlerPtr ptr {(static_cast<CallMediaHandler*>(data))}; if (!ptr) @@ -102,7 +109,8 @@ CallServicesManager::registerComponentsLifeCycleManagers(PluginManager& pluginMa }; // unregisterMediaHandler may be called by the PluginManager while unloading. - auto unregisterMediaHandler = [this](void* data) { + auto unregisterMediaHandler = [this](void* data, std::mutex& pmMtx_) { + std::lock_guard<std::mutex> lk(pmMtx_); auto handlerIt = std::find_if(callMediaHandlers_.begin(), callMediaHandlers_.end(), [data](CallMediaHandlerPtr& handler) { @@ -273,9 +281,9 @@ CallServicesManager::toggleCallMediaHandler(const uintptr_t mediaHandlerId, } #ifndef __ANDROID__ if (applyRestart) { - if (auto call = Manager::instance().callFactory.getCall<SIPCall>(callId)) { + auto call = Manager::instance().callFactory.getCall<SIPCall>(callId); + if (call && call->getConfId().empty()) call->getVideoRtp().restartSender(); - } } #endif } diff --git a/src/plugin/chatservicesmanager.cpp b/src/plugin/chatservicesmanager.cpp index 96e4581dddd7a421ae367c82077243f5abf2c96c..e84b0a6b39fe330041d6761ae7bf9e40dc17be88 100644 --- a/src/plugin/chatservicesmanager.cpp +++ b/src/plugin/chatservicesmanager.cpp @@ -35,7 +35,8 @@ void ChatServicesManager::registerComponentsLifeCycleManagers(PluginManager& pluginManager) { // registerChatHandler may be called by the PluginManager upon loading a plugin. - auto registerChatHandler = [this](void* data) { + auto registerChatHandler = [this](void* data, std::mutex& pmMtx_) { + std::lock_guard<std::mutex> lk(pmMtx_); ChatHandlerPtr ptr {(static_cast<ChatHandler*>(data))}; if (!ptr) @@ -50,7 +51,8 @@ ChatServicesManager::registerComponentsLifeCycleManagers(PluginManager& pluginMa }; // unregisterChatHandler may be called by the PluginManager while unloading. - auto unregisterChatHandler = [this](void* data) { + auto unregisterChatHandler = [this](void* data, std::mutex& pmMtx_) { + std::lock_guard<std::mutex> lk(pmMtx_); auto handlerIt = std::find_if(chatHandlers_.begin(), chatHandlers_.end(), [data](ChatHandlerPtr& handler) { diff --git a/src/plugin/pluginmanager.cpp b/src/plugin/pluginmanager.cpp index ae510607231096725761ad82919fa43f0c834c64..eb99d226356fbec5b3b3398373d7087226bdcf59 100644 --- a/src/plugin/pluginmanager.cpp +++ b/src/plugin/pluginmanager.cpp @@ -33,9 +33,9 @@ PluginManager::PluginManager() PluginManager::~PluginManager() { - for (auto func : exitFuncVec_) { + for (auto& func : exitFunc_) { try { - (*func)(); + func.second(); } catch (...) { JAMI_ERR() << "Exception caught during plugin exit"; } @@ -44,7 +44,7 @@ PluginManager::~PluginManager() dynPluginMap_.clear(); exactMatchMap_.clear(); wildCardVec_.clear(); - exitFuncVec_.clear(); + exitFunc_.clear(); } bool @@ -85,7 +85,9 @@ PluginManager::unload(const std::string& path) destroyPluginComponents(path); auto it = dynPluginMap_.find(path); if (it != dynPluginMap_.end()) { - it->second.second = false; + std::lock_guard<std::mutex> lk(mtx_); + exitFunc_[path](); + dynPluginMap_.erase(it); } return true; @@ -120,7 +122,7 @@ PluginManager::destroyPluginComponents(const std::string& path) for (auto pairIt = itComponents->second.begin(); pairIt != itComponents->second.end();) { auto clcm = componentsLifeCycleManagers_.find(pairIt->first); if (clcm != componentsLifeCycleManagers_.end()) { - clcm->second.destroyComponent(pairIt->second); + clcm->second.destroyComponent(pairIt->second, mtx_); pairIt = itComponents->second.erase(pairIt); } } @@ -209,7 +211,7 @@ PluginManager::registerPlugin(std::unique_ptr<Plugin>& plugin) return false; } - exitFuncVec_.push_back(exitFunc); + exitFunc_[pluginPtr->getPath()] = exitFunc; return true; } @@ -259,7 +261,7 @@ PluginManager::manageComponent(const DLPlugin* plugin, const std::string& name, const auto& componentLifecycleManager = iter->second; try { - int32_t r = componentLifecycleManager.takeComponentOwnership(data); + int32_t r = componentLifecycleManager.takeComponentOwnership(data, mtx_); if (r == 0) { pluginComponentsMap_[plugin->getPath()].emplace_back(name, data); } diff --git a/src/plugin/pluginmanager.h b/src/plugin/pluginmanager.h index 16f95b867c084aa77d8f196fc65afbf54890060e..703f8835bb7ec57cbaf88fe77b06a85fc45bbaeb 100644 --- a/src/plugin/pluginmanager.h +++ b/src/plugin/pluginmanager.h @@ -56,7 +56,7 @@ private: // A Component is either a MediaHandler or a ChatHandler. // A ComponentFunction is a function that may start or end a component life. - using ComponentFunction = std::function<int32_t(void*)>; + using ComponentFunction = std::function<int32_t(void*, std::mutex&)>; // A list of component type (MediaHandler or ChatHandler), and component pointer pairs using ComponentPtrList = std::list<std::pair<std::string, void*>>; @@ -86,8 +86,8 @@ private: // Map between plugins' library path and their components list using PluginComponentsMap = std::map<std::string, ComponentPtrList>; - // Vector with plugins' destruction functions - using ExitFuncVec = std::vector<JAMI_PluginExitFunc>; + // Map with plugins' destruction functions + using ExitFuncMap = std::map<std::string, JAMI_PluginExitFunc>; using ObjectFactoryVec = std::vector<ObjectFactory>; using ObjectFactoryMap = std::map<std::string, ObjectFactory>; @@ -215,7 +215,7 @@ private: PluginMap dynPluginMap_ {}; // Should keep reference to plugins' destruction functions read during library loading. - ExitFuncVec exitFuncVec_ {}; + ExitFuncMap exitFunc_ {}; ObjectFactoryMap exactMatchMap_ {}; ObjectFactoryVec wildCardVec_ {}; @@ -228,5 +228,7 @@ private: // Keeps a map between plugins' library path and their components list. PluginComponentsMap pluginComponentsMap_ {}; + + std::mutex mtx_; }; } // namespace jami diff --git a/src/sip/sipcall.cpp b/src/sip/sipcall.cpp index 022e0d29d9afd1577609af9e166ed0b16bec4769..74bf4bb9257a3456be4b58c98ddcb448efd6a51c 100644 --- a/src/sip/sipcall.cpp +++ b/src/sip/sipcall.cpp @@ -41,8 +41,8 @@ #include "dring/media_const.h" #include "client/ring_signal.h" #include "ice_transport.h" + #ifdef ENABLE_PLUGIN -// Plugin manager #include "plugin/jamipluginmanager.h" #endif @@ -128,24 +128,29 @@ SIPCall::getSIPAccount() const void SIPCall::createCallAVStreams() { + if (videortp_->hasConference()) { + clearCallAVStreams(); + return; + } + auto baseId = getCallId(); /** * Map: maps the AudioFrame to an AVFrame **/ - auto audioMap = [](const std::shared_ptr<jami::MediaFrame> m) -> AVFrame* { + auto audioMap = [](const std::shared_ptr<jami::MediaFrame>& m) -> AVFrame* { return std::static_pointer_cast<AudioFrame>(m)->pointer(); }; // Preview if (auto& localAudio = avformatrtp_->getAudioLocal()) { auto previewSubject = std::make_shared<MediaStreamSubject>(audioMap); - StreamData microStreamData {getCallId(), false, StreamType::audio, getPeerNumber()}; + StreamData microStreamData {baseId, false, StreamType::audio, getPeerNumber()}; createCallAVStream(microStreamData, *localAudio, previewSubject); } // Receive if (auto& audioReceive = avformatrtp_->getAudioReceive()) { auto receiveSubject = std::make_shared<MediaStreamSubject>(audioMap); - StreamData phoneStreamData {getCallId(), true, StreamType::audio, getPeerNumber()}; + StreamData phoneStreamData {baseId, true, StreamType::audio, getPeerNumber()}; createCallAVStream(phoneStreamData, (AVMediaStream&) *audioReceive, receiveSubject); } #ifdef ENABLE_VIDEO @@ -153,21 +158,21 @@ SIPCall::createCallAVStreams() /** * Map: maps the VideoFrame to an AVFrame **/ - auto videoMap = [](const std::shared_ptr<jami::MediaFrame> m) -> AVFrame* { + auto videoMap = [](const std::shared_ptr<jami::MediaFrame>& m) -> AVFrame* { return std::static_pointer_cast<VideoFrame>(m)->pointer(); }; // Preview if (auto& videoPreview = videortp_->getVideoLocal()) { auto previewSubject = std::make_shared<MediaStreamSubject>(videoMap); - StreamData previewStreamData {getCallId(), false, StreamType::video, getPeerNumber()}; + StreamData previewStreamData {baseId, false, StreamType::video, getPeerNumber()}; createCallAVStream(previewStreamData, *videoPreview, previewSubject); } // Receive if (auto& videoReceive = videortp_->getVideoReceive()) { auto receiveSubject = std::make_shared<MediaStreamSubject>(videoMap); - StreamData receiveStreamData {getCallId(), true, StreamType::video, getPeerNumber()}; + StreamData receiveStreamData {baseId, true, StreamType::video, getPeerNumber()}; createCallAVStream(receiveStreamData, *videoReceive, receiveSubject); } } @@ -192,6 +197,13 @@ SIPCall::createCallAVStream(const StreamData& StreamData, .getCallServicesManager() .createAVSubject(StreamData, it->second); } + +void +SIPCall::clearCallAVStreams() +{ + std::lock_guard<std::mutex> lk(avStreamsMtx_); + callAVStreams.clear(); +} #endif // ENABLE_PLUGIN void @@ -1238,11 +1250,10 @@ SIPCall::startAllMedia() #endif rtp->updateMedia(remote, local); - rtp->setSuccessfulSetupCb( - [wthis = weak()](MediaType type, bool isRemote) { - if (auto this_ = wthis.lock()) - this_->rtpSetupSuccess(type, isRemote); - }); + rtp->setSuccessfulSetupCb([wthis = weak()](MediaType type, bool isRemote) { + if (auto this_ = wthis.lock()) + this_->rtpSetupSuccess(type, isRemote); + }); #ifdef ENABLE_VIDEO videortp_->setRequestKeyFrameCallback([wthis = weak()] { @@ -1337,14 +1348,11 @@ SIPCall::stopAllMedia() #endif #ifdef ENABLE_PLUGIN { + clearCallAVStreams(); std::lock_guard<std::mutex> lk(avStreamsMtx_); - callAVStreams.erase(getCallId() + "00"); // audio out - callAVStreams.erase(getCallId() + "01"); // audio in - callAVStreams.erase(getCallId() + "10"); // video out - callAVStreams.erase(getCallId() + "11"); // video in + Manager::instance().getJamiPluginManager().getCallServicesManager().clearAVSubject( + getCallId()); } - jami::Manager::instance().getJamiPluginManager().getCallServicesManager().clearAVSubject( - getCallId()); #endif } @@ -1394,8 +1402,7 @@ SIPCall::onMediaUpdate() std::lock_guard<std::recursive_mutex> lk {this_->callMutex_}; // The call is already ended, so we don't need to restart medias if (not this_->inviteSession_ - or this_->inviteSession_->state == PJSIP_INV_STATE_DISCONNECTED - or not this_->sdp_) + or this_->inviteSession_->state == PJSIP_INV_STATE_DISCONNECTED or not this_->sdp_) return; // If ICE is not used, start medias now auto rem_ice_attrs = this_->sdp_->getIceAttributes(); @@ -1580,6 +1587,9 @@ SIPCall::enterConference(const std::string& confId) auto conf = Manager::instance().getConferenceFromID(confId); getVideoRtp().enterConference(conf.get()); #endif +#ifdef ENABLE_PLUGIN + clearCallAVStreams(); +#endif } void @@ -1588,6 +1598,9 @@ SIPCall::exitConference() #ifdef ENABLE_VIDEO getVideoRtp().exitConference(); #endif +#ifdef ENABLE_PLUGIN + createCallAVStreams(); +#endif } bool diff --git a/src/sip/sipcall.h b/src/sip/sipcall.h index 619769accb12f1d988a4f2288282d1e4e694f35d..d41676304e32135223052e0bcc01c2a6267f9027 100644 --- a/src/sip/sipcall.h +++ b/src/sip/sipcall.h @@ -261,13 +261,13 @@ private: return tmpMediaTransport_ ? tmpMediaTransport_.get() : mediaTransport_.get(); } +#ifdef ENABLE_PLUGIN /** * Call Streams and some typedefs */ using AVMediaStream = Observable<std::shared_ptr<MediaFrame>>; using MediaStreamSubject = PublishMapSubject<std::shared_ptr<MediaFrame>, AVFrame*>; -#ifdef ENABLE_PLUGIN /** * @brief createCallAVStream * Creates a call AV stream like video input, video receive, audio input or audio receive @@ -283,10 +283,15 @@ private: * Creates all Call AV Streams (2 if audio, 4 if audio video) */ void createCallAVStreams(); -#endif // ENABLE_PLUGIN + + /** + * @brief Detach all plugins from call streams; + */ + void clearCallAVStreams(); std::mutex avStreamsMtx_ {}; std::map<std::string, std::shared_ptr<MediaStreamSubject>> callAVStreams; +#endif // ENABLE_PLUGIN void setCallMediaLocal();