Ring Daemon 16.0.0
Loading...
Searching...
No Matches
callservicesmanager.cpp
Go to the documentation of this file.
1/*
2 * Copyright (C) 2004-2025 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](std::pair<const StreamData, AVSubjectSPtr> item) {
46 return data.id == item.first.id && data.direction == item.first.direction
47 && data.type == item.first.type;
48 };
49 callAVsubjects_[data.id].remove_if(predicate);
50
51 // callAVsubjects_ emplaces data and subject with callId key to easy of access
52 // When call is ended, subjects from this call are erased.
53 callAVsubjects_[data.id].emplace_back(data, subject);
54
55 // Search for activation flag.
56 for (auto& callMediaHandler : callMediaHandlers_) {
57 std::size_t found = callMediaHandler->id().find_last_of(DIR_SEPARATOR_CH);
58 // toggle is true if we should automatically activate the MediaHandler.
60 callMediaHandler->id().substr(0, found),
61 callMediaHandler->getCallMediaHandlerDetails().at("name"),
62 data.source);
63 // toggle may be overwritten if the MediaHandler was previously activated/deactivated
64 // for the given call.
65 for (const auto& toggledMediaHandlerPair : mediaHandlerToggled_[data.id]) {
68 break;
69 }
70 }
71 if (toggle)
72#ifndef __ANDROID__
73 // If activation is expected, we call activation function
75#else
76 // Due to Android's camera activation process, we don't automaticaly
77 // activate the MediaHandler here. But we set it as active
78 // and the client-android will handle its activation.
79 mediaHandlerToggled_[data.id].insert({(uintptr_t) callMediaHandler.get(), true});
80#endif
81 }
82}
83
84void
85CallServicesManager::clearAVSubject(const std::string& callId)
86{
87 callAVsubjects_.erase(callId);
88}
89
90void
91CallServicesManager::registerComponentsLifeCycleManagers(PluginManager& pluginManager)
92{
93 // registerMediaHandler may be called by the PluginManager upon loading a plugin.
94 auto registerMediaHandler = [this](void* data, std::mutex& pmMtx_) {
95 std::lock_guard lk(pmMtx_);
96 CallMediaHandlerPtr ptr {(static_cast<CallMediaHandler*>(data))};
97
98 if (!ptr)
99 return -1;
100 std::size_t found = ptr->id().find_last_of(DIR_SEPARATOR_CH);
101 // Adding preference that tells us to automatically activate a MediaHandler.
102 PluginPreferencesUtils::addAlwaysHandlerPreference(ptr->getCallMediaHandlerDetails().at(
103 "name"),
104 ptr->id().substr(0, found));
105 callMediaHandlers_.emplace_back(std::move(ptr));
106 return 0;
107 };
108
109 // unregisterMediaHandler may be called by the PluginManager while unloading.
110 auto unregisterMediaHandler = [this](void* data, std::mutex& pmMtx_) {
111 std::lock_guard lk(pmMtx_);
112 auto handlerIt = std::find_if(callMediaHandlers_.begin(),
113 callMediaHandlers_.end(),
115 return (handler.get() == data);
116 });
117
118 if (handlerIt != callMediaHandlers_.end()) {
119 for (auto& toggledList : mediaHandlerToggled_) {
120 auto handlerId = std::find_if(toggledList.second.begin(),
121 toggledList.second.end(),
122 [handlerIt](
123 std::pair<uintptr_t, bool> handlerIdPair) {
124 return handlerIdPair.first
125 == (uintptr_t) handlerIt->get()
126 && handlerIdPair.second;
127 });
128 // If MediaHandler is attempting to destroy one which is currently in use, we deactivate it.
129 if (handlerId != toggledList.second.end())
130 toggleCallMediaHandler((*handlerId).first, toggledList.first, false);
131 }
132 callMediaHandlers_.erase(handlerIt);
133 }
134 return true;
135 };
136
137 // Services are registered to the PluginManager.
138 pluginManager.registerComponentManager("CallMediaHandlerManager",
141}
142
143std::vector<std::string>
145{
146 std::vector<std::string> res;
147 res.reserve(callMediaHandlers_.size());
148 for (const auto& mediaHandler : callMediaHandlers_) {
149 res.emplace_back(std::to_string((uintptr_t) mediaHandler.get()));
150 }
151 return res;
152}
153
154void
156 const std::string& callId,
157 const bool toggle)
158{
159 try {
160 toggleCallMediaHandler(std::stoull(mediaHandlerId), callId, toggle);
161 } catch (const std::exception& e) {
162 JAMI_ERR("Error toggling media handler: %s", e.what());
163 }
164}
165
166std::map<std::string, std::string>
168{
169 auto mediaHandlerId = std::stoull(mediaHandlerIdStr);
170 for (auto& mediaHandler : callMediaHandlers_) {
171 if ((uintptr_t) mediaHandler.get() == mediaHandlerId) {
172 return mediaHandler->getCallMediaHandlerDetails();
173 }
174 }
175 return {};
176}
177
178bool
179CallServicesManager::isVideoType(const CallMediaHandlerPtr& mediaHandler)
180{
181 // "dataType" is known from the MediaHandler implementation.
182 const auto& details = mediaHandler->getCallMediaHandlerDetails();
183 const auto& it = details.find("dataType");
184 if (it != details.end()) {
185 bool status;
186 std::istringstream(it->second) >> status;
187 return status;
188 }
189 // If there is no "dataType" returned, it's safer to return True and allow
190 // sender to restart.
191 return true;
192}
193
194bool
195CallServicesManager::isAttached(const CallMediaHandlerPtr& mediaHandler)
196{
197 // "attached" is known from the MediaHandler implementation.
198 const auto& details = mediaHandler->getCallMediaHandlerDetails();
199 const auto& it = details.find("attached");
200 if (it != details.end()) {
201 bool status;
202 std::istringstream(it->second) >> status;
203 return status;
204 }
205 return true;
206}
207
208std::vector<std::string>
210{
211 std::vector<std::string> ret;
212 const auto& it = mediaHandlerToggled_.find(callId);
213 if (it != mediaHandlerToggled_.end())
214 for (const auto& mediaHandlerId : it->second)
215 if (mediaHandlerId.second) // Only return active MediaHandler ids
216 ret.emplace_back(std::to_string(mediaHandlerId.first));
217 return ret;
218}
219
220bool
222 const std::string& value,
223 const std::string& rootPath)
224{
225 bool status {true};
226 for (auto& mediaHandler : callMediaHandlers_) {
227 if (mediaHandler->id().find(rootPath) != std::string::npos) {
228 if (mediaHandler->preferenceMapHasKey(key)) {
229 mediaHandler->setPreferenceAttribute(key, value);
230 status &= false;
231 }
232 }
233 }
234 return status;
235}
236
237void
239{
240 mediaHandlerToggled_.erase(callId);
241}
242
243void
244CallServicesManager::notifyAVSubject(CallMediaHandlerPtr& callMediaHandlerPtr,
245 const StreamData& data,
247{
248 if (auto soSubject = subject.lock())
249 callMediaHandlerPtr->notifyAVFrameSubject(data, soSubject);
250}
251
252void
254 const std::string& callId,
255 const bool toggle)
256{
257 auto& handlers = mediaHandlerToggled_[callId];
258 bool applyRestart = false;
259
260 for (auto subject : callAVsubjects_[callId]) {
261 auto handlerIt = std::find_if(callMediaHandlers_.begin(),
262 callMediaHandlers_.end(),
264 return ((uintptr_t) handler.get() == mediaHandlerId);
265 });
266
267 if (handlerIt != callMediaHandlers_.end()) {
268 if (toggle) {
269 notifyAVSubject((*handlerIt), subject.first, subject.second);
270 if (isAttached((*handlerIt)))
271 handlers[mediaHandlerId] = true;
272 } else {
273 (*handlerIt)->detach();
274 handlers[mediaHandlerId] = false;
275 }
276 if (subject.first.type == StreamType::video && isVideoType((*handlerIt)))
277 applyRestart = true;
278 }
279 }
280#ifndef __ANDROID__
281#ifdef ENABLE_VIDEO
282 if (applyRestart) {
283 auto call = Manager::instance().callFactory.getCall<SIPCall>(callId);
284 if (call && !call->isConferenceParticipant()) {
285 for (auto const& videoRtp: call->getRtpSessionList(MediaType::MEDIA_VIDEO))
286 videoRtp->restartSender();
287 }
288 }
289#endif
290#endif
291}
292} // 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:676
CallFactory callFactory
Definition manager.h:794
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:218
std::unique_ptr< CallMediaHandler > CallMediaHandlerPtr
void emitSignal(Args... args)
Definition ring_signal.h:64
std::weak_ptr< Observable< AVFrame * > > AVSubjectSPtr
@ MEDIA_VIDEO
Definition media_codec.h:48
SIPCall are SIP implementation of a normal Call.
Contains information about an AV subject.
Definition streamdata.h:29
const std::string source
Definition streamdata.h:55
const bool direction
Definition streamdata.h:51
const std::string id
Definition streamdata.h:49
const StreamType type
Definition streamdata.h:53