Line data Source code
1 : /*
2 : * Copyright (C) 2004-2024 Savoir-faire Linux Inc.
3 : *
4 : * Author: Pierre-Luc Beaudoin <pierre-luc.beaudoin@savoirfairelinux.com>
5 : * Author: Alexandre Bourget <alexandre.bourget@savoirfairelinux.com>
6 : * Author: Guillaume Roguez <Guillaume.Roguez@savoirfairelinux.com>
7 : *
8 : * This program is free software; you can redistribute it and/or modify
9 : * it under the terms of the GNU General Public License as published by
10 : * the Free Software Foundation; either version 3 of the License, or
11 : * (at your option) any later version.
12 : *
13 : * This program is distributed in the hope that it will be useful,
14 : * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 : * GNU General Public License for more details.
17 : *
18 : * You should have received a copy of the GNU General Public License
19 : * along with this program; if not, write to the Free Software
20 : * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
21 : */
22 : #include <vector>
23 : #include <cstring>
24 :
25 : #include "callmanager_interface.h"
26 : #include "call_factory.h"
27 : #include "client/ring_signal.h"
28 :
29 : #include "sip/siptransport.h"
30 : #include "sip/sipvoiplink.h"
31 : #include "sip/sipcall.h"
32 : #include "audio/audiolayer.h"
33 : #include "media/media_attribute.h"
34 : #include "string_utils.h"
35 :
36 : #include "logger.h"
37 : #include "manager.h"
38 : #include "jamidht/jamiaccount.h"
39 :
40 : namespace libjami {
41 :
42 : void
43 0 : registerCallHandlers(const std::map<std::string, std::shared_ptr<CallbackWrapperBase>>& handlers)
44 : {
45 0 : registerSignalHandlers(handlers);
46 0 : }
47 :
48 : std::string
49 0 : placeCall(const std::string& accountId, const std::string& to)
50 : {
51 : // TODO. Remove ASAP.
52 0 : JAMI_WARN("This API is deprecated, use placeCallWithMedia() instead");
53 0 : return placeCallWithMedia(accountId, to, {});
54 : }
55 :
56 : std::string
57 117 : placeCallWithMedia(const std::string& accountId,
58 : const std::string& to,
59 : const std::vector<libjami::MediaMap>& mediaList)
60 : {
61 : // Check if a destination number is available
62 117 : if (to.empty()) {
63 0 : JAMI_DBG("No number entered - Call aborted");
64 0 : return {};
65 : } else {
66 117 : return jami::Manager::instance().outgoingCall(accountId, to, mediaList);
67 : }
68 : }
69 :
70 : bool
71 18 : requestMediaChange(const std::string& accountId,
72 : const std::string& callId,
73 : const std::vector<libjami::MediaMap>& mediaList)
74 : {
75 18 : if (auto account = jami::Manager::instance().getAccount(accountId)) {
76 18 : if (auto call = account->getCall(callId)) {
77 15 : return call->requestMediaChange(mediaList);
78 3 : } else if (auto conf = account->getConference(callId)) {
79 3 : return conf->requestMediaChange(mediaList);
80 21 : }
81 18 : }
82 0 : return false;
83 : }
84 :
85 : bool
86 1 : refuse(const std::string& accountId, const std::string& callId)
87 : {
88 1 : return jami::Manager::instance().refuseCall(accountId, callId);
89 : }
90 :
91 : bool
92 0 : accept(const std::string& accountId, const std::string& callId)
93 : {
94 0 : return jami::Manager::instance().answerCall(accountId, callId);
95 : }
96 :
97 : bool
98 20 : acceptWithMedia(const std::string& accountId,
99 : const std::string& callId,
100 : const std::vector<libjami::MediaMap>& mediaList)
101 : {
102 20 : return jami::Manager::instance().answerCall(accountId, callId, mediaList);
103 : }
104 :
105 : bool
106 3 : answerMediaChangeRequest(const std::string& accountId,
107 : const std::string& callId,
108 : const std::vector<libjami::MediaMap>& mediaList)
109 : {
110 3 : if (auto account = jami::Manager::instance().getAccount(accountId))
111 3 : if (auto call = account->getCall(callId)) {
112 : try {
113 3 : call->answerMediaChangeRequest(mediaList);
114 3 : return true;
115 0 : } catch (const std::runtime_error& e) {
116 0 : JAMI_ERR("%s", e.what());
117 0 : }
118 6 : }
119 0 : return false;
120 : }
121 :
122 : bool
123 16 : hangUp(const std::string& accountId, const std::string& callId)
124 : {
125 16 : return jami::Manager::instance().hangupCall(accountId, callId);
126 : }
127 :
128 : bool
129 0 : hangUpConference(const std::string& accountId, const std::string& confId)
130 : {
131 0 : return jami::Manager::instance().hangupConference(accountId, confId);
132 : }
133 :
134 : bool
135 3 : hold(const std::string& accountId, const std::string& callId)
136 : {
137 3 : return jami::Manager::instance().onHoldCall(accountId, callId);
138 : }
139 :
140 : bool
141 3 : unhold(const std::string& accountId, const std::string& callId)
142 : {
143 3 : return jami::Manager::instance().offHoldCall(accountId, callId);
144 : }
145 :
146 : bool
147 0 : muteLocalMedia(const std::string& accountId,
148 : const std::string& callId,
149 : const std::string& mediaType,
150 : bool mute)
151 : {
152 0 : if (auto account = jami::Manager::instance().getAccount(accountId)) {
153 0 : if (auto call = account->getCall(callId)) {
154 0 : JAMI_DBG("Muting [%s] for call %s", mediaType.c_str(), callId.c_str());
155 0 : call->muteMedia(mediaType, mute);
156 0 : return true;
157 0 : } else if (auto conf = account->getConference(callId)) {
158 0 : JAMI_DBG("Muting local host [%s] for conference %s", mediaType.c_str(), callId.c_str());
159 0 : conf->muteLocalHost(mute, mediaType);
160 0 : return true;
161 : } else {
162 0 : JAMI_WARN("ID %s doesn't match any call or conference", callId.c_str());
163 0 : }
164 0 : }
165 0 : return false;
166 : }
167 :
168 : bool
169 2 : transfer(const std::string& accountId, const std::string& callId, const std::string& to)
170 : {
171 2 : return jami::Manager::instance().transferCall(accountId, callId, to);
172 : }
173 :
174 : bool
175 0 : attendedTransfer(const std::string& accountId,
176 : const std::string& transferID,
177 : const std::string& targetID)
178 : {
179 0 : if (auto account = jami::Manager::instance().getAccount(accountId))
180 0 : if (auto call = account->getCall(transferID))
181 0 : return call->attendedTransfer(targetID);
182 0 : return false;
183 : }
184 :
185 : bool
186 0 : joinParticipant(const std::string& accountId,
187 : const std::string& sel_callId,
188 : const std::string& account2Id,
189 : const std::string& drag_callId)
190 : {
191 0 : return jami::Manager::instance().joinParticipant(accountId, sel_callId, account2Id, drag_callId);
192 : }
193 :
194 : void
195 0 : createConfFromParticipantList(const std::string& accountId,
196 : const std::vector<std::string>& participants)
197 : {
198 0 : jami::Manager::instance().createConfFromParticipantList(accountId, participants);
199 0 : }
200 :
201 : void
202 0 : setConferenceLayout(const std::string& accountId, const std::string& confId, uint32_t layout)
203 : {
204 0 : if (const auto account = jami::Manager::instance().getAccount(accountId)) {
205 0 : if (auto conf = account->getConference(confId)) {
206 0 : conf->setLayout(layout);
207 0 : } else if (auto call = account->getCall(confId)) {
208 0 : Json::Value root;
209 0 : root["layout"] = layout;
210 0 : call->sendConfOrder(root);
211 0 : }
212 0 : }
213 0 : }
214 :
215 : bool
216 0 : isConferenceParticipant(const std::string& accountId, const std::string& callId)
217 : {
218 0 : if (auto account = jami::Manager::instance().getAccount(accountId))
219 0 : if (auto call = account->getCall(callId))
220 0 : return call->isConferenceParticipant();
221 0 : return false;
222 : }
223 :
224 : void
225 0 : startSmartInfo(uint32_t refreshTimeMs)
226 : {
227 0 : JAMI_WARNING("startSmartInfo is deprecated and does nothing.");
228 0 : }
229 :
230 : void
231 0 : stopSmartInfo()
232 : {
233 0 : JAMI_WARNING("stopSmartInfo is deprecated and does nothing.");
234 0 : }
235 :
236 : bool
237 0 : addParticipant(const std::string& accountId,
238 : const std::string& callId,
239 : const std::string& account2Id,
240 : const std::string& confId)
241 : {
242 0 : return jami::Manager::instance().addParticipant(accountId, callId, account2Id, confId);
243 : }
244 :
245 : bool
246 0 : addMainParticipant(const std::string& accountId, const std::string& confId)
247 : {
248 0 : return jami::Manager::instance().addMainParticipant(accountId, confId);
249 : }
250 :
251 : bool
252 0 : detachLocalParticipant()
253 : {
254 0 : return jami::Manager::instance().detachLocalParticipant();
255 : }
256 :
257 : bool
258 0 : detachParticipant(const std::string&, const std::string& callId)
259 : {
260 0 : return jami::Manager::instance().detachParticipant(callId);
261 : }
262 :
263 : bool
264 0 : joinConference(const std::string& accountId,
265 : const std::string& sel_confId,
266 : const std::string& account2Id,
267 : const std::string& drag_confId)
268 : {
269 0 : return jami::Manager::instance().joinConference(accountId, sel_confId, account2Id, drag_confId);
270 : }
271 :
272 : bool
273 0 : holdConference(const std::string& accountId, const std::string& confId)
274 : {
275 0 : return jami::Manager::instance().holdConference(accountId, confId);
276 : }
277 :
278 : bool
279 0 : unholdConference(const std::string& accountId, const std::string& confId)
280 : {
281 0 : return jami::Manager::instance().unHoldConference(accountId, confId);
282 : }
283 :
284 : std::map<std::string, std::string>
285 0 : getConferenceDetails(const std::string& accountId, const std::string& confId)
286 : {
287 0 : if (const auto account = jami::Manager::instance().getAccount(accountId))
288 0 : if (auto conf = account->getConference(confId))
289 : return {{"ID", confId},
290 0 : {"STATE", conf->getStateStr()},
291 : #ifdef ENABLE_VIDEO
292 0 : {"VIDEO_SOURCE", conf->getVideoInput()},
293 : #endif
294 0 : {"RECORDING", conf->isRecording() ? jami::TRUE_STR : jami::FALSE_STR}};
295 0 : return {};
296 : }
297 :
298 : std::vector<std::map<std::string, std::string>>
299 0 : currentMediaList(const std::string& accountId, const std::string& callId)
300 : {
301 0 : if (const auto account = jami::Manager::instance().getAccount(accountId)) {
302 0 : if (auto call = account->getCall(callId)) {
303 0 : return call->currentMediaList();
304 0 : } else if (auto conf = account->getConference(callId)) {
305 0 : return conf->currentMediaList();
306 0 : }
307 0 : }
308 0 : JAMI_WARN("Call not found %s", callId.c_str());
309 0 : return {};
310 : }
311 :
312 : std::vector<std::string>
313 4 : getConferenceList(const std::string& accountId)
314 : {
315 4 : if (const auto account = jami::Manager::instance().getAccount(accountId))
316 4 : return account->getConferenceList();
317 0 : return {};
318 : }
319 :
320 : std::vector<std::string>
321 4 : getParticipantList(const std::string& accountId, const std::string& confId)
322 : {
323 4 : if (const auto account = jami::Manager::instance().getAccount(accountId))
324 4 : if (auto conf = account->getConference(confId)) {
325 4 : const auto& participants(conf->getParticipantList());
326 4 : return {participants.begin(), participants.end()};
327 12 : }
328 0 : return {};
329 : }
330 :
331 : std::string
332 0 : getConferenceId(const std::string& accountId, const std::string& callId)
333 : {
334 0 : if (const auto account = jami::Manager::instance().getAccount(accountId))
335 0 : if (auto call = account->getCall(callId))
336 0 : if (auto conf = call->getConference())
337 0 : return conf->getConfId();
338 0 : return {};
339 : }
340 :
341 : bool
342 0 : startRecordedFilePlayback(const std::string& filepath)
343 : {
344 0 : return jami::Manager::instance().startRecordedFilePlayback(filepath);
345 : }
346 :
347 : void
348 0 : stopRecordedFilePlayback()
349 : {
350 0 : jami::Manager::instance().stopRecordedFilePlayback();
351 0 : }
352 :
353 : bool
354 11 : toggleRecording(const std::string& accountId, const std::string& callId)
355 : {
356 11 : return jami::Manager::instance().toggleRecordingCall(accountId, callId);
357 : }
358 :
359 : void
360 0 : setRecording(const std::string& accountId, const std::string& callId)
361 : {
362 0 : toggleRecording(accountId, callId);
363 0 : }
364 :
365 : void
366 0 : recordPlaybackSeek(double value)
367 : {
368 0 : jami::Manager::instance().recordingPlaybackSeek(value);
369 0 : }
370 :
371 : bool
372 10 : getIsRecording(const std::string& accountId, const std::string& callId)
373 : {
374 10 : if (const auto account = jami::Manager::instance().getAccount(accountId)) {
375 10 : if (auto call = account->getCall(callId)) {
376 10 : return call->isRecording();
377 0 : } else if (auto conf = account->getConference(callId)) {
378 0 : return conf->isRecording();
379 10 : }
380 10 : }
381 0 : return false;
382 : }
383 :
384 : std::map<std::string, std::string>
385 395 : getCallDetails(const std::string& accountId, const std::string& callId)
386 : {
387 395 : if (const auto account = jami::Manager::instance().getAccount(accountId))
388 395 : if (auto call = account->getCall(callId))
389 790 : return call->getDetails();
390 0 : return {};
391 : }
392 :
393 : std::vector<std::string>
394 0 : getCallList()
395 : {
396 0 : return jami::Manager::instance().getCallList();
397 : }
398 :
399 : std::vector<std::string>
400 0 : getCallList(const std::string& accountId)
401 : {
402 0 : if (accountId.empty())
403 0 : return jami::Manager::instance().getCallList();
404 0 : else if (const auto account = jami::Manager::instance().getAccount(accountId))
405 0 : return account->getCallList();
406 0 : JAMI_WARN("Unknown account: %s", accountId.c_str());
407 0 : return {};
408 : }
409 :
410 : std::vector<std::map<std::string, std::string>>
411 0 : getConferenceInfos(const std::string& accountId, const std::string& confId)
412 : {
413 0 : if (const auto account = jami::Manager::instance().getAccount(accountId)) {
414 0 : if (auto conf = account->getConference(confId))
415 0 : return conf->getConferenceInfos();
416 0 : else if (auto call = account->getCall(confId))
417 0 : return call->getConferenceInfos();
418 0 : }
419 0 : return {};
420 : }
421 :
422 : void
423 0 : playDTMF(const std::string& key)
424 : {
425 0 : auto code = key.data()[0];
426 0 : jami::Manager::instance().playDtmf(code);
427 :
428 0 : if (auto current_call = jami::Manager::instance().getCurrentCall())
429 0 : current_call->carryingDTMFdigits(code);
430 0 : }
431 :
432 : void
433 0 : startTone(int32_t start, int32_t type)
434 : {
435 0 : if (start) {
436 0 : if (type == 0)
437 0 : jami::Manager::instance().playTone();
438 : else
439 0 : jami::Manager::instance().playToneWithMessage();
440 : } else
441 0 : jami::Manager::instance().stopTone();
442 0 : }
443 :
444 : bool
445 1 : switchInput(const std::string& accountId, const std::string& callId, const std::string& resource)
446 : {
447 1 : if (const auto account = jami::Manager::instance().getAccount(accountId)) {
448 0 : if (auto conf = account->getConference(callId)) {
449 0 : conf->switchInput(resource);
450 0 : return true;
451 0 : } else if (auto call = account->getCall(callId)) {
452 0 : call->switchInput(resource);
453 0 : return true;
454 0 : }
455 1 : }
456 1 : return false;
457 : }
458 :
459 : bool
460 0 : switchSecondaryInput(const std::string& accountId,
461 : const std::string& confId,
462 : const std::string& resource)
463 : {
464 0 : JAMI_ERR("Use requestMediaChange");
465 0 : return false;
466 : }
467 :
468 : void
469 0 : sendTextMessage(const std::string& accountId,
470 : const std::string& callId,
471 : const std::map<std::string, std::string>& messages,
472 : const std::string& from,
473 : bool isMixed)
474 : {
475 0 : jami::runOnMainThread([accountId, callId, messages, from, isMixed] {
476 0 : jami::Manager::instance().sendCallTextMessage(accountId, callId, messages, from, isMixed);
477 0 : });
478 0 : }
479 :
480 : void
481 1 : setModerator(const std::string& accountId,
482 : const std::string& confId,
483 : const std::string& peerId,
484 : const bool& state)
485 : {
486 1 : if (const auto account = jami::Manager::instance().getAccount(accountId)) {
487 1 : if (auto conf = account->getConference(confId)) {
488 1 : conf->setModerator(peerId, state);
489 : } else {
490 0 : JAMI_WARN("Fail to change moderator %s, conference %s not found",
491 : peerId.c_str(),
492 : confId.c_str());
493 1 : }
494 1 : }
495 1 : }
496 :
497 : void
498 0 : muteParticipant(const std::string& accountId,
499 : const std::string& confId,
500 : const std::string& peerId,
501 : const bool& state)
502 : {
503 0 : JAMI_ERR() << "muteParticipant is deprecated, please use muteStream";
504 0 : if (const auto account = jami::Manager::instance().getAccount(accountId)) {
505 0 : if (auto conf = account->getConference(confId)) {
506 0 : conf->muteParticipant(peerId, state);
507 0 : } else if (auto call = account->getCall(confId)) {
508 0 : Json::Value root;
509 0 : root["muteParticipant"] = peerId;
510 0 : root["muteState"] = state ? jami::TRUE_STR : jami::FALSE_STR;
511 0 : call->sendConfOrder(root);
512 0 : }
513 0 : }
514 0 : }
515 :
516 : void
517 4 : muteStream(const std::string& accountId,
518 : const std::string& confId,
519 : const std::string& accountUri,
520 : const std::string& deviceId,
521 : const std::string& streamId,
522 : const bool& state)
523 : {
524 4 : if (const auto account = jami::Manager::instance().getAccount(accountId)) {
525 4 : if (auto conf = account->getConference(confId)) {
526 3 : conf->muteStream(accountUri, deviceId, streamId, state);
527 1 : } else if (auto call = account->getCall(confId)) {
528 0 : if (call->conferenceProtocolVersion() == 1) {
529 0 : Json::Value sinkVal;
530 0 : sinkVal["muteAudio"] = state;
531 0 : Json::Value mediasObj;
532 0 : mediasObj[streamId] = sinkVal;
533 0 : Json::Value deviceVal;
534 0 : deviceVal["medias"] = mediasObj;
535 0 : Json::Value deviceObj;
536 0 : deviceObj[deviceId] = deviceVal;
537 0 : Json::Value accountVal;
538 0 : deviceVal["devices"] = deviceObj;
539 0 : Json::Value root;
540 0 : root[accountUri] = deviceVal;
541 0 : root["version"] = 1;
542 0 : call->sendConfOrder(root);
543 0 : } else if (call->conferenceProtocolVersion() == 0) {
544 0 : Json::Value root;
545 0 : root["muteParticipant"] = accountUri;
546 0 : root["muteState"] = state ? jami::TRUE_STR : jami::FALSE_STR;
547 0 : call->sendConfOrder(root);
548 0 : }
549 5 : }
550 4 : }
551 4 : }
552 :
553 : void
554 0 : setActiveParticipant(const std::string& accountId,
555 : const std::string& confId,
556 : const std::string& participant)
557 : {
558 0 : JAMI_ERR() << "setActiveParticipant is deprecated, please use setActiveStream";
559 0 : if (const auto account = jami::Manager::instance().getAccount(accountId)) {
560 0 : if (auto conf = account->getConference(confId)) {
561 0 : conf->setActiveParticipant(participant);
562 0 : } else if (auto call = account->getCall(confId)) {
563 0 : Json::Value root;
564 0 : root["activeParticipant"] = participant;
565 0 : call->sendConfOrder(root);
566 0 : }
567 0 : }
568 0 : }
569 :
570 : void
571 2 : setActiveStream(const std::string& accountId,
572 : const std::string& confId,
573 : const std::string& accountUri,
574 : const std::string& deviceId,
575 : const std::string& streamId,
576 : const bool& state)
577 : {
578 2 : if (const auto account = jami::Manager::instance().getAccount<jami::JamiAccount>(accountId)) {
579 2 : if (auto conf = account->getConference(confId)) {
580 1 : conf->setActiveStream(streamId, state);
581 2 : } else if (auto call = std::static_pointer_cast<jami::SIPCall>(account->getCall(confId))) {
582 0 : call->setActiveMediaStream(accountUri, deviceId, streamId, state);
583 3 : }
584 2 : }
585 2 : }
586 :
587 : void
588 2 : hangupParticipant(const std::string& accountId,
589 : const std::string& confId,
590 : const std::string& accountUri,
591 : const std::string& deviceId)
592 : {
593 2 : if (const auto account = jami::Manager::instance().getAccount(accountId)) {
594 2 : if (auto conf = account->getConference(confId)) {
595 1 : conf->hangupParticipant(accountUri, deviceId);
596 2 : } else if (auto call = std::static_pointer_cast<jami::SIPCall>(account->getCall(confId))) {
597 0 : if (call->conferenceProtocolVersion() == 1) {
598 0 : Json::Value deviceVal;
599 0 : deviceVal["hangup"] = jami::TRUE_STR;
600 0 : Json::Value deviceObj;
601 0 : deviceObj[deviceId] = deviceVal;
602 0 : Json::Value accountVal;
603 0 : deviceVal["devices"] = deviceObj;
604 0 : Json::Value root;
605 0 : root[accountUri] = deviceVal;
606 0 : root["version"] = 1;
607 0 : call->sendConfOrder(root);
608 0 : } else if (call->conferenceProtocolVersion() == 0) {
609 0 : Json::Value root;
610 0 : root["hangupParticipant"] = accountUri;
611 0 : call->sendConfOrder(root);
612 0 : }
613 3 : }
614 2 : }
615 2 : }
616 :
617 : void
618 0 : raiseParticipantHand(const std::string& accountId,
619 : const std::string& confId,
620 : const std::string& peerId,
621 : const bool& state)
622 : {
623 0 : JAMI_ERR() << "raiseParticipantHand is deprecated, please use raiseHand";
624 0 : if (const auto account = jami::Manager::instance().getAccount(accountId)) {
625 0 : if (auto conf = account->getConference(confId)) {
626 0 : if (auto call = std::static_pointer_cast<jami::SIPCall>(
627 0 : conf->getCallFromPeerID(peerId))) {
628 0 : if (auto* transport = call->getTransport())
629 0 : conf->setHandRaised(std::string(transport->deviceId()), state);
630 0 : }
631 0 : } else if (auto call = account->getCall(confId)) {
632 0 : Json::Value root;
633 0 : root["handRaised"] = peerId;
634 0 : root["handState"] = state ? jami::TRUE_STR : jami::FALSE_STR;
635 0 : call->sendConfOrder(root);
636 0 : }
637 0 : }
638 0 : }
639 :
640 : void
641 9 : raiseHand(const std::string& accountId,
642 : const std::string& confId,
643 : const std::string& accountUri,
644 : const std::string& deviceId,
645 : const bool& state)
646 : {
647 9 : if (const auto account = jami::Manager::instance().getAccount<jami::JamiAccount>(accountId)) {
648 9 : if (auto conf = account->getConference(confId)) {
649 2 : auto device = deviceId;
650 2 : if (device.empty())
651 0 : device = std::string(account->currentDeviceId());
652 2 : conf->setHandRaised(device, state);
653 16 : } else if (auto call = std::static_pointer_cast<jami::SIPCall>(account->getCall(confId))) {
654 6 : if (call->conferenceProtocolVersion() == 1) {
655 6 : Json::Value deviceVal;
656 6 : deviceVal["raiseHand"] = state;
657 6 : Json::Value deviceObj;
658 6 : std::string device = deviceId.empty() ? std::string(account->currentDeviceId())
659 6 : : deviceId;
660 6 : deviceObj[device] = deviceVal;
661 6 : Json::Value accountVal;
662 6 : deviceVal["devices"] = deviceObj;
663 6 : Json::Value root;
664 6 : std::string uri = accountUri.empty() ? account->getUsername() : accountUri;
665 6 : root[uri] = deviceVal;
666 6 : root["version"] = 1;
667 6 : call->sendConfOrder(root);
668 6 : } else if (call->conferenceProtocolVersion() == 0) {
669 0 : Json::Value root;
670 0 : root["handRaised"] = account->getUsername();
671 0 : root["handState"] = state ? jami::TRUE_STR : jami::FALSE_STR;
672 0 : call->sendConfOrder(root);
673 0 : }
674 16 : }
675 9 : }
676 9 : }
677 :
678 : } // namespace libjami
|