Ring Daemon
Loading...
Searching...
No Matches
callservicesmanager.cpp
Go to the documentation of this file.
1/*
2 * Copyright (C) 2004-2026 Savoir-faire Linux Inc.
3 *
4 * This program is free software: you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation, either version 3 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program. If not, see <https://www.gnu.org/licenses/>.
16 */
17
18#include "callservicesmanager.h"
19
20#include "pluginmanager.h"
22
23#include "manager.h"
24#include "sip/sipcall.h"
25#include "fileutils.h"
26#include "logger.h"
27
28namespace jami {
29
31{
32 registerComponentsLifeCycleManagers(pluginManager);
33}
34
36{
37 callMediaHandlers_.clear();
38 callAVsubjects_.clear();
39 mediaHandlerToggled_.clear();
40}
41
42void
44{
45 auto predicate = [&data](const std::pair<const StreamData, AVSubjectSPtr>& item) {
46 return data.id == item.first.id && data.direction == item.first.direction && data.type == item.first.type;
47 };
48 callAVsubjects_[data.id].remove_if(predicate);
49
50 // callAVsubjects_ emplaces data and subject with callId key to easy of access
51 // When call is ended, subjects from this call are erased.
52 callAVsubjects_[data.id].emplace_back(data, subject);
53
54 // Search for activation flag.
55 for (auto& callMediaHandler : callMediaHandlers_) {
56 std::size_t found = callMediaHandler->id().find_last_of(DIR_SEPARATOR_CH);
57 // toggle is true if we should automatically activate the MediaHandler.
59 callMediaHandler->getCallMediaHandlerDetails().at(
60 "name"),
61 data.source);
62 // toggle may be overwritten if the MediaHandler was previously activated/deactivated
63 // for the given call.
64 for (const auto& toggledMediaHandlerPair : mediaHandlerToggled_[data.id]) {
67 break;
68 }
69 }
70 if (toggle)
71#ifndef __ANDROID__
72 // If activation is expected, we call activation function
74#else
75 // Due to Android's camera activation process, we don't automaticaly
76 // activate the MediaHandler here. But we set it as active
77 // and the client-android will handle its activation.
78 mediaHandlerToggled_[data.id].insert({(uintptr_t) callMediaHandler.get(), true});
79#endif
80 }
81}
82
83void
84CallServicesManager::clearAVSubject(const std::string& callId)
85{
86 callAVsubjects_.erase(callId);
87}
88
89void
90CallServicesManager::registerComponentsLifeCycleManagers(PluginManager& pluginManager)
91{
92 // registerMediaHandler may be called by the PluginManager upon loading a plugin.
93 auto registerMediaHandler = [this](void* data, std::mutex& pmMtx_) {
94 std::lock_guard lk(pmMtx_);
95 CallMediaHandlerPtr ptr {(static_cast<CallMediaHandler*>(data))};
96
97 if (!ptr)
98 return -1;
99 std::size_t found = ptr->id().find_last_of(DIR_SEPARATOR_CH);
100 // Adding preference that tells us to automatically activate a MediaHandler.
101 PluginPreferencesUtils::addAlwaysHandlerPreference(ptr->getCallMediaHandlerDetails().at("name"),
102 ptr->id().substr(0, found));
103 callMediaHandlers_.emplace_back(std::move(ptr));
104 return 0;
105 };
106
107 // unregisterMediaHandler may be called by the PluginManager while unloading.
108 auto unregisterMediaHandler = [this](void* data, std::mutex& pmMtx_) {
109 std::lock_guard lk(pmMtx_);
110 auto handlerIt = std::find_if(callMediaHandlers_.begin(),
111 callMediaHandlers_.end(),
112 [data](CallMediaHandlerPtr& handler) { return (handler.get() == data); });
113
114 if (handlerIt != callMediaHandlers_.end()) {
115 for (auto& toggledList : mediaHandlerToggled_) {
116 auto handlerId = std::find_if(toggledList.second.begin(),
117 toggledList.second.end(),
118 [handlerIt](std::pair<uintptr_t, bool> handlerIdPair) {
119 return handlerIdPair.first == (uintptr_t) handlerIt->get()
120 && handlerIdPair.second;
121 });
122 // If MediaHandler is attempting to destroy one which is currently in use, we deactivate it.
123 if (handlerId != toggledList.second.end())
124 toggleCallMediaHandler((*handlerId).first, toggledList.first, false);
125 }
126 callMediaHandlers_.erase(handlerIt);
127 }
128 return true;
129 };
130
131 // Services are registered to the PluginManager.
132 pluginManager.registerComponentManager("CallMediaHandlerManager", registerMediaHandler, unregisterMediaHandler);
133}
134
135std::vector<std::string>
137{
138 std::vector<std::string> res;
139 res.reserve(callMediaHandlers_.size());
140 for (const auto& mediaHandler : callMediaHandlers_) {
141 res.emplace_back(std::to_string((uintptr_t) mediaHandler.get()));
142 }
143 return res;
144}
145
146void
148 const std::string& callId,
149 const bool toggle)
150{
151 try {
152 toggleCallMediaHandler(std::stoull(mediaHandlerId), callId, toggle);
153 } catch (const std::exception& e) {
154 JAMI_ERR("Error toggling media handler: %s", e.what());
155 }
156}
157
158std::map<std::string, std::string>
160{
161 auto mediaHandlerId = std::stoull(mediaHandlerIdStr);
162 for (auto& mediaHandler : callMediaHandlers_) {
163 if ((uintptr_t) mediaHandler.get() == mediaHandlerId) {
164 return mediaHandler->getCallMediaHandlerDetails();
165 }
166 }
167 return {};
168}
169
170bool
171CallServicesManager::isVideoType(const CallMediaHandlerPtr& mediaHandler)
172{
173 // "dataType" is known from the MediaHandler implementation.
174 const auto& details = mediaHandler->getCallMediaHandlerDetails();
175 const auto& it = details.find("dataType");
176 if (it != details.end()) {
177 bool status;
178 std::istringstream(it->second) >> status;
179 return status;
180 }
181 // If there is no "dataType" returned, it's safer to return True and allow
182 // sender to restart.
183 return true;
184}
185
186bool
187CallServicesManager::isAttached(const CallMediaHandlerPtr& mediaHandler)
188{
189 // "attached" is known from the MediaHandler implementation.
190 const auto& details = mediaHandler->getCallMediaHandlerDetails();
191 const auto& it = details.find("attached");
192 if (it != details.end()) {
193 bool status;
194 std::istringstream(it->second) >> status;
195 return status;
196 }
197 return true;
198}
199
200std::vector<std::string>
202{
203 std::vector<std::string> ret;
204 const auto& it = mediaHandlerToggled_.find(callId);
205 if (it != mediaHandlerToggled_.end())
206 for (const auto& mediaHandlerId : it->second)
207 if (mediaHandlerId.second) // Only return active MediaHandler ids
208 ret.emplace_back(std::to_string(mediaHandlerId.first));
209 return ret;
210}
211
212bool
213CallServicesManager::setPreference(const std::string& key, const std::string& value, const std::string& rootPath)
214{
215 bool status {true};
216 for (auto& mediaHandler : callMediaHandlers_) {
217 if (mediaHandler->id().find(rootPath) != std::string::npos) {
218 if (mediaHandler->preferenceMapHasKey(key)) {
219 mediaHandler->setPreferenceAttribute(key, value);
220 status &= false;
221 }
222 }
223 }
224 return status;
225}
226
227void
229{
230 mediaHandlerToggled_.erase(callId);
231}
232
233void
234CallServicesManager::notifyAVSubject(CallMediaHandlerPtr& callMediaHandlerPtr,
235 const StreamData& data,
237{
238 if (auto soSubject = subject.lock())
239 callMediaHandlerPtr->notifyAVFrameSubject(data, soSubject);
240}
241
242void
243CallServicesManager::toggleCallMediaHandler(const uintptr_t mediaHandlerId, const std::string& callId, const bool toggle)
244{
245 auto& handlers = mediaHandlerToggled_[callId];
246 bool applyRestart = false;
247
248 for (auto subject : callAVsubjects_[callId]) {
249 auto handlerIt = std::find_if(callMediaHandlers_.begin(),
250 callMediaHandlers_.end(),
252 return ((uintptr_t) handler.get() == mediaHandlerId);
253 });
254
255 if (handlerIt != callMediaHandlers_.end()) {
256 if (toggle) {
257 notifyAVSubject((*handlerIt), subject.first, subject.second);
258 if (isAttached((*handlerIt)))
259 handlers[mediaHandlerId] = true;
260 } else {
261 (*handlerIt)->detach();
262 handlers[mediaHandlerId] = false;
263 }
264 if (subject.first.type == StreamType::video && isVideoType((*handlerIt)))
265 applyRestart = true;
266 }
267 }
268#ifndef __ANDROID__
269#ifdef ENABLE_VIDEO
270 if (applyRestart) {
271 auto call = Manager::instance().callFactory.getCall<SIPCall>(callId);
272 if (call && !call->isConferenceParticipant()) {
273 for (auto const& videoRtp : call->getRtpSessionList(MediaType::MEDIA_VIDEO))
274 videoRtp->restartSender();
275 }
276 }
277#endif
278#endif
279}
280} // namespace jami
std::shared_ptr< Call > getCall(const std::string &id) const
Return call pointer associated to given ID.Type can optionally be specified.
This abstract class is an API we need to implement from plugin side.
CallServicesManager(PluginManager &pluginManager)
Constructor registers MediaHandler API services to the PluginManager instance.
void clearAVSubject(const std::string &callId)
Clears all stream subjects related to the callId.
std::vector< std::string > getCallMediaHandlerStatus(const std::string &callId)
Returns a list of active MediaHandlers for a given call.
void toggleCallMediaHandler(const std::string &mediaHandlerId, const std::string &callId, const bool toggle)
(De)Activates a given MediaHandler to a given call.
void clearCallHandlerMaps(const std::string &callId)
Removes call from mediaHandlerToggled_ mapping.
std::map< std::string, std::string > getCallMediaHandlerDetails(const std::string &mediaHandlerIdStr)
Returns details Map from MediaHandler implementation.
void createAVSubject(const StreamData &data, AVSubjectSPtr subject)
Stores a AV stream subject with StreamData properties.
bool setPreference(const std::string &key, const std::string &value, const std::string &rootPath)
Sets a preference that may be changed while MediaHandler is active.
std::vector< std::string > getCallMediaHandlers()
List all MediaHandlers available.
static LIBJAMI_TEST_EXPORT Manager & instance()
Definition manager.cpp:694
CallFactory callFactory
Definition manager.h:826
This class manages plugin (un)loading.
static bool getAlwaysPreference(const std::string &rootPath, const std::string &handlerName, const std::string &accountId)
Read plugin's preferences and returns wheter a specific handler "always" preference is True or False.
static void addAlwaysHandlerPreference(const std::string &handlerName, const std::string &rootPath)
Creates a "always" preference for a handler if this preference doesn't exist yet.
#define DIR_SEPARATOR_CH
Definition fileutils.h:34
#define JAMI_ERR(...)
Definition logger.h:230
std::unique_ptr< CallMediaHandler > CallMediaHandlerPtr
void emitSignal(Args... args)
Definition jami_signal.h:64
std::weak_ptr< Observable< AVFrame * > > AVSubjectSPtr
@ MEDIA_VIDEO
Definition media_codec.h:47
SIPCall are SIP implementation of a normal Call.
Contains information about an AV subject.
Definition streamdata.h:30
const std::string source
Definition streamdata.h:56
const bool direction
Definition streamdata.h:52
const std::string id
Definition streamdata.h:50
const StreamType type
Definition streamdata.h:54