44#include <opendht/thread_pool.h>
46using namespace std::literals;
57 JAMI_LOG(
"[conf:{}] Creating conference", id_);
58 duration_start_ = clock::now();
63 registerProtocolHandlers();
70Conference::setupVideoMixer()
72 videoMixer_ = std::make_shared<video::VideoMixer>(id_);
73 videoMixer_->setOnSourcesUpdated([
this](std::vector<video::SourceInfo>&& infos) {
75 if (
auto shared = w.lock())
76 shared->onVideoSourcesUpdated(std::move(infos));
82#if defined(__APPLE__) && TARGET_OS_MAC
85 videoMixer_->setParameters(
static_cast<int>(
conf_res[0]),
static_cast<int>(
conf_res[1]));
88 JAMI_ERROR(
"[conf:{}] Conference resolution is invalid", id_);
93Conference::onVideoSourcesUpdated(
const std::vector<video::SourceInfo>& infos)
95 auto acc = std::dynamic_pointer_cast<JamiAccount>(account_.lock());
101 std::lock_guard lock(confInfoMutex_);
108 for (
const auto& info : infos) {
109 if (!info.callId.empty()) {
123 pi.videoMuted =
true;
125 pi.isModerator =
true;
133Conference::createParticipantInfoFromRemoteSource(
const video::SourceInfo& info)
142 std::string callId = info.callId;
143 if (
auto call = std::dynamic_pointer_cast<SIPCall>(getCall(callId))) {
147 if (
auto* transport = call->getTransport())
155 participant.voiceActivity = isVoiceActive(info.streamId);
165Conference::createParticipantInfoFromLocalSource(
const video::SourceInfo& info,
166 const std::shared_ptr<JamiAccount>& acc,
176 auto streamInfo = videoMixer_->streamInfo(info.source);
177 std::string
streamId = streamInfo.streamId;
185 participant.audioModeratorMuted = isMuted(streamId);
188 if (
auto call = std::dynamic_pointer_cast<SIPCall>(getCall(streamInfo.callId))) {
192 if (
auto* transport = call->getTransport())
213 participant.voiceActivity = isVoiceActive(streamId);
221Conference::registerProtocolHandlers()
240 if (
auto* transport = call->getTransport())
249 JAMI_LOG(
"[conf:{}] Destroying conference", id_);
254 foreachCall([&](
const auto& call) {
255 call->exitConference();
257 call->resetConfInfo();
266 if (
not call->isRecording()) {
267 JAMI_DEBUG(
"[call:{}] Starting recording (conference was recorded)", call->getCallId());
268 call->toggleRecording();
272 if (call->isPeerRecording())
273 call->peerRecording(
true);
276 auto&
sink = videoMixer_->getSink();
278 sink->detach(
it->second.get());
293 shutdownCb_(
static_cast<int>(
getDuration().count()));
314Conference::initSourcesForHost()
316 hostSources_.clear();
353std::vector<std::map<std::string, std::string>>
361Conference::createConfAVStreams()
365 auto audioMap = [](
const std::shared_ptr<jami::MediaFrame>&
m) ->
AVFrame* {
366 return std::static_pointer_cast<AudioFrame>(
m)->pointer();
420 for (
auto& source : hostSources_)
421 if (source.type_ == type) {
422 source.muted_ =
muted;
442 for (
const auto& source : hostSources_) {
443 if (source.type_ == type) {
445 JAMI_WARNING(
"The host source for {} is not set. The mute state is meaningless",
446 source.mediaTypeToString(source.type_));
449 return source.muted_;
457Conference::takeOverMediaSourceControl(
const std::string& callId)
459 auto call = getCall(callId);
461 JAMI_ERROR(
"[conf:{}] No call matches participant {}", id_, callId);
465 auto account = call->getAccount().lock();
467 JAMI_ERROR(
"[conf:{}] No account detected for call {}", id_, callId);
471 auto mediaList = call->getMediaAttributeList();
486 JAMI_DEBUG(
"[conf:{}] Call {} does not have an active {} media source",
497 if (subCalls_.size() == 1) {
512 JAMI_DEBUG(
"[conf:{}] Taking over audio control from call {} - current state: {}",
515 muted ?
"muted" :
"unmuted");
519 JAMI_DEBUG(
"[conf:{}] Taking over video control from call {} - current state: {}",
522 muted ?
"muted" :
"unmuted");
532 JAMI_ERROR(
"[conf {}] Request media change can be performed only in attached mode",
getConfId());
556 if (!
media.enabled_ ||
media.sourceUri_.empty())
563 if (
pos == std::string::npos)
572 mediaPlayerId_ =
media.sourceUri_;
589 auto oldIdx = std::find_if(hostSources_.begin(), hostSources_.end(), [&](
const auto&
oldAttr) {
590 return oldAttr.label_ == mediaAttr.label_;
599 srcUri =
vm->videoDeviceMonitor.getMRLForDefaultDevice();
611 if (
oldIdx != hostSources_.end()) {
649 JAMI_DEBUG(
"[conf:{}] Host added video, negotiating video with all subcalls",
getConfId());
663 JAMI_DEBUG(
"[conf:{}] Answering media change request from call {}",
getConfId(), call->getCallId());
676 "[conf:{}] [call:{}] remoteHasVideo={}, removing from audio-only sources BEFORE media negotiation completes",
681 auto callId = call->getCallId();
683 JAMI_WARNING(
"[conf:{}] [call:{}] Removing audio-only source '{}' - participant may briefly disappear from "
684 "layout until video is attached",
722 unbindSubCallAudio(call->getCallId());
723 bindSubCallAudio(call->getCallId());
730 JAMI_DEBUG(
"[conf:{}] [call:{}] Participant added video, negotiating video with other subcalls",
741 JAMI_DEBUG(
"[conf:{}] Adding call {}", id_, callId);
746 std::lock_guard
lk(subcallsMtx_);
747 if (!subCalls_.insert(callId).second)
751 if (
auto call = std::dynamic_pointer_cast<SIPCall>(getCall(callId))) {
753 if (call->isPeerMuted())
754 participantsMuted_.emplace(call->getCallId());
759 takeOverMediaSourceControl(callId);
760 auto w = call->getAccount();
764 for (
const auto&
mod :
account->getDefaultModerators()) {
765 moderators_.emplace(
mod);
769 if (
account->isLocalModeratorsEnabled() &&
not localModAdded_) {
772 moderators_.emplace(
account->getUsername());
774 localModAdded_ =
true;
778 if (
account->isAllModerators())
779 moderators_.emplace(getRemoteId(call));
784 auto mediaList = call->getMediaAttributeList();
785 if (call->peerUri().find(
"swarm:") != 0) {
790 videoMixer_->addAudioOnlySource(call->getCallId(),
797 if (call->isRecording()) {
798 JAMI_DEBUG(
"[call:{}] Stopping recording", call->getCallId());
799 call->toggleRecording();
805 bindSubCallAudio(callId);
808 JAMI_ERROR(
"[conf:{}] No call associated with participant {}", id_, callId);
817 JAMI_DEBUG(
"[conf:{}] Removing call {}", id_, callId);
819 std::lock_guard
lk(subcallsMtx_);
820 if (!subCalls_.erase(callId))
824 clearParticipantData(callId);
826 if (
auto call = std::dynamic_pointer_cast<SIPCall>(getCall(callId))) {
829 for (
auto const&
rtpSession : call->getRtpSessionList()) {
831 videoMixer_->removeAudioOnlySource(callId,
rtpSession->streamId());
832 if (videoMixer_->verifyActive(
rtpSession->streamId()))
833 videoMixer_->resetActiveStream();
837 unbindSubCallAudio(callId);
838 call->exitConference();
839 if (call->isPeerRecording())
840 call->peerRecording(
false);
846Conference::negotiateVideoWithSubcalls(
const std::string&
excludeCallId)
849 JAMI_DEBUG(
"[conf:{}] Video is disabled in account, skipping subcall video negotiation", id_);
853 JAMI_DEBUG(
"[conf:{}] Negotiating video with subcalls (excluding: {})",
862 auto call = std::dynamic_pointer_cast<SIPCall>(getCall(callId));
867 auto mediaList = call->getMediaAttributeList();
869 return media.type_ == MediaType::MEDIA_VIDEO;
873 JAMI_DEBUG(
"[conf:{}] [call:{}] Call does not have video, triggering renegotiation to add video",
899 if (!
videoIt->sourceUri_.empty()) {
906 JAMI_DEBUG(
"[conf:{}] [call:{}] Unmuting existing video stream for renegotiation", id_, callId);
936 videoMixer_->resetActiveStream();
947 videoMixer_->setActiveStream(streamId);
949 videoMixer_->resetActiveStream();
958 JAMI_ERROR(
"[conf:{}] Unknown layout {}", id_, layout);
964 std::lock_guard
lk(confInfoMutex_);
965 confInfo_.
layout = layout;
967 videoMixer_->setVideoLayout(
static_cast<video::Layout>(layout));
971std::vector<std::map<std::string, std::string>>
974 std::vector<std::map<std::string, std::string>> infos;
975 infos.reserve(size());
976 for (
const auto& info : *
this)
977 infos.emplace_back(info.toMap());
984 Json::Value
val = {};
985 for (
const auto& info : *
this) {
986 val[
"p"].append(info.toJson());
996Conference::sendConferenceInfos()
999 foreachCall([&](
const auto& call) {
1002 auto w = call->getAccount();
1007 dht::ThreadPool::io().run(
1008 [call,
confInfo = getConfInfoHostUri(
account->getUsername() +
"@ring.dht", call->getPeerNumber())] {
1009 call->sendConfInfo(confInfo.toString());
1013 auto confInfo = getConfInfoHostUri(
"",
"");
1024Conference::createSinks(
const ConfInfo& infos)
1026 std::lock_guard
lk(sinksMtx_);
1029 auto&
sink = videoMixer_->getSink();
1032 {std::static_pointer_cast<video::VideoFrameActiveWriter>(
sink)},
1046 JAMI_DEBUG(
"[conf:{}] Empty media list, initializing default sources", id_);
1047 initSourcesForHost();
1052 for (
const auto& source : hostSources_) {
1067 JAMI_WARNING(
"[conf:{}] Invalid conference state in attach participant: current \"{}\" - expected \"{}\"",
1077 JAMI_LOG(
"[conf:{}] Detaching host", id_);
1086 videoMixer_->stopInputs();
1089 JAMI_WARNING(
"[conf:{}] Invalid conference state in detach participant: current \"{}\" - expected \"{}\"",
1097 initSourcesForHost();
1103 std::lock_guard
lk(subcallsMtx_);
1117 foreachCall([&](
const auto& call) { call->updateRecState(
newState); });
1128 return account->getAccountID();
1136 JAMI_DEBUG(
"[conf:{}] Switching video input to {}", id_, input);
1141 for (
auto& source : hostSources_) {
1145 source.sourceUri_ = input;
1157 if (
auto mixer = videoMixer_) {
1158 mixer->switchInputs({input});
1174 if (
auto shared = account_.lock())
1175 return shared->isVideoEnabled();
1180std::shared_ptr<video::VideoMixer>
1181Conference::getVideoMixer()
1187Conference::getVideoInput()
const
1189 for (
const auto& source : hostSources_) {
1191 return source.sourceUri_;
1198Conference::initRecorder(std::shared_ptr<MediaRecorder>&
rec)
1203 if (
auto*
ob =
rec->addStream(videoMixer_->getStream(
"v:mixer"))) {
1204 videoMixer_->attach(
ob);
1219 if (
auto*
ob =
rec->addStream(audioMixer_->getInfo(
"a:mixer"))) {
1220 audioMixer_->attach(
ob);
1225Conference::deinitRecorder(std::shared_ptr<MediaRecorder>&
rec)
1230 if (
auto*
ob =
rec->getStream(
"v:mixer")) {
1231 videoMixer_->detach(
ob);
1237 if (
auto*
ob =
rec->getStream(
"a:mixer"))
1238 audioMixer_->detach(
ob);
1239 audioMixer_.reset();
1241 ghostRingBuffer_.reset();
1248 if (
auto call = getCall(callId)) {
1249 const auto& peerId = getRemoteId(call);
1252 JAMI_WARNING(
"[conf:{}] Unable to parse conference order from {}", id_, peerId);
1261std::shared_ptr<Call>
1262Conference::getCall(
const std::string& callId)
1268Conference::isModerator(std::string_view uri)
const
1270 return moderators_.find(uri) != moderators_.end()
or isHost(uri);
1274Conference::isHandRaised(std::string_view deviceId)
const
1276 return isHostDevice(deviceId) ? handsRaised_.find(
"host"sv) != handsRaised_.end()
1277 : handsRaised_.find(deviceId) != handsRaised_.end();
1283 if (isHostDevice(deviceId)) {
1286 handsRaised_.emplace(
"host"sv);
1287 updateHandsRaised();
1289 handsRaised_.erase(
"host");
1290 updateHandsRaised();
1294 if (
auto call = std::dynamic_pointer_cast<SIPCall>(getCall(p))) {
1297 if (
auto* transport = call->getTransport())
1301 handsRaised_.emplace(deviceId);
1302 updateHandsRaised();
1304 handsRaised_.erase(deviceId);
1305 updateHandsRaised();
1311 JAMI_WARNING(
"[conf:{}] Failed to set hand raised for {} (participant not found)", id_, deviceId);
1316Conference::isVoiceActive(std::string_view streamId)
const
1318 return streamsVoiceActive.find(streamId) != streamsVoiceActive.end();
1334 JAMI_ERROR(
"[conf:{}] Participant not found with streamId: {}", id_, streamId);
1347 streamsVoiceActive.emplace(streamId);
1354 streamsVoiceActive.erase(streamId);
1364 if (
auto call = getCall(p)) {
1382Conference::updateModerators()
1384 std::lock_guard
lk(confInfoMutex_);
1385 for (
auto& info : confInfo_) {
1388 sendConferenceInfos();
1392Conference::updateHandsRaised()
1394 std::lock_guard
lk(confInfoMutex_);
1395 for (
auto& info : confInfo_)
1396 info.handRaised = isHandRaised(info.device);
1397 sendConferenceInfos();
1403 std::lock_guard
lk(confInfoMutex_);
1423 sendConferenceInfos();
1427Conference::foreachCall(
const std::function<
void(
const std::shared_ptr<Call>& call)>&
cb)
1430 if (
auto call = getCall(p))
1435Conference::isMuted(std::string_view callId)
const
1437 return participantsMuted_.find(callId) != participantsMuted_.end();
1443 if (
auto acc = std::dynamic_pointer_cast<JamiAccount>(account_.lock())) {
1444 if (
accountUri == acc->getUsername() && deviceId == acc->currentDeviceId()) {
1446 }
else if (
auto call = getCallWith(
accountUri, deviceId)) {
1447 muteCall(call->getCallId(), state);
1455Conference::muteHost(
bool state)
1459 participantsMuted_.emplace(
"host"sv);
1464 participantsMuted_.erase(
"host");
1473Conference::muteCall(
const std::string& callId,
bool state)
1477 participantsMuted_.emplace(callId);
1478 unbindSubCallAudio(callId);
1481 participantsMuted_.erase(callId);
1482 bindSubCallAudio(callId);
1498 auto w = call->getAccount();
1505 call->sendConfOrder(
root);
1514 muteCall(call->getCallId(), state);
1520 std::lock_guard
lk(confInfoMutex_);
1521 for (
auto& info : confInfo_) {
1522 if (info.uri.empty()) {
1524 }
else if (
auto call = getCallWith(std::string(
string_remove_suffix(info.uri,
'@')), info.device)) {
1525 info.recording = call->isPeerRecording();
1528 sendConferenceInfos();
1534 std::lock_guard
lk(confInfoMutex_);
1535 for (
auto& info : confInfo_) {
1536 if (info.uri.empty()) {
1537 info.audioModeratorMuted = isMuted(
"host"sv);
1539 }
else if (
auto call = getCallWith(std::string(
string_remove_suffix(info.uri,
'@')), info.device)) {
1540 info.audioModeratorMuted = isMuted(call->getCallId());
1541 info.audioLocalMuted = call->isPeerMuted();
1544 sendConferenceInfos();
1553 bool isRemoteHost = remoteHosts_.find(
it->uri) != remoteHosts_.end();
1585Conference::isHost(std::string_view uri)
const
1593 if (
auto call = getCall(p)) {
1594 if (
auto account = call->getAccount().lock()) {
1595 if (
account->getUsername() == uri)
1604Conference::isHostDevice(std::string_view deviceId)
const
1606 if (
auto acc = std::dynamic_pointer_cast<JamiAccount>(account_.lock()))
1607 return deviceId == acc->currentDeviceId();
1614 std::lock_guard
lk(confInfoMutex_);
1616 sendConferenceInfos();
1622 if (
auto acc = std::dynamic_pointer_cast<JamiAccount>(account_.lock())) {
1623 if (deviceId.empty()) {
1630 if (
accountUri == acc->getUsername() && deviceId == acc->currentDeviceId()) {
1633 }
else if (
auto call = getCallWith(
accountUri, deviceId)) {
1656 JAMI_DEBUG(
"[conf:{}] Local audio source already {}", id_,
is_muted ?
"muted" :
"unmuted");
1673 JAMI_ERROR(
"Unable to stop camera, the camera is disabled!");
1678 JAMI_DEBUG(
"[conf:{}] Local camera source already {}", id_,
is_muted ?
"stopped" :
"started");
1683 if (
auto mixer = videoMixer_) {
1684 mixer->stopInputs();
1687 if (
auto mixer = videoMixer_) {
1689 for (
const auto& source : hostSources_) {
1714 auto recv = std::static_pointer_cast<video::VideoRtpSession>(
videoRtp)->getVideoReceive();
1726 JAMI_WARNING(
"[conf:{}] Remote frame size not found", id_);
1732 for (
const auto& p : confInfo_) {
1760 std::lock_guard
lk(confInfoMutex_);
1762 sendConferenceInfos();
1770 std::lock_guard
lk(confInfoMutex_);
1773 if (
it != remoteHosts_.end()) {
1789 videoMixer_->updateLayout();
1793 sendConferenceInfos();
1797Conference::findHostforRemoteParticipant(std::string_view uri, std::string_view deviceId)
1799 for (
const auto&
host : remoteHosts_) {
1808std::shared_ptr<Call>
1812 auto call = getCall(p);
1813 if (call && getRemoteId(call) ==
peerID) {
1820std::shared_ptr<Call>
1821Conference::getCallWith(
const std::string&
accountUri,
const std::string& deviceId)
1824 if (
auto call = std::dynamic_pointer_cast<SIPCall>(getCall(p))) {
1825 auto* transport = call->getTransport();
1827 && deviceId == transport->deviceId()) {
1836Conference::getRemoteId(
const std::shared_ptr<jami::Call>& call)
const
1838 if (
auto* transport = std::dynamic_pointer_cast<SIPCall>(call)->getTransport())
1839 if (
auto cert = transport->getTlsInfos().peerCert)
1841 return cert->issuer->getId().toString();
1863Conference::bindHostAudio()
1865 JAMI_DEBUG(
"[conf:{}] Binding host audio", id_);
1876 for (
const auto& source : hostSources_) {
1895 if (source.muted_) {
1899 JAMI_DEBUG(
"[conf:{}] Secondary host buffer {} is muted – unbinding", id_,
bufferId);
1908 JAMI_WARNING(
"[conf:{}] No source ring buffer for host audio {}", id_, source.label_);
1917 auto call = getCall(
item);
1922 const auto medias = call->getRemoteAudioStreams();
1972Conference::unbindHostAudio()
1974 JAMI_DEBUG(
"[conf:{}] Unbinding host audio", id_);
1977 for (
const auto& source : hostSources_) {
2001Conference::bindSubCallAudio(
const std::string& callId)
2115 for (
const auto& source : hostSources_) {
2117 auto it = hostAudioInputs_.find(source.label_);
2118 if (
it != hostAudioInputs_.end() &&
it->second) {
2119 auto buffer =
it->second->getSourceRingBufferId();
2136Conference::unbindSubCallAudio(
const std::string& callId)
2138 JAMI_DEBUG(
"[conf:{}] Unbinding participant audio: {}", id_, callId);
2139 if (
auto call = getCall(callId)) {
2140 auto medias = call->getAudioStreams();
2150 rbPool.unBindAllHalfDuplexOut(
id);
2158Conference::clearParticipantData(
const std::string& callId)
2160 JAMI_DEBUG(
"[conf:{}] Clearing participant data for call {}", id_, callId);
2162 if (callId.empty()) {
2163 JAMI_WARNING(
"[conf:{}] Cannot clear participant data: empty call id", id_);
2167 auto call = std::dynamic_pointer_cast<SIPCall>(getCall(callId));
2169 JAMI_WARNING(
"[conf:{}] Unable to find call {} to clear participant", id_, callId);
2173 auto* transport = call->getTransport();
2175 JAMI_WARNING(
"[conf:{}] Unable to find transport for call {} to clear participant", id_, callId);
2179 const std::string deviceId = std::string(transport->deviceId());
2183 std::lock_guard
lk(confInfoMutex_);
2184 for (
auto it = confInfo_.begin();
it != confInfo_.end();) {
2186 it = confInfo_.erase(
it);
2192 if (
remoteIt != remoteHosts_.end()) {
2195 handsRaised_.erase(deviceId);
2197 participantsMuted_.erase(callId);
2200 sendConferenceInfos();
std::shared_ptr< Call > getCall(const std::string &id) const
Return call pointer associated to given ID.Type can optionally be specified.
void onHangupParticipant(std::function< void(const std::string &, const std::string &)> &&cb)
void onMuteStreamAudio(std::function< void(const std::string &, const std::string &, const std::string &, bool)> &&cb)
void onKickParticipant(std::function< void(const std::string &)> &&cb)
void onRaiseHand(std::function< void(const std::string &, bool)> &&cb)
void initData(Json::Value &&d, std::string_view peerId)
Inject in the parser the data to parse.
void onMuteParticipant(std::function< void(const std::string &, bool)> &&cb)
void onSetActiveParticipant(std::function< void(const std::string &)> &&cb)
void onSetActiveStream(std::function< void(const std::string &, bool)> &&cb)
void onCheckAuthorization(std::function< bool(std::string_view)> &&cb)
Ask the caller to check if a peer is authorized (moderator of the conference)
void onSetLayout(std::function< void(int)> &&cb)
void onVersion(std::function< void(uint32_t)> &&cb)
void parse()
Parse the datas, this will call the methods injected if necessary.
void onVoiceActivity(std::function< void(const std::string &, bool)> &&cb)
void onRaiseHandUri(std::function< void(const std::string &, bool)> &&cb)
const char * getStateStr() const
void setVoiceActivity(const std::string &streamId, const bool &newState)
std::string getAccountId() const
bool isVideoEnabled() const
void hangupParticipant(const std::string &accountUri, const std::string &deviceId="")
void muteLocalHost(bool is_muted, const std::string &mediaType)
std::chrono::milliseconds getDuration() const
bool startRecording(const std::string &path) override
Start recording.
const std::string & getConfId() const
Return the conference id.
void removeSubCall(const std::string &callId)
Remove a subcall from the conference.
void updateVoiceActivity()
std::vector< libjami::MediaMap > currentMediaList() const
Retrieve current medias list.
void detachHost()
Detach local audio/video from the conference.
~Conference()
Destructor for this class, decrement static counter.
void mergeConfInfo(ConfInfo &newInfo, const std::string &peerURI)
void setActiveParticipant(const std::string &participant_id)
void handleMediaChangeRequest(const std::shared_ptr< Call > &call, const std::vector< libjami::MediaMap > &remoteMediaList)
Process incoming media change request.
void setLocalHostMuteState(MediaType type, bool muted)
Set the mute state of the local host.
void setState(State state)
Set conference state.
bool requestMediaChange(const std::vector< libjami::MediaMap > &mediaList)
Process a media change request.
void onConfOrder(const std::string &callId, const std::string &order)
void addSubCall(const std::string &callId)
Add a new subcall to the conference.
std::shared_ptr< Account > getAccount() const
Conference(const std::shared_ptr< Account > &, const std::string &confId="")
Constructor for this class, increment static counter.
std::shared_ptr< Call > getCallFromPeerID(std::string_view peerId)
void setActiveStream(const std::string &streamId, bool state)
void setModerator(const std::string &uri, const bool &state)
void stopRecording() override
Stop recording.
bool toggleRecording() override
Start/stop recording toggle.
CallIdSet getSubCalls() const
Get the participant list for this conference.
void setHandRaised(const std::string &uri, const bool &state)
void attachHost(const std::vector< libjami::MediaMap > &mediaList)
Attach host.
void muteParticipant(const std::string &uri, const bool &state)
State getState() const
Return the current conference state.
void muteStream(const std::string &accountUri, const std::string &deviceId, const std::string &streamId, const bool &state)
The client shows one tile per stream (video/audio related to a media)
void updateConferenceInfo(ConfInfo confInfo)
void switchInput(const std::string &input)
void setLayout(int layout)
void reportMediaNegotiationStatus()
Announce to the client that medias are successfully negotiated.
bool isMediaSourceMuted(MediaType type) const
Get the mute state of the local host.
Ring Account is build on top of SIPAccountBase and uses DHT to handle call connectivity.
Manager (controller) of daemon.
std::vector< std::shared_ptr< T > > getAllAccounts() const
Get a list of account pointers of type T (baseclass Account)
static LIBJAMI_TEST_EXPORT Manager & instance()
VideoManager * getVideoManager() const
bool hangupCall(const std::string &accountId, const std::string &callId)
Functions which occur with a user's action Hangup the call.
bool detachHost(const std::shared_ptr< Conference > &conf={})
Detach the local participant from curent conference.
RingBufferPool & getRingBufferPool()
Return a pointer to the instance of the RingBufferPool.
virtual bool startRecording(const std::string &path)
Start recording.
virtual void stopRecording()
Stop recording.
virtual bool toggleRecording()
This method must be implemented for this interface as calls and conferences have different behavior.
std::shared_ptr< MediaRecorder > recorder_
bool isRecording() const
Return recording state (true/false)
void unBindAllHalfDuplexIn(const std::string &sourceBufferId)
Detaches a source from all its readers.
static const char *const DEFAULT_ID
void unBindAll(const std::string &ringbufferId)
#define JAMI_ERROR(formatstr,...)
#define JAMI_DEBUG(formatstr,...)
#define JAMI_WARNING(formatstr,...)
#define JAMI_LOG(formatstr,...)
std::string toString(const Json::Value &jsonVal)
bool parse(std::string_view jsonStr, Json::Value &jsonVal)
std::string streamId(const std::string &callId, std::string_view label)
constexpr std::string_view DEFAULT_VIDEO_STREAMID
constexpr std::string_view DEFAULT_AUDIO_STREAMID
std::set< std::string > CallIdSet
static constexpr const char TRUE_STR[]
bool closeMediaPlayer(const std::string &id)
void emitSignal(Args... args)
std::shared_ptr< AudioInput > getAudioInput(const std::string &device)
std::vector< unsigned > split_string_to_unsigned(std::string_view str, char delim)
std::string_view string_remove_suffix(std::string_view str, char separator)
static constexpr const char FALSE_STR[]
std::string createMediaPlayer(const std::string &path)
static void runOnMainThread(Callback &&cb)
void hangupParticipant(const std::string &accountId, const std::string &confId, const std::string &accountUri, const std::string &deviceId)
SIPCall are SIP implementation of a normal Call.
Contains information about an AV subject.
std::string toString() const
std::vector< std::map< std::string, std::string > > toVectorMapStringString() const
#define jami_tracepoint(...)