diff --git a/src/sip/sipcall.cpp b/src/sip/sipcall.cpp index f2aab4c5b04753017d462b1d69a5e215d0c4d71c..e06b506eb53f3894f55439e4e57b9f7326ffcddc 100644 --- a/src/sip/sipcall.cpp +++ b/src/sip/sipcall.cpp @@ -394,6 +394,26 @@ SIPCall::requestKeyframe() lastKeyFrameReq_ = now; } +void +SIPCall::setMute(bool state) +{ + std::string BODY = "<?xml version=\"1.0\" encoding=\"utf-8\" ?>" + "<media_control><vc_primitive><to_encoder>" + "<mute_state=" + + std::to_string(state) + + "/>" + "</to_encoder></vc_primitive></media_control>"; + // see https://tools.ietf.org/html/rfc5168 for XML Schema for Media Control details + + JAMI_DBG("Sending mute state via SIP INFO"); + + try { + sendSIPInfo(BODY.c_str(), "media_control+xml"); + } catch (const std::exception& e) { + JAMI_ERR("Error sending mute state: %s", e.what()); + } +} + void SIPCall::updateSDPFromSTUN() { @@ -1294,6 +1314,8 @@ SIPCall::muteMedia(const std::string& mediaType, bool mute) avformatrtp_->setMuted(isAudioMuted_); if (not isSubcall()) emitSignal<DRing::CallSignal::AudioMuted>(getCallId(), isAudioMuted_); + setMute(mute); + } } @@ -1733,4 +1755,18 @@ SIPCall::setRemoteRecording(bool state) peerRecording_ = state; } +void +SIPCall::setPeerMute(bool state) +{ + if (state) { + JAMI_WARN("SIP Peer muted"); + } else { + JAMI_WARN("SIP Peer ummuted"); + } + peerMuted_ = state; + if (auto conf = Manager::instance().getConferenceFromID(getConfId())) { + conf->muteParticipant(getPeerNumber(), state); + } +} + } // namespace jami diff --git a/src/sip/sipcall.h b/src/sip/sipcall.h index e9d88cb8f54e2f30e615ccbd9c215858a8abff8d..58cab3da4a95f302a8e2c84eef75b45070dbec7a 100644 --- a/src/sip/sipcall.h +++ b/src/sip/sipcall.h @@ -240,7 +240,13 @@ public: // NOT SIP RELATED (good candidates to be moved elsewhere) void setRemoteRecording(bool state); - bool isPeerRecording() { return peerRecording_; } + bool isPeerRecording() const { return peerRecording_; } + + void setMute(bool state); + + void setPeerMute(bool state); + + bool isPeerMuted() const { return peerMuted_; } private: using clock = std::chrono::steady_clock; @@ -381,6 +387,7 @@ private: OnReadyCb offHoldCb_ {}; bool peerRecording_ {false}; + bool peerMuted_ {false}; std::atomic_bool waitForIceInit_ {false}; }; diff --git a/src/sip/sipvoiplink.cpp b/src/sip/sipvoiplink.cpp index 0ef2be8782a38b0a461cd6da3a209fe02f00f4de..7b91e4861cafade3925a18a5c4e2d653f9b6b8dd 100644 --- a/src/sip/sipvoiplink.cpp +++ b/src/sip/sipvoiplink.cpp @@ -1053,6 +1053,7 @@ handleMediaControl(SIPCall& call, pjsip_msg_body* body) static constexpr auto PICT_FAST_UPDATE = "picture_fast_update"sv; static constexpr auto DEVICE_ORIENTATION = "device_orientation"sv; static constexpr auto RECORDING_STATE = "recording_state"sv; + static constexpr auto MUTE_STATE = "mute_state"sv; if (body_msg.find(PICT_FAST_UPDATE) != std::string_view::npos) { call.sendKeyframe(); @@ -1093,6 +1094,20 @@ handleMediaControl(SIPCall& call, pjsip_msg_body* body) } return true; } + } else if (body_msg.find(MUTE_STATE) != std::string_view::npos) { + static const std::regex REC_REGEX("mute_state=([0-1])"); + std::svmatch matched_pattern; + std::regex_search(body_msg, matched_pattern, REC_REGEX); + + if (matched_pattern.ready() && !matched_pattern.empty() && matched_pattern[1].matched) { + try { + bool state = std::stoi(matched_pattern[1]); + call.setPeerMute(state); + } catch (const std::exception& e) { + JAMI_WARN("Error parsing state remote mute: %s", e.what()); + } + return true; + } } }