38#define RESIPROCATE_SUBSYSTEM ReconSubsystem::RECON
61 RemoteParticipant(partHandle, conversationManager, dum, remoteParticipantDialogSet),
63 mRemoveExtraMediaDescriptors(false),
64 mSipRtpEndpoint(true),
65 mReuseSdpAnswer(false),
66 mWSAcceptsKeyframeRequests(true),
68 mWaitingAnswer(false),
69 mWebRTCOutgoing(getDialogSet().getConversationProfile()->mediaEndpointMode() ==
ConversationProfile::WebRTC)
71 InfoLog(<<
"KurentoRemoteParticipant created (UAC), handle=" <<
mHandle);
82 mRemoveExtraMediaDescriptors(false),
83 mSipRtpEndpoint(true),
84 mReuseSdpAnswer(false),
85 mWSAcceptsKeyframeRequests(true),
87 mWaitingAnswer(false),
88 mWebRTCOutgoing(getDialogSet().getConversationProfile()->mediaEndpointMode() ==
ConversationProfile::WebRTC)
90 InfoLog(<<
"KurentoRemoteParticipant created (UAS or forked leg), handle=" <<
mHandle);
105 mEndpoint->release([h]
107 DebugLog(<<
"release requested for Endpoint mHandle = " << h);
111 InfoLog(<<
"KurentoRemoteParticipant destroyed, handle=" <<
mHandle);
153KurentoRemoteParticipant::newEndpoint()
161KurentoRemoteParticipant::initEndpointIfRequired(
bool isWebRTC)
170 mIceGatheringDone =
false;
175 mIceGatheringDone =
true;
176 mEndpoint.reset(newEndpoint());
191 if(!holdVideo.
empty())
203 std::shared_ptr<kurento::WebRtcEndpoint> webRtc = std::static_pointer_cast<kurento::WebRtcEndpoint>(mEndpoint);
205 std::shared_ptr<kurento::EventContinuation> elEventIceCandidateFound =
206 std::make_shared<kurento::EventContinuation>([
this](std::shared_ptr<kurento::Event> event){
207 DebugLog(<<
"received event: " << *event);
208 std::shared_ptr<kurento::OnIceCandidateFoundEvent> _event =
209 std::dynamic_pointer_cast<kurento::OnIceCandidateFoundEvent>(event);
217 _event->getLineIndex(),
Data(_event->getId()));
220 std::shared_ptr<kurento::EventContinuation> elIceGatheringDone =
221 std::make_shared<kurento::EventContinuation>([
this, sdpReady](std::shared_ptr<kurento::Event> event){
222 mIceGatheringDone =
true;
223 mEndpoint->getLocalSessionDescriptor(sdpReady);
226 webRtc->addOnIceCandidateFoundListener(elEventIceCandidateFound, [=](){
227 webRtc->addOnIceGatheringDoneListener(elIceGatheringDone, [=](){
228 webRtc->gatherCandidates([]{
241 std::shared_ptr<kurento::EventContinuation> elError =
242 std::make_shared<kurento::EventContinuation>([
this](std::shared_ptr<kurento::Event> event){
243 ErrLog(<<
"Error from Kurento MediaObject: " << *event);
246 std::shared_ptr<kurento::EventContinuation> elEventDebug =
247 std::make_shared<kurento::EventContinuation>([
this](std::shared_ptr<kurento::Event> event){
248 DebugLog(<<
"received event: " << *event);
251 std::shared_ptr<kurento::EventContinuation> elEventKeyframeRequired =
252 std::make_shared<kurento::EventContinuation>([
this](std::shared_ptr<kurento::Event> event){
253 DebugLog(<<
"received event: " << *event);
257 auto cConnectedInternal = [
this, cConnected, elEventDebug]
259 std::shared_ptr<kurento::WebRtcEndpoint> webRtc = std::dynamic_pointer_cast<kurento::WebRtcEndpoint>(mEndpoint);
262 webRtc->addDataChannelOpenedListener(elEventDebug, [
this](){});
267 mEndpoint->create([=]{
268 mEndpoint->addErrorListener(elError, [=](){
269 mEndpoint->addConnectionStateChangedListener(elEventDebug, [=](){
270 mEndpoint->addMediaStateChangedListener(elEventDebug, [=](){
271 mEndpoint->addMediaTranscodingStateChangeListener(elEventDebug, [=](){
272 mEndpoint->addMediaFlowInStateChangeListener(elEventDebug, [=](){
273 mEndpoint->addMediaFlowOutStateChangeListener(elEventDebug, [=](){
274 mEndpoint->addKeyframeRequiredListener(elEventKeyframeRequired, [=](){
277 mPlayer->create([
this, cConnectedInternal]{
278 mPlayer->play([
this, cConnectedInternal]{
279 mPlayer->connect(cConnectedInternal, *mEndpoint);
286 mEndpoint->connect([
this, cConnectedInternal]{
293 cConnectedInternal();
308 bool useExistingSdp =
false;
317 bool firstUseEndpoint = initEndpointIfRequired(isWebRTC);
320 StackLog(<<
"offer FROM Kurento: " << offer);
322 Mime type(
"application",
"sdp");
323 std::unique_ptr<SdpContents> _offer(
new SdpContents(hfv, type));
324 _offer->session().transformLocalHold(holdSdp);
326 sdpReady(
true, std::move(_offer));
332 mEndpoint->generateOffer([
this, isWebRTC, sdpReady, cOnOfferReady](
const std::string& offer){
336 doIceGathering(cOnOfferReady);
340 cOnOfferReady(offer);
347 createAndConnectElements(cConnected);
357 std::ostringstream offerMangledBuf;
360 std::shared_ptr<std::string> offerMangledStr = std::make_shared<std::string>(offerMangledBuf.str());
361 cOnOfferReady(*offerMangledStr);
367 ErrLog(<<
"something went wrong: " << e.what());
368 sdpReady(
false,
nullptr);
373KurentoRemoteParticipant::buildSdpAnswer(
const SdpContents& offer, CallbackSdpReady sdpReady)
375 bool requestSent =
false;
377 std::shared_ptr<SdpContents> offerMangled = std::make_shared<SdpContents>(offer);
381 DebugLog(<<
"more than 2 media descriptors, removing the last");
382 offerMangled->session().media().pop_back();
389 bool isWebRTC = offerMangled->session().isWebRTC();
390 DebugLog(<<
"peer is " << (isWebRTC ?
"WebRTC":
"not WebRTC"));
400 if(
getDialogSet().getConversationProfile()->forceCOMedia())
402 offerMangled->session().transformCOMedia(
"active",
"direction");
406 std::ostringstream offerMangledBuf;
407 offerMangledBuf << *offerMangled;
408 std::shared_ptr<std::string> offerMangledStr = std::make_shared<std::string>(offerMangledBuf.str());
410 StackLog(<<
"offer TO Kurento: " << *offerMangledStr);
412 bool firstUseEndpoint = initEndpointIfRequired(isWebRTC);
415 StackLog(<<
"answer FROM Kurento: " << answer);
417 Mime type(
"application",
"sdp");
418 std::unique_ptr<SdpContents> _answer(
new SdpContents(hfv, type));
419 _answer->session().transformLocalHold(
isHolding());
422 sdpReady(
true, std::move(_answer));
425 kurento::ContinuationVoid cConnected = [
this, offerMangled, offerMangledStr, isWebRTC, firstUseEndpoint, sdpReady, cOnAnswerReady]{
431 std::ostringstream answerBuf;
433 std::shared_ptr<std::string> answerStr = std::make_shared<std::string>(answerBuf.str());
434 cOnAnswerReady(*answerStr);
437 mEndpoint->processOffer([
this, offerMangled, isWebRTC, sdpReady, cOnAnswerReady](
const std::string& answer){
442 HeaderFieldValue hfv(answer.data(), answer.size());
443 Mime type(
"application",
"sdp");
444 std::unique_ptr<SdpContents> _local(new SdpContents(hfv, type));
445 DebugLog(<<
"storing incomplete webrtc answer");
446 setLocalSdp(*_local);
447 setRemoteSdp(*offerMangled);
448 ServerInviteSession* sis = dynamic_cast<ServerInviteSession*>(getInviteSessionHandle().get());
449 sis->provideAnswer(*_local);
450 sis->provisional(183, true);
458 doIceGathering(cOnAnswerReady);
462 cOnAnswerReady(answer);
464 }, *offerMangledStr);
469 createAndConnectElements(cConnected);
480 ErrLog(<<
"something went wrong: " << e.what());
486 sdpReady(
false,
nullptr);
499 std::shared_ptr<SdpContents> remoteSdp =
getRemoteSdp();
505 if(!remoteDirection.
recv())
516 DebugLog(<<
"remoteSdp has changed, sending to Kurento");
518 std::ostringstream answerBuf;
519 answerBuf << *remoteSdp;
522 mEndpoint->processOffer([
this](
const std::string updatedOffer){
524 WarningLog(<<
"Kurento has processed the peer's SDP answer");
525 StackLog(<<
"updatedOffer FROM Kurento: " << updatedOffer);
527 Mime type(
"application",
"sdp");
528 std::unique_ptr<SdpContents> _updatedOffer(
new SdpContents(hfv, type));
529 _updatedOffer->session().transformLocalHold(
isHolding());
530 if(
getDialogSet().getConversationProfile()->maximumVideoBandwidth() > 0)
549 for(
int i = 1000; i <= 5000; i+=1000)
551 std::chrono::milliseconds _i = std::chrono::milliseconds(i);
580 if(!e || e == mEndpoint)
585 DebugLog(<<
"connected in waiting mode, waiting for peer");
592 mEndpoint->connect([
this]{
600std::shared_ptr<kurento::MediaElement>
605 return dynamic_pointer_cast<kurento::Endpoint>(
mPlayer);
622 auto now = std::chrono::steady_clock::now();
625 DebugLog(<<
"keyframe request ignored, too soon");
628 mLastLocalKeyframeRequest = now;
629 InfoLog(<<
"onMediaControlEvent: sending to Kurento");
631 mEndpoint->sendPictureFastUpdate([
this](){});
636 WarningLog(<<
"rejecting MediaControlEvent due to config option mWSAcceptsKeyframeRequests");
644 DebugLog(<<
"onTrickleIce: sending to Kurento");
648 std::shared_ptr<kurento::WebRtcEndpoint> webRtc = std::static_pointer_cast<kurento::WebRtcEndpoint>(mEndpoint);
649 for(
auto m = trickleIce.
media().cbegin(); m != trickleIce.
media().cend(); m++)
653 const Data& mid = m->getValues(
"mid").front();
654 const std::string _mid = mid.
c_str();
656 if(m->exists(
"candidate"))
658 auto candidates = m->getValues(
"candidate");
659 for(
auto a = candidates.cbegin(); a != candidates.cend(); a++)
661 webRtc->addIceCandidate([
this](){},
670 WarningLog(<<
"mid is missing for Medium in SDP fragment: " << trickleIce);
680 if(mEndpoint->valid())
682 mEndpoint->sendPictureFastUpdate([]{});
686 WarningLog(<<
"can't request keyframe, mEndpoint not valid");
#define WarningLog(args_)
#define resip_assert(x)
This file needs to work for both C and C++ code.
This class is one of two main classes of concern to an application using the UserAgent library.
bool sendKeyframesAtStart() const
virtual void requestKeyframe(ParticipantHandle partHandle, std::chrono::duration< double > durationMs)
virtual void requestKeyframeFromPeerRecurring(ParticipantHandle partHandle, std::chrono::duration< double > interval)
std::shared_ptr< resip::ConfigParse > getConfig()
This class extends the resip UserProfile to include Conversation Manager specific settings.
This class is used to manage membership of participants.
This is the base class for a KurentoRemoteParticipant, KurentoLocalParticipant and a KurentoMediaReso...
KurentoMediaStackAdapter & mKurentoMediaStackAdapter
virtual int getMediaConnectionId()
virtual ~KurentoRemoteParticipant()
virtual void applyBridgeMixWeights() override
virtual std::shared_ptr< kurento::MediaElement > getWaitingModeElement()
virtual void waitingMode()
virtual bool mediaStackPortAvailable()
KurentoRemoteParticipant(ParticipantHandle partHandle, ConversationManager &conversationManager, KurentoMediaStackAdapter &kurentoMediaStackAdapter, resip::DialogUsageManager &dum, RemoteParticipantDialogSet &remoteParticipantDialogSet)
virtual void adjustRTPStreams(bool sendingOffer=false)
virtual KurentoRemoteParticipantDialogSet & getKurentoDialogSet()
virtual bool onTrickleIce(resip::TrickleIceContents &trickleIce) override
virtual void removeFromConversation(Conversation *conversation) override
virtual void buildSdpOffer(bool holdSdp, CallbackSdpReady sdpReady, bool preferExistingSdp=false)
std::shared_ptr< kurento::PassThroughElement > mPassThrough
virtual void requestKeyframe() override
std::shared_ptr< kurento::PlayerEndpoint > mPlayer
bool mRemoveExtraMediaDescriptors
resip::SdpContents * mLastRemoteSdp
bool mTrickleIcePermitted
bool mWSAcceptsKeyframeRequests
virtual void addToConversation(Conversation *conversation, unsigned int inputGain=100, unsigned int outputGain=100) override
virtual int getConnectionPortOnBridge()
virtual bool onMediaControlEvent(resip::MediaControlContents::MediaControl &mediaControl)
virtual int getMediaConnectionId()
This is the base class for a RemoteParticipant, LocalParticipant and a MediaResourceParticipant.
virtual ParticipantHandle getParticipantHandle()
virtual void unregisterFromAllConversations()
ParticipantHandle mHandle
ConversationManager & mConversationManager
This class is used by Invite DialogSets.
This class represent a remote participant.
void setProposedSdp(const resip::SdpContents &sdp)
void setRemoteSdp(const resip::SdpContents &sdp, bool answer=false)
virtual void requestKeyframeFromPeerTimeout(bool reset)
virtual std::chrono::duration< double > getKeyframeRequestInterval() const
virtual void onLocalIceCandidate(const resip::Data &candidate, unsigned int lineIndex, const resip::Data &mid)
std::function< void(bool sdpOk, std::unique_ptr< resip::SdpContents > sdp)> CallbackSdpReady
void setLocalSdp(const resip::SdpContents &sdp)
virtual void addToConversation(Conversation *conversation, unsigned int inputGain=100, unsigned int outputGain=100) override
std::shared_ptr< resip::SdpContents > getLocalSdp()
virtual void removeFromConversation(Conversation *conversation) override
std::shared_ptr< resip::SdpContents > getRemoteSdp()
virtual void requestKeyframeFromPeer()
virtual resip::InviteSessionHandle & getInviteSessionHandle()
void setRemoteHold(bool remoteHold)
RemoteParticipantDialogSet & getDialogSet()
An alternative to std::string, encapsulates an arbitrary buffer of bytes.
const char * c_str() const
Returns a null-terminated string representing.
bool empty() const noexcept
Checks whether the Data is empty.
int convertInt() const
Takes the contents of the Data and converts them to an integer.
virtual void provideOffer(const Contents &offer)
Called to set the offer that will be used in the next message that sends an offer.
Represents the "media-type" element in the RFC 3261 grammar.
Process optional b= (bandwidth) lines in SDP.
Provides an interface to process and generate SDP bodies (MIME content-type application/sdp).
const SdpContents::Session::MediumContainer & media() const
This class is used in the logging subsystem to identify logging messages generated from the Kurento c...
std::function< void(void) > ContinuationVoid
std::function< void(const std::string &s) > ContinuationString
unsigned int ParticipantHandle
dcm! – add UnusedChecking(_enum) below;