Commit b424a5d0 authored by Pierre Lespagnol's avatar Pierre Lespagnol Committed by Sébastien Blin

recorder: add remote recording indicator

Change-Id: I711a0b2f446f1620d7dff66945bf9295fd8372ac
parent 98fd6f05
......@@ -842,5 +842,12 @@
<annotation name="org.qtproject.QtDBus.QtTypeName.In1" value="VectorMapStringString"/>
<arg type="aa{ss}" name="infos" />
</signal>
<signal name="remoteRecordingChanged" tp:name-for-bindings="remoteRecordingChanged">
<tp:added version="1.0.0"/>
<arg type="s" name="callID" />
<arg type="s" name="peerNumber" />
<arg type="b" name="remoteRecordingState" />
</signal>
</interface>
</node>
......@@ -177,7 +177,8 @@ DBusClient::initLibrary(int flags)
exportable_callback<CallSignal::PeerHold>(bind(&DBusCallManager::peerHold, callM, _1, _2)),
exportable_callback<CallSignal::AudioMuted>(bind(&DBusCallManager::audioMuted, callM, _1, _2)),
exportable_callback<CallSignal::VideoMuted>(bind(&DBusCallManager::videoMuted, callM, _1, _2)),
exportable_callback<CallSignal::SmartInfo>(bind(&DBusCallManager::SmartInfo, callM, _1))
exportable_callback<CallSignal::SmartInfo>(bind(&DBusCallManager::SmartInfo, callM, _1)),
exportable_callback<CallSignal::RemoteRecordingChanged>(bind(&DBusCallManager::remoteRecordingChanged, callM, _1, _2, _3))
};
// Configuration event handlers
......
......@@ -48,6 +48,7 @@ public:
virtual void onConferenceInfosUpdated(const std::string& confId, const std::vector<std::map<std::string, std::string>>& infos) {}
virtual void peerHold(const std::string& call_id, bool holding){}
virtual void connectionUpdate(const std::string& id, int state){}
virtual void remoteRecordingChanged(const std::string& call_id, const std::string& peer_number, bool state){}
};
......@@ -137,4 +138,6 @@ public:
virtual void onConferenceInfosUpdated(const std::string& confId, const std::vector<std::map<std::string, std::string>>& infos) {}
virtual void peerHold(const std::string& call_id, bool holding){}
virtual void connectionUpdate(const std::string& id, int state){}
virtual void remoteRecordingChanged(const std::string& call_id, const std::string& peer_number, bool state){}
};
......@@ -249,7 +249,8 @@ void init(ConfigurationCallback* confM, Callback* callM, PresenceCallback* presM
exportable_callback<CallSignal::RtcpReportReceived>(bind(&Callback::onRtcpReportReceived, callM, _1, _2)),
exportable_callback<CallSignal::OnConferenceInfosUpdated>(bind(&Callback::onConferenceInfosUpdated, callM, _1, _2)),
exportable_callback<CallSignal::PeerHold>(bind(&Callback::peerHold, callM, _1, _2)),
exportable_callback<CallSignal::ConnectionUpdate>(bind(&Callback::connectionUpdate, callM, _1, _2))
exportable_callback<CallSignal::ConnectionUpdate>(bind(&Callback::connectionUpdate, callM, _1, _2)),
exportable_callback<CallSignal::RemoteRecordingChanged>(bind(&Callback::remoteRecordingChanged, callM, _1, _2, _3))
};
// Configuration event handlers
......
......@@ -4,7 +4,7 @@ dnl Process this file with autoconf to produce a configure script.
AC_PREREQ([2.65])
AC_INIT([Jami Daemon],[9.5.0],[ring@gnu.org],[jami])
AC_COPYRIGHT([[Copyright (c) Savoir-faire Linux 2004-2019]])
AC_COPYRIGHT([[Copyright (c) Savoir-faire Linux 2004-2020]])
AC_REVISION([$Revision$])
dnl Where to find configure files
......
......@@ -49,6 +49,7 @@ getSignalHandlers()
exported_callback<DRing::CallSignal::SmartInfo>(),
exported_callback<DRing::CallSignal::ConnectionUpdate>(),
exported_callback<DRing::CallSignal::OnConferenceInfosUpdated>(),
exported_callback<DRing::CallSignal::RemoteRecordingChanged>(),
/* Configuration */
exported_callback<DRing::ConfigurationSignal::VolumeChanged>(),
......
......@@ -228,6 +228,10 @@ struct DRING_PUBLIC CallSignal
using cb_type = void(const std::string&,
const std::vector<std::map<std::string, std::string>>&);
};
struct DRING_PUBLIC RemoteRecordingChanged {
constexpr static const char* name = "RemoteRecordingChanged";
using cb_type = void(const std::string&, const std::string&, bool);
};
};
} // namespace DRing
......
......@@ -649,6 +649,8 @@ VideoRtpSession::initRecorder(std::shared_ptr<MediaRecorder>& rec)
}
}
}
if (recordingStateCallback_)
recordingStateCallback_(true);
}
void
......@@ -664,6 +666,9 @@ VideoRtpSession::deinitRecorder(std::shared_ptr<MediaRecorder>& rec)
input->detach(ob);
}
}
if (recordingStateCallback_)
recordingStateCallback_(false);
}
void
......
......@@ -97,6 +97,9 @@ public:
const std::string& getInput() const { return input_; }
void setChangeOrientationCallback(std::function<void(int)> cb);
void setRecStateCallback(std::function<void(bool)> cb) {
recordingStateCallback_ = std::move(cb);
}
void initRecorder(std::shared_ptr<MediaRecorder>& rec) override;
void deinitRecorder(std::shared_ptr<MediaRecorder>& rec) override;
......@@ -161,6 +164,8 @@ private:
std::function<void(int)> changeOrientationCallback_;
std::function<void(bool)> recordingStateCallback_;
// interval in seconds between RTCP checkings
std::chrono::seconds rtcp_checking_interval {4};
......
......@@ -335,6 +335,25 @@ SIPCall::sendSIPInfo(const char* const body, const char* const subtype)
pjsip_dlg_send_request(inv->dlg, tdata, Manager::instance().sipVoIPLink().getModId(), NULL);
}
void
SIPCall::updateRecState(bool state)
{
std::string BODY =
"<?xml version=\"1.0\" encoding=\"utf-8\" ?>"
"<media_control><vc_primitive><to_encoder>"
"<recording_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 recording state via SIP INFO");
try {
sendSIPInfo(BODY.c_str(), "media_control+xml");
} catch (const std::exception& e) {
JAMI_ERR("Error sending recording state: %s", e.what());
}
}
void
SIPCall::requestKeyframe()
{
......@@ -1037,6 +1056,12 @@ SIPCall::startAllMedia()
this_->setVideoOrientation(angle);
});
});
videortp_->setRecStateCallback([wthis = weak()] (bool state) {
runOnMainThread([wthis, state] {
if (auto this_ = wthis.lock())
this_->updateRecState(state);
});
});
#endif
for (const auto& slot : slots) {
......@@ -1599,4 +1624,16 @@ SIPCall::rtpSetupSuccess(MediaType type)
toggleRecording();
}
void
SIPCall::setRemoteRecording(bool state)
{
if (state) {
JAMI_WARN("SIP remote recording enabled");
emitSignal<DRing::CallSignal::RemoteRecordingChanged>(getCallId(), getPeerNumber(), true);
} else {
JAMI_WARN("SIP remote recording disabled");
emitSignal<DRing::CallSignal::RemoteRecordingChanged>(getCallId(), getPeerNumber(), false);
}
}
} // namespace jami
......@@ -174,6 +174,8 @@ public: // SIP related
void requestKeyframe();
void updateRecState(bool state);
SIPAccountBase& getSIPAccount() const;
void updateSDPFromSTUN();
......@@ -233,6 +235,8 @@ public: // NOT SIP RELATED (good candidates to be moved elsewhere)
void rtpSetupSuccess(MediaType type);
void setRemoteRecording(bool state);
private:
using clock = std::chrono::steady_clock;
using time_point = clock::time_point;
......
......@@ -1052,6 +1052,7 @@ handleMediaControl(SIPCall& call, pjsip_msg_body* body)
pj_strset(&control_st, (char*) body->data, body->len);
static constexpr pj_str_t PICT_FAST_UPDATE = CONST_PJ_STR("picture_fast_update");
static constexpr pj_str_t DEVICE_ORIENTATION = CONST_PJ_STR("device_orientation");
static constexpr pj_str_t RECORDING_STATE = CONST_PJ_STR("recording_state");
if (pj_strstr(&control_st, &PICT_FAST_UPDATE)) {
call.sendKeyframe();
......@@ -1078,6 +1079,22 @@ handleMediaControl(SIPCall& call, pjsip_msg_body* body)
return true;
}
}
else if (pj_strstr(&control_st, &RECORDING_STATE)) {
static const std::regex REC_REGEX("recording_state=([0-1])");
std::string body_msg(control_st.ptr, control_st.slen);
std::smatch 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.setRemoteRecording(state);
} catch (const std::exception& e) {
JAMI_WARN("Error parsing state remote recording: %s", e.what());
}
return true;
}
}
}
return false;
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment