36#define RESIPROCATE_SUBSYSTEM ReconSubsystem::RECON
59 RemoteParticipant(partHandle, conversationManager, dum, remoteParticipantDialogSet),
61 mRemoveExtraMediaDescriptors(false),
62 mSipRtpEndpoint(true),
63 mReuseSdpAnswer(false),
64 mWSAcceptsKeyframeRequests(true),
66 mWaitingAnswer(false),
67 mWebRTCOutgoing(getDialogSet().getConversationProfile()->mediaEndpointMode() ==
ConversationProfile::WebRTC)
69 InfoLog(<<
"LibWebRTCRemoteParticipant created (UAC), handle=" <<
mHandle);
80 mRemoveExtraMediaDescriptors(false),
81 mSipRtpEndpoint(true),
82 mReuseSdpAnswer(false),
83 mWSAcceptsKeyframeRequests(true),
85 mWaitingAnswer(false),
86 mWebRTCOutgoing(getDialogSet().getConversationProfile()->mediaEndpointMode() ==
ConversationProfile::WebRTC)
88 InfoLog(<<
"LibWebRTCRemoteParticipant created (UAS or forked leg), handle=" <<
mHandle);
100 InfoLog(<<
"LibWebRTCRemoteParticipant destroyed, handle=" <<
mHandle);
141libwebrtc::BaseRtpEndpoint*
142LibWebRTCRemoteParticipant::newEndpoint()
150LibWebRTCRemoteParticipant::initEndpointIfRequired(
bool isWebRTC)
159 mIceGatheringDone =
false;
164 mIceGatheringDone =
true;
165 mEndpoint.reset(newEndpoint());
182LibWebRTCRemoteParticipant::doIceGathering(libwebrtc::ContinuationString sdpReady)
184 std::shared_ptr<libwebrtc::WebRtcEndpoint> webRtc = std::static_pointer_cast<libwebrtc::WebRtcEndpoint>(mEndpoint);
186 std::shared_ptr<libwebrtc::EventContinuation> elEventIceCandidateFound =
187 std::make_shared<libwebrtc::EventContinuation>([
this](std::shared_ptr<libwebrtc::Event> event){
188 DebugLog(<<
"received event: " << *event);
189 std::shared_ptr<libwebrtc::OnIceCandidateFoundEvent> _event =
190 std::dynamic_pointer_cast<libwebrtc::OnIceCandidateFoundEvent>(event);
199 auto ice =
getLocalSdp()->session().makeIceFragment(
Data(_event->getCandidate()),
200 _event->getLineIndex(),
Data(_event->getId()));
203 StackLog(<<
"about to send " << *ice);
208 WarningLog(<<
"failed to create ICE fragment for mid: " << _event->getId());
212 std::shared_ptr<libwebrtc::EventContinuation> elIceGatheringDone =
213 std::make_shared<libwebrtc::EventContinuation>([
this, sdpReady](std::shared_ptr<libwebrtc::Event> event){
214 mIceGatheringDone =
true;
215 mEndpoint->getLocalSessionDescriptor(sdpReady);
218 webRtc->addOnIceCandidateFoundListener(elEventIceCandidateFound, [=](){
219 webRtc->addOnIceGatheringDoneListener(elIceGatheringDone, [=](){
220 webRtc->gatherCandidates([]{
229LibWebRTCRemoteParticipant::createAndConnectElements(libwebrtc::ContinuationVoid cConnected)
233 std::shared_ptr<libwebrtc::EventContinuation> elError =
234 std::make_shared<libwebrtc::EventContinuation>([
this](std::shared_ptr<libwebrtc::Event> event){
235 ErrLog(<<
"Error from LibWebRTC MediaObject: " << *event);
238 std::shared_ptr<libwebrtc::EventContinuation> elEventDebug =
239 std::make_shared<libwebrtc::EventContinuation>([
this](std::shared_ptr<libwebrtc::Event> event){
240 DebugLog(<<
"received event: " << *event);
243 std::shared_ptr<libwebrtc::EventContinuation> elEventKeyframeRequired =
244 std::make_shared<libwebrtc::EventContinuation>([
this](std::shared_ptr<libwebrtc::Event> event){
245 DebugLog(<<
"received event: " << *event);
249 mEndpoint->create([=]{
250 mEndpoint->addErrorListener(elError, [=](){
251 mEndpoint->addConnectionStateChangedListener(elEventDebug, [=](){
252 mEndpoint->addMediaStateChangedListener(elEventDebug, [=](){
253 mEndpoint->addMediaTranscodingStateChangeListener(elEventDebug, [=](){
254 mEndpoint->addMediaFlowInStateChangeListener(elEventDebug, [=](){
255 mEndpoint->addMediaFlowOutStateChangeListener(elEventDebug, [=](){
256 mEndpoint->addKeyframeRequiredListener(elEventKeyframeRequired, [=](){
259 mPlayer->create([
this, cConnected]{
261 mEndpoint->connect([
this, cConnected]{
288 bool useExistingSdp =
false;
297 bool firstUseEndpoint = initEndpointIfRequired(isWebRTC);
299 libwebrtc::ContinuationString cOnOfferReady = [
this, holdSdp, sdpReady](
const std::string& offer){
300 StackLog(<<
"offer FROM LibWebRTC: " << offer);
302 Mime type(
"application",
"sdp");
303 std::unique_ptr<SdpContents> _offer(
new SdpContents(hfv, type));
304 _offer->session().transformLocalHold(holdSdp);
306 sdpReady(
true, std::move(_offer));
309 libwebrtc::ContinuationVoid cConnected = [
this, holdSdp, isWebRTC, sdpReady, cOnOfferReady]{
312 mEndpoint->generateOffer([
this, isWebRTC, sdpReady, cOnOfferReady](
const std::string& offer){
316 doIceGathering(cOnOfferReady);
320 cOnOfferReady(offer);
327 createAndConnectElements(cConnected);
337 std::ostringstream offerMangledBuf;
340 std::shared_ptr<std::string> offerMangledStr = std::make_shared<std::string>(offerMangledBuf.str());
341 cOnOfferReady(*offerMangledStr);
347 ErrLog(<<
"something went wrong: " << e.what());
348 sdpReady(
false,
nullptr);
353LibWebRTCRemoteParticipant::buildSdpAnswer(
const SdpContents& offer, CallbackSdpReady sdpReady)
355 bool requestSent =
false;
357 std::shared_ptr<SdpContents> offerMangled = std::make_shared<SdpContents>(offer);
361 DebugLog(<<
"more than 2 media descriptors, removing the last");
362 offerMangled->session().media().pop_back();
369 bool isWebRTC = offerMangled->session().isWebRTC();
370 DebugLog(<<
"peer is " << (isWebRTC ?
"WebRTC":
"not WebRTC"));
380 offerMangled->session().transformCOMedia(
"active",
"direction");
383 std::ostringstream offerMangledBuf;
384 offerMangledBuf << *offerMangled;
385 std::shared_ptr<std::string> offerMangledStr = std::make_shared<std::string>(offerMangledBuf.str());
387 StackLog(<<
"offer TO LibWebRTC: " << *offerMangledStr);
389 bool firstUseEndpoint = initEndpointIfRequired(isWebRTC);
391 libwebrtc::ContinuationString cOnAnswerReady = [
this, offerMangled, isWebRTC, sdpReady](
const std::string& answer){
392 StackLog(<<
"answer FROM LibWebRTC: " << answer);
394 Mime type(
"application",
"sdp");
395 std::unique_ptr<SdpContents> _answer(
new SdpContents(hfv, type));
396 _answer->session().transformLocalHold(
isHolding());
399 sdpReady(
true, std::move(_answer));
402 libwebrtc::ContinuationVoid cConnected = [
this, offerMangled, offerMangledStr, isWebRTC, firstUseEndpoint, sdpReady, cOnAnswerReady]{
408 std::ostringstream answerBuf;
410 std::shared_ptr<std::string> answerStr = std::make_shared<std::string>(answerBuf.str());
411 cOnAnswerReady(*answerStr);
414 mEndpoint->processOffer([
this, offerMangled, isWebRTC, sdpReady, cOnAnswerReady](
const std::string& answer){
419 HeaderFieldValue hfv(answer.data(), answer.size());
420 Mime type(
"application",
"sdp");
421 std::unique_ptr<SdpContents> _local(new SdpContents(hfv, type));
422 DebugLog(<<
"storing incomplete webrtc answer");
423 setLocalSdp(*_local);
424 setRemoteSdp(*offerMangled);
425 ServerInviteSession* sis = dynamic_cast<ServerInviteSession*>(getInviteSessionHandle().get());
426 sis->provideAnswer(*_local);
427 sis->provisional(183, true);
435 doIceGathering(cOnAnswerReady);
439 cOnAnswerReady(answer);
441 }, *offerMangledStr);
446 createAndConnectElements(cConnected);
457 ErrLog(<<
"something went wrong: " << e.what());
463 sdpReady(
false,
nullptr);
476 std::shared_ptr<SdpContents> remoteSdp =
getRemoteSdp();
482 if(!remoteDirection.
recv())
493 DebugLog(<<
"remoteSdp has changed, sending to LibWebRTC");
495 std::ostringstream answerBuf;
496 answerBuf << *remoteSdp;
497 mEndpoint->processAnswer([
this](
const std::string updatedOffer){
499 WarningLog(<<
"LibWebRTC has processed the peer's SDP answer");
500 StackLog(<<
"updatedOffer FROM LibWebRTC: " << updatedOffer);
502 Mime type(
"application",
"sdp");
503 std::unique_ptr<SdpContents> _updatedOffer(
new SdpContents(hfv, type));
504 _updatedOffer->session().transformLocalHold(
isHolding());
509 for(
int i = 1000; i <= 5000; i+=1000)
511 std::chrono::milliseconds _i = std::chrono::milliseconds(i);
512 std::chrono::milliseconds __i = std::chrono::milliseconds(i + 500);
546 DebugLog(<<
"connected in waiting mode, waiting for peer");
553 mEndpoint->connect([
this]{
561std::shared_ptr<libwebrtc::MediaElement>
566 return dynamic_pointer_cast<libwebrtc::Endpoint>(
mPlayer);
579 auto now = std::chrono::steady_clock::now();
582 DebugLog(<<
"keyframe request ignored, too soon");
585 mLastLocalKeyframeRequest = now;
586 InfoLog(<<
"onMediaControlEvent: sending to LibWebRTC");
588 mEndpoint->sendPictureFastUpdate([
this](){});
593 WarningLog(<<
"rejecting MediaControlEvent due to config option mWSAcceptsKeyframeRequests");
601 DebugLog(<<
"onTrickleIce: sending to LibWebRTC");
605 std::shared_ptr<libwebrtc::WebRtcEndpoint> webRtc = std::static_pointer_cast<libwebrtc::WebRtcEndpoint>(mEndpoint);
606 for(
auto m = trickleIce.
media().cbegin(); m != trickleIce.
media().cend(); m++)
610 const Data& mid = m->getValues(
"mid").front();
611 const std::string _mid = mid.
c_str();
613 if(m->exists(
"candidate"))
615 auto candidates = m->getValues(
"candidate");
616 for(
auto a = candidates.cbegin(); a != candidates.cend(); a++)
618 webRtc->addIceCandidate([
this](){},
627 WarningLog(<<
"mid is missing for Medium in SDP fragment: " << trickleIce);
637 WarningLog(<<
"requestKeyframe not implemented for this media stack");
#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.
virtual void requestKeyframeFromPeer(ParticipantHandle partHandle, std::chrono::duration< double > durationMs)
virtual void requestKeyframe(ParticipantHandle partHandle, std::chrono::duration< double > durationMs)
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 LibWebRTCRemoteParticipant, LibWebRTCLocalParticipant and a LibWebRTCMed...
LibWebRTCMediaStackAdapter & mLibWebRTCMediaStackAdapter
virtual int getMediaConnectionId()
virtual LibWebRTCRemoteParticipantDialogSet & getLibWebRTCDialogSet()
bool mWSAcceptsKeyframeRequests
virtual void applyBridgeMixWeights() override
LibWebRTCRemoteParticipant(ParticipantHandle partHandle, ConversationManager &conversationManager, LibWebRTCMediaStackAdapter &libwebrtcMediaStackAdapter, resip::DialogUsageManager &dum, RemoteParticipantDialogSet &remoteParticipantDialogSet)
std::shared_ptr< libwebrtc::PassThroughElement > mPassThrough
virtual void addToConversation(Conversation *conversation, unsigned int inputGain=100, unsigned int outputGain=100) override
virtual void adjustRTPStreams(bool sendingOffer=false)
std::shared_ptr< libwebrtc::PlayerEndpoint > mPlayer
virtual int getConnectionPortOnBridge()
virtual std::shared_ptr< libwebrtc::MediaElement > getWaitingModeElement()
bool mRemoveExtraMediaDescriptors
virtual int getMediaConnectionId()
virtual bool mediaStackPortAvailable()
virtual bool onTrickleIce(resip::TrickleIceContents &trickleIce) override
virtual ~LibWebRTCRemoteParticipant()
virtual void waitingMode()
resip::SdpContents * mLastRemoteSdp
virtual bool onMediaControlEvent(resip::MediaControlContents::MediaControl &mediaControl)
virtual void removeFromConversation(Conversation *conversation) override
virtual void buildSdpOffer(bool holdSdp, CallbackSdpReady sdpReady, bool preferExistingSdp=false)
virtual void requestKeyframe() override
bool mTrickleIcePermitted
This is the base class for a RemoteParticipant, LocalParticipant and a MediaResourceParticipant.
virtual void unregisterFromAllConversations()
ParticipantHandle mHandle
ConversationManager & mConversationManager
This class is used by Invite DialogSets.
virtual std::shared_ptr< resip::SdpContents > getProposedSdp()
This class represent a remote participant.
void setProposedSdp(const resip::SdpContents &sdp)
void setRemoteSdp(const resip::SdpContents &sdp, bool answer=false)
virtual std::chrono::duration< double > getKeyframeRequestInterval() const
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 info(const resip::Contents &contents)
virtual void removeFromConversation(Conversation *conversation) override
std::shared_ptr< resip::SdpContents > getRemoteSdp()
virtual void requestKeyframeFromPeer()
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.
int convertInt() const
Takes the contents of the Data and converts them to an integer.
Represents the "media-type" element in the RFC 3261 grammar.
Provides an interface to process and generate SDP bodies (MIME content-type application/sdp).
const SdpContents::Session::MediumContainer & media() const
unsigned int ParticipantHandle
dcm! – add UnusedChecking(_enum) below;