rtphone/src/engine/endpoint/EP_Session.cpp

1153 lines
34 KiB
C++

/* Copyright(C) 2007-2017 VoIP objects (voipobjects.com)
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "EP_Session.h"
#include "EP_Engine.h"
#include "EP_AudioProvider.h"
#include "../media/MT_Stream.h"
#include "../media/MT_AudioStream.h"
#include "../media/MT_Dtmf.h"
#include "../helper/HL_Log.h"
#include "../helper/HL_Exception.h"
#include "../helper/HL_StreamState.h"
#include "../helper/HL_Sync.h"
#include "../helper/HL_String.h"
#define LOG_SUBSYSTEM "[Engine]"
typedef resip::SdpContents::Session::Medium Medium;
typedef resip::SdpContents::Session::MediumContainer MediumContainer;
#define DOMULTIPLEX() mUserAgent->mConfig[CONFIG_MULTIPLEXING].asBool() ? SocketHeap::DoMultiplexing : SocketHeap::DontMultiplexing
//------------ ResipSessionAppDialog ------------
#pragma region ResipSessionAppDialog
ResipSessionAppDialog::ResipSessionAppDialog(resip::HandleManager& ham) : AppDialog(ham)
{
}
ResipSessionAppDialog::~ResipSessionAppDialog()
{
}
#pragma endregion
#pragma region ResipSession
resip::AtomicCounter ResipSession::InstanceCounter;
ResipSession::ResipSession(resip::DialogUsageManager& dum)
: resip::AppDialogSet(dum), mUserAgent(NULL), mType(Type_None), mSessionId(0), mSession(0)
{
ResipSession::InstanceCounter.increment();
mTag = NULL;
mTerminated = false;
mOnWatchingStartSent = false;
mSessionId = Session::generateId();
}
ResipSession::~ResipSession()
{
try
{
// Detach from user session
if (mSession)
mSession->mResipSession = nullptr;
runTerminatedEvent(Type_Auto, 0, 0);
}
catch(...)
{
}
ResipSession::InstanceCounter.decrement();
}
resip::AppDialog* ResipSession::createAppDialog(const resip::SipMessage& msg)
{
return new ResipSessionAppDialog(static_cast<resip::HandleManager&>(mDum));
}
void ResipSession::runTerminatedEvent(Type type, int code, int reason)
{
if (mTerminated)
return;
Type t = type;
if (type == Type_Auto)
t = mType;
if (t == Type_None)
t = Type_Call;
mTerminated = true;
if (mUserAgent)
{
switch (t)
{
case Type_Call:
if (mSession)
mUserAgent->onSessionTerminated(mUserAgent->getUserSession(mSessionId), code, reason);
break;
case Type_Registration:
mUserAgent->onAccountStop(mUserAgent->getAccount(mSessionId), code);
break;
case Type_Subscription:
if (mSession)
{
UserAgent::ClientObserverMap::iterator observerIter = mUserAgent->mClientObserverMap.find(mSession->sessionId());
if (observerIter != mUserAgent->mClientObserverMap.end())
mUserAgent->onClientObserverStop(observerIter->second, code);
}
break;
default:
break;
}
}
}
std::string ResipSession::remoteAddress() const
{
return mRemoteAddress;
}
void ResipSession::setRemoteAddress(std::string address)
{
mRemoteAddress = address;
}
void ResipSession::setType(Type type)
{
mType = type;
}
ResipSession::Type ResipSession::type()
{
return mType;
}
Session* ResipSession::session()
{
return mSession;
}
void* ResipSession::tag() const
{
return mTag;
}
void ResipSession::setTag(void* tag)
{
mTag = tag;
}
void ResipSession::setSession(Session* session)
{
mSession = session;
if (mSession)
mSessionId = mSession->sessionId();
}
UserAgent* ResipSession::ua()
{
return mUserAgent;
}
void ResipSession::setUa(UserAgent* ua)
{
mUserAgent = ua;
}
int ResipSession::sessionId()
{
return mSessionId;
}
void ResipSession::setUASProfile(std::shared_ptr<resip::UserProfile> profile)
{
mUASProfile = profile;
}
resip::SharedPtr<resip::UserProfile> ResipSession::selectUASUserProfile(const resip::SipMessage& msg)
{
assert(mUserAgent != nullptr);
if (mUserAgent)
{
PAccount account = mUserAgent->getAccount(msg.header(resip::h_To));
if (account)
return account->getUserProfile();
else
return mUserAgent->mProfile;
}
return resip::SharedPtr<resip::UserProfile>();
}
#pragma endregion
#pragma region Session::Stream
Session::Stream::Stream()
:mRtcpAttr(false), mRtcpMuxAttr(false)
{
}
Session::Stream::~Stream()
{
}
void Session::Stream::setProvider(PDataProvider provider)
{
mProvider = provider;
}
PDataProvider Session::Stream::provider()
{
return mProvider;
}
void Session::Stream::setSocket4(const RtpPair<PDatagramSocket>& socket)
{
mSocket4 = socket;
}
RtpPair<PDatagramSocket>& Session::Stream::socket4()
{
return mSocket4;
}
void Session::Stream::setSocket6(const RtpPair<PDatagramSocket>& socket)
{
mSocket6 = socket;
}
RtpPair<PDatagramSocket>& Session::Stream::socket6()
{
return mSocket6;
}
void Session::Stream::setIceInfo(const IceInfo& ii)
{
mIceInfo = ii;
}
Session::IceInfo Session::Stream::iceInfo() const
{
return mIceInfo;
}
bool Session::Stream::rtcpAttr() const
{
return mRtcpAttr;
}
void Session::Stream::setRtcpAttr(bool value)
{
mRtcpAttr = value;
}
bool Session::Stream::rtcpMuxAttr() const
{
return mRtcpMuxAttr;
}
void Session::Stream::setRtcpMuxAttr(bool value)
{
mRtcpMuxAttr = value;
}
#pragma endregion
#pragma region Session
resip::AtomicCounter Session::InstanceCounter;
Session::Session(PAccount account)
{
InstanceCounter.increment();
mAccount = account;
mSessionId = Session::generateId();
mTag = NULL;
mAcceptedByEngine = false;
mAcceptedByUser = false;
mUserAgent = NULL;
mOriginVersion = 0;
mSessionVersion = 0;
mRole = Acceptor;
mGatheredCandidates = false;
mTerminated = false;
mRemoteOriginVersion = (UInt64)-1;
mResipSession = NULL;
mRefCount = 1;
mOfferAnswerCounter = 0;
mHasToSendOffer = false;
mSendOfferUpdateAfterIceGather = false;
}
Session::~Session()
{
try
{
if (mResipSession)
mResipSession->setSession(NULL);
clearProvidersAndSockets();
}
catch(...)
{}
InstanceCounter.decrement();
}
void Session::start(const std::string& peer)
{
ICELogInfo( << "Attempt to start session to " << peer);
Lock l(mGuard);
if (mResipSession)
{
ICELogError(<< "Session " << mSessionId << " is already started.");
return;
}
// Save target address
mRemoteAddress = UserAgent::formatSipAddress(peer);
// Create resiprocate session
mResipSession = new ResipSession(*mUserAgent->mDum);
mResipSession->setSession(this);
mResipSession->setUa(mUserAgent);
// Do not call OnNewSession for this session
mAcceptedByEngine = true;
// Mark session as Initiator
mRole = Session::Initiator;
resip::Data addrData(peer);
resip::NameAddr addr(addrData);
// Save target address
mRemotePeer = addr;
// Start to gather ICE candidates (streams are created in addProvider() method)
mIceStack->gatherCandidates();
}
void Session::stop()
{
ICELogInfo(<< "Stopping session " << mSessionId);
Lock l(mGuard);
for (unsigned i=0; i<mStreamList.size(); i++)
{
Session::Stream& dataStream = mStreamList[i];
if (dataStream.provider())
{
// Notify provider about finished I/O
dataStream.provider()->sessionTerminated();
// Free socket
SocketHeap::instance().freeSocketPair( dataStream.socket4() );
SocketHeap::instance().freeSocketPair( dataStream.socket6() );
}
}
if (mResipSession)
mResipSession->runTerminatedEvent(ResipSession::Type_Call, 0, LocalBye);
if (mResipSession)
mResipSession->end(); // Stop SIP session
}
void Session::accept()
{
ICELogInfo(<< "Attempt to accept session " << mSessionId);
Lock locksession(mGuard);
// If ICE candidate gathering is not finished - just mark session as accepted. It will be accepted in ICE handling code.
mAcceptedByUser = true;
if (mGatheredCandidates || mIceStack->state() == ice::IceNone)
{
ICELogInfo(<< "Candidates are gathered for session " << mSessionId << ", build&send answer.");
// Build SDP
resip::SdpContents sdp;
buildSdp(sdp, Sdp_Answer);
resip::ServerInviteSession* sis = dynamic_cast<resip::ServerInviteSession*>(mInviteHandle.get());
if (sis)
{
/*if (mInviteHandle.isValid())
mInviteHandle->setUserHeaders(mUserHeaders);*/
sis->setUserHeaders(mUserHeaders);
sis->provideAnswer(sdp);
sis->accept();
}
// Reset mAcceptScheduled & mGatheredCandidates
mGatheredCandidates = false;
// Start connectivity checks
if (mIceStack->state() > ice::IceNone)
{
ICELogInfo(<< "Start connectivity checks for session " << mSessionId);
mIceStack->checkConnectivity();
}
}
else
{
ICELogInfo(<< "ICE gathering is not finished yet for session " << mSessionId << " SDP build is deferred.");
}
}
void Session::reject(int code)
{
ICELogInfo( << "Attempt to reject session " << mSessionId);
Lock l(mGuard);
if (mInviteHandle.isValid())
{
mInviteHandle->reject(code);
ICELogInfo(<< "Session " << mSessionId << " is rejected.");
}
else
ICELogError(<< "Session " << mSessionId << " has not valid invite handle.");
}
AudioProvider* Session::findProviderForActiveAudio()
{
for (unsigned streamIndex = 0; streamIndex < mStreamList.size(); streamIndex++)
{
PDataProvider p = mStreamList[streamIndex].provider();
if (p)
{
if (p->streamName() == "audio")
{
AudioProvider* audio = (AudioProvider*)p.get();
if (audio->activeStream())
return audio;
}
}
}
return NULL;
}
void Session::getSessionInfo(Session::InfoOptions options, VariantMap& info)
{
Lock l(mGuard);
// Retrieve remote sip address
info[SessionInfo_RemoteSipAddress] = remoteAddress();
if (mIceStack)
info[SessionInfo_IceState] = mIceStack->state();
// Get media stats
MT::Statistics stat;
// Iterate all session providers
stat.reset();
Stream* media = NULL;
for (unsigned streamIndex = 0; streamIndex < mStreamList.size(); streamIndex++)
{
Stream& stream = mStreamList[streamIndex];
if (stream.provider())
{
media = &stream;
MT::Statistics s = stream.provider()->getStatistics();
#if defined(USE_PVQA_LIBRARY) && !defined(TARGET_SERVER)
if (options != InfoOptions::Standard)
{
// This information is available AFTER audio stream is deleted
info[SessionInfo_PvqaMos] = s.mPvqaMos;
info[SessionInfo_PvqaReport] = s.mPvqaReport;
}
#endif
info[SessionInfo_NetworkMos] = static_cast<float>(s.calculateMos(4.14));
info[SessionInfo_AudioCodec] = s.mCodecName;
stat += s;
}
}
info[SessionInfo_ReceivedTraffic] = static_cast<int>(stat.mReceived);
info[SessionInfo_SentTraffic] = static_cast<int>(stat.mSent);
info[SessionInfo_ReceivedRtp] = static_cast<int>(stat.mReceivedRtp);
info[SessionInfo_ReceivedRtcp] = static_cast<int>(stat.mReceivedRtcp);
info[SessionInfo_LostRtp] = static_cast<int>(stat.mPacketLoss);
info[SessionInfo_DroppedRtp] = static_cast<int>(stat.mPacketDropped);
info[SessionInfo_SentRtp] = static_cast<int>(stat.mSentRtp);
info[SessionInfo_SentRtcp] = static_cast<int>(stat.mSentRtcp);
if (stat.mFirstRtpTime)
info[SessionInfo_Duration] = static_cast<int>(std::chrono::duration_cast<std::chrono::seconds>(std::chrono::system_clock::now() - *(stat.mFirstRtpTime)).count());
else
info[SessionInfo_Duration] = 0;
if (stat.mReceivedRtp)
info[SessionInfo_PacketLoss] = static_cast<int>((stat.mPacketLoss * 1000) / stat.mReceivedRtp);
if (media)
info[SessionInfo_AudioPeer] = mIceStack->remoteAddress(media->iceInfo().mStreamId, media->iceInfo().mComponentId.mRtp).toStdString();
info[SessionInfo_Jitter] = stat.mJitter;
if (stat.mRttDelay.is_initialized())
info[SessionInfo_Rtt] = static_cast<float>(stat.mRttDelay * 1000);
#if defined(USE_AMR_CODEC)
info[SessionInfo_BitrateSwitchCounter] = stat.mBitrateSwitchCounter;
#endif
info[SessionInfo_SSRC] = stat.mSsrc;
info[SessionInfo_RemotePeer] = stat.mRemotePeer.toStdString();
}
int Session::id() const
{
return mSessionId;
}
PAccount Session::account()
{
return mAccount;
}
void Session::onReceivedData(PDatagramSocket socket, InternetAddress& src, const void* receivedPtr, unsigned receivedSize)
{
Lock l(mGuard);
if (mTerminated)
return;
// Check if it STUN packet and must be processed by ICE stack
//ICELogDebug (<< "Received UDP packet from " << src.ip() << ":" << src.port());
ice::ByteBuffer received(receivedPtr, receivedSize);
received.setRemoteAddress(src);
ice::ByteBuffer plain;
if (ice::Stack::isStun(received))
{
// Check if it is Data indication packet
if (ice::Stack::isDataIndication(received, &plain))
{
received = plain;
}
}
else // Check if packet is prefixed with TURN prefix
if (received.size() >= 4)
{
bool turnPrefix = false;
for (unsigned i=0; i<mTurnPrefixList.size() && !turnPrefix; i++)
turnPrefix |= ice::Stack::isChannelData(received, mTurnPrefixList[i]);
if (turnPrefix)
received.erase(0, 4);
}
// Now process actual stun packet - it could be wrapped in Data Indication or Channel Data
if (ice::Stack::isStun(received))
{
// Try to process incoming data by ICE stack
int component = -1, stream = -1;
bool processed;
if (mIceStack->findStreamAndComponent(socket->family(), socket->localport(), &stream, &component))
{
ice::ByteBuffer buffer(receivedPtr, receivedSize);
buffer.setRemoteAddress(src);
processed = mIceStack->processIncomingData(stream, component, buffer);
}
}
else
{
// Find provider responsible for processing
PDataProvider provider = this->findProviderByPort(socket->family(), socket->localport());
if (provider)
{
provider->processData(socket, receivedPtr, receivedSize, src);
}
else
{
// Just ignore these data
}
}
}
// Called when new candidate is gathered
void Session::onCandidateGathered(ice::Stack* stack, void* tag, const char* address)
{
mUserAgent->onCandidateGathered(mUserAgent->getUserSession(mSessionId), address);
}
// Called when connectivity check is finished
void Session::onCheckFinished(ice::Stack* stack, void* tag, const char* checkDescription)
{
mUserAgent->onCheckFinished(mUserAgent->getUserSession(mSessionId), checkDescription);
}
void Session::onGathered(ice::Stack* stack, void* tag)
{
Lock l(mGuard);
// This part handles situation when network was changed and new ice candidate were gathered
if (mSendOfferUpdateAfterIceGather)
{
mSendOfferUpdateAfterIceGather = false;
enqueueOffer();
return;
}
// This is sending of initial offer/answer after first gather of ice candidates
mUserAgent->onGathered(mUserAgent->getUserSession(mSessionId));
if (mRole == Initiator)
mUserAgent->sendOffer(this);
else
if (mRole == Acceptor)
{
// Mark session as gathered ICE candidates
mGatheredCandidates = true;
// if AcceptSession was already called() on session - recall it again to make real work
if (mAcceptedByUser)
{
// Check if session is needed here - because session can be terminated already
if (mResipSession && mInviteHandle.isValid())
accept();
}
}
}
void Session::onSuccess(ice::Stack* stack, void* tag)
{
ICELogInfo(<< "ICE connectivity check succeed.");
RtpPair<InternetAddress> t;
for (unsigned i=0; i<this->mStreamList.size(); i++)
{
PDataProvider p = mStreamList[i].provider();
if (p)
{
// Set new destination address
t.mRtp = stack->remoteAddress(mStreamList[i].iceInfo().mStreamId, ICE_RTP_ID);
// Check if there remote address for rtcp component
t.mRtcp = stack->remoteAddress(mStreamList[i].iceInfo().mStreamId, ICE_RTCP_ID);
if (t.mRtcp.isEmpty())
t.mRtcp = t.mRtp;
p->setDestinationAddress(t);
// Notify provider about connectivity checks success
mStreamList[i].provider()->sessionEstablished(EV_ICE);
}
}
mUserAgent->onSessionEstablished(mUserAgent->getUserSession(mSessionId), EV_ICE, t);
//time to resend updated media info over SIP
//TODO:
}
void Session::onFailed(ice::Stack* stack, void* tag)
{
ICELogError(<< "ICE connectivity check failed for session " << mSessionId);
mUserAgent->onConnectivityFailed(mUserAgent->getUserSession(mSessionId));
//if (mInviteHandle.isValid())
// mInviteHandle->end();
}
void Session::onNetworkChange(ice::Stack *stack, void *tag)
{
ICELogInfo(<< "Network change detected by ICE stack for session " << mSessionId);
mUserAgent->onNetworkChange(mUserAgent->getUserSession(mSessionId));
}
void Session::buildSdp(resip::SdpContents &sdp, SdpDirection sdpDirection)
{
sdp.session().name() = "ICE_UA";
sdp.session().origin().user() = "user";
// Set versions
sdp.version() = 0;
sdp.session().version() = mSessionVersion;
sdp.session().origin().getVersion() = ++mOriginVersion;
// At least 1 stream must exists
if (mStreamList.empty())
return;
// Get default ip address for front stream
ice::NetworkAddress defaultAddr = mIceStack->defaultAddress(mStreamList.front().iceInfo().mStreamId, ICE_RTP_ID);
// Set IP address for origin and connection
sdp.session().origin().setAddress(resip::Data(defaultAddr.ip()), defaultAddr.family() == AF_INET ? resip::SdpContents::IP4 : resip::SdpContents::IP6);
sdp.session().connection().setAddress(resip::Data(defaultAddr.ip()), defaultAddr.family() == AF_INET ? resip::SdpContents::IP4 : resip::SdpContents::IP6);
// Add ICE credentials
if (mIceStack->state() > ice::IceNone)
{
sdp.session().addAttribute("ice-pwd", resip::Data(mIceStack->localPassword()));
sdp.session().addAttribute("ice-ufrag", resip::Data(mIceStack->localUfrag()));
}
// Iterate media streams
for (unsigned i=0; i<mStreamList.size(); i++)
{
Stream& stream = mStreamList[i];
if (!stream.provider())
continue;
DataProvider& provider = *mStreamList[i].provider();
// Get default stream port
ice::NetworkAddress rtpPort = mIceStack->defaultAddress(mStreamList[i].iceInfo().mStreamId, ICE_RTP_ID),
rtcpPort = mIceStack->defaultAddress(mStreamList[i].iceInfo().mStreamId, ICE_RTCP_ID);
// Define media stream SDP's header
resip::SdpContents::Session::Medium media(resip::Data(provider.streamName()), rtpPort.port(), 0, resip::Data(provider.streamProfile()));
// Add "rtcp" attribute
if (mUserAgent->mConfig[CONFIG_RTCP_ATTR].asBool())
{
if (mUserAgent->mConfig[CONFIG_MULTIPLEXING].asBool())
rtcpPort = rtpPort;
else
if (rtcpPort.isEmpty())
{
rtcpPort = rtpPort;
rtcpPort.setPort( rtpPort.port() + 1);
}
media.addAttribute("rtcp", resip::Data(rtcpPort.port()));
}
// Add "rtcp-mux" attribute
if (mUserAgent->mConfig[CONFIG_MULTIPLEXING].asBool())
media.addAttribute("rtcp-mux");
// Ask provider about specific information - codecs are filled here
provider.updateSdpOffer(media, sdpDirection);
// Add ICE information
std::vector<std::string> candidates;
if (stream.iceInfo().mStreamId != -1)
{
IceInfo ii = stream.iceInfo();
mIceStack->fillCandidateList(ii.mStreamId, ii.mComponentId.mRtp, candidates);
if (mIceStack->hasComponent(ii.mStreamId, ii.mComponentId.mRtcp))
mIceStack->fillCandidateList(ii.mStreamId, ii.mComponentId.mRtcp, candidates);
for (unsigned c=0; c<candidates.size(); c++)
media.addAttribute("candidate", candidates[c].c_str());
}
// Add stream to session
sdp.session().addMedium(media);
}
}
PDataProvider Session::findProviderByPort(int family, unsigned short port)
{
for (unsigned i = 0; i < mStreamList.size(); i++)
{
Stream& s = mStreamList[i];
if ((s.socket4().mRtp->localport() == port || s.socket4().mRtcp->localport() == port) && family == AF_INET)
return s.provider();
if ((s.socket6().mRtp->localport() == port || s.socket6().mRtcp->localport() == port) && family == AF_INET6)
return s.provider();
}
return PDataProvider();
}
void Session::addProvider(PDataProvider provider)
{
// Ignore NULL providers
if (!provider)
return;
// Avoid duplicating providers
for (unsigned i=0; i<mStreamList.size(); i++)
if (mStreamList[i].provider() == provider)
return;
// Find first non-filled record or create new one
std::vector<Stream>::iterator streamIter;
for (streamIter = mStreamList.begin(); streamIter != mStreamList.end(); ++streamIter)
{
if (!streamIter->provider() && (streamIter->socket4().mRtp->isValid() || streamIter->socket6().mRtp->isValid()))
{
streamIter->setProvider( provider );
provider->setSocket(streamIter->socket4(), streamIter->socket6());
return;
}
}
Stream s;
s.setProvider( provider );
// Allocate socket for provider
s.setSocket4( SocketHeap::instance().allocSocketPair(AF_INET, this, DOMULTIPLEX()) );
s.setSocket6( SocketHeap::instance().allocSocketPair(AF_INET6, this, DOMULTIPLEX()) );
s.provider()->setSocket(s.socket4(), s.socket6());
// Create ICE stream/component
IceInfo ii;
ii.mStreamId = mIceStack->addStream();
ii.mPort4 = s.socket4().mRtp->localport();
ii.mPort6 = s.socket6().mRtp->localport();
ii.mComponentId.mRtp = mIceStack->addComponent(ii.mStreamId, NULL, s.socket4().mRtp->localport(),
s.socket6().mRtp->localport());
if (!mUserAgent->mConfig[CONFIG_MULTIPLEXING].asBool())
ii.mComponentId.mRtcp = mIceStack->addComponent(ii.mStreamId, NULL, s.socket4().mRtcp->localport(), s.socket6().mRtcp->localport());
s.setIceInfo(ii);
mStreamList.push_back(s);
}
PDataProvider Session::providerAt(int index)
{
if (mStreamList.size() > unsigned(index))
return mStreamList[index].provider();
return PDataProvider();
}
int Session::getProviderCount()
{
return mStreamList.size();
}
int Session::sessionId()
{
return mSessionId;
}
resip::AtomicCounter Session::IdGenerator;
int Session::generateId()
{
return (int)IdGenerator.increment();
}
std::string Session::remoteAddress() const
{
return mRemoteAddress;
}
void Session::setRemoteAddress(const std::string& address)
{
mRemoteAddress = address;
}
void Session::setUserHeaders(const UserHeaders& headers)
{
mUserHeaders = headers;
}
void* Session::tag()
{
return mTag;
}
void Session::setTag(void* tag)
{
mTag = tag;
}
void Session::pause()
{
for (unsigned i=0; i<mStreamList.size(); i++)
{
Stream& s = mStreamList[i];
if (s.provider())
s.provider()->pause();
}
enqueueOffer();
}
void Session::resume()
{
for (unsigned i=0; i<mStreamList.size(); i++)
{
Stream& s = mStreamList[i];
if (s.provider())
s.provider()->resume();
}
enqueueOffer();
}
void Session::refreshMediaPath()
{
// Recreate media sockets
for (unsigned i=0; i<mStreamList.size(); i++)
{
Stream& s= mStreamList[i];
PDataProvider p = s.provider();
if (!p)
continue;
// Close old socket
SocketHeap::instance().freeSocketPair(p->socket(AF_INET));
// Bring new socket to provider and stream
RtpPair<PDatagramSocket> s4 = SocketHeap::instance().allocSocketPair(AF_INET, this, DOMULTIPLEX() ),
s6 = SocketHeap::instance().allocSocketPair(AF_INET, this, DOMULTIPLEX());
p->setSocket(s4, s6);
s.setSocket4(s4);
s.setSocket6(s6);
}
// Recreate new ufrag/pwd and gather ice candidates
mIceStack->refreshPwdUfrag();
mIceStack->gatherCandidates();
// New offer will be enqueued after ice gather finished
mSendOfferUpdateAfterIceGather = true;
mHasToSendOffer = false;
}
// Received offer with new SDP
int Session::processSdp(UInt64 version, bool iceAvailable, std::string icePwd, std::string iceUfrag,
std::string remoteIp, const resip::SdpContents::Session::MediumContainer& media)
{
bool iceRestart = false;
int mediaCompatible = 0;
MediumContainer::const_iterator mediaIter;
unsigned streamIndex = 0;
for (mediaIter = media.begin(); mediaIter != media.end(); ++mediaIter, ++streamIndex)
{
// Get reference to SDP description of remote stream
const resip::SdpContents::Session::Medium& remoteStream = *mediaIter;
// Get reference to local stream description
if (streamIndex >= mStreamList.size())
mStreamList.push_back(Session::Stream());
Session::Stream& stream = mStreamList[streamIndex];
// Ask about provider if needed
if (!stream.provider())
stream.setProvider( mUserAgent->onProviderNeeded(remoteStream.name().c_str()) );
// Check the stream validity
if (!stream.provider())
continue;
if (!stream.provider()->processSdpOffer(remoteStream, Sdp_Offer))
continue;
// See for rtcp & rtcp-mux attribute
stream.setRtcpAttr( remoteStream.exists("rtcp") );
stream.setRtcpMuxAttr( remoteStream.exists("rtcp-mux") );
// Set destination address
if (!remoteStream.getConnections().empty())
remoteIp = remoteStream.getConnections().front().getAddress().c_str();
RtpPair<InternetAddress> targetAddr;
targetAddr.mRtp.setIp(remoteIp);
targetAddr.mRtp.setPort(remoteStream.port());
targetAddr.mRtcp.setIp(remoteIp);
if (stream.rtcpMuxAttr())
targetAddr.mRtcp.setPort( remoteStream.port() );
else
if (stream.rtcpAttr())
targetAddr.mRtcp.setPort( StringHelper::toInt(remoteStream.getValues("rtcp").front().c_str(), remoteStream.port() + 1 ) );
else
targetAddr.mRtcp.setPort( remoteStream.port() + 1);
stream.provider()->setDestinationAddress(targetAddr);
// Media is compatible; increase the counter and prepare ice stream/component
mediaCompatible++;
// Get default remote port number
unsigned short remotePort = remoteStream.port();
// Create media socket if needed
if (!stream.socket4().mRtp)
{
try
{
stream.setSocket4(SocketHeap::instance().allocSocketPair(AF_INET, this, DOMULTIPLEX()));
stream.setSocket6(SocketHeap::instance().allocSocketPair(AF_INET6, this, DOMULTIPLEX()));
}
catch(...)
{
ICELogError( << "Cannot create media socket.");
return 503;
}
// Update provider with socket references
stream.provider()->setSocket(stream.socket4(), stream.socket6());
}
const std::list<resip::Data>& iceUfragAttr = remoteStream.getValues("ice-ufrag");
if (iceUfragAttr.size())
iceUfrag = iceUfragAttr.front().c_str();
const std::list<resip::Data>& icePwdAttr = remoteStream.getValues("ice-pwd");
if (icePwdAttr.size())
icePwd = icePwdAttr.front().c_str();
// Create ICE stream; it will be created even if ice is not requested.
// The cause is we need to hold default address and possible STUN requests result
if (stream.iceInfo().mStreamId == -1)
{
IceInfo ii;
ii.mStreamId = mIceStack->addStream();
ii.mPort4 = stream.socket4().mRtp->localport();
ii.mPort6 = stream.socket6().mRtp->localport();
ii.mComponentId.mRtp = mIceStack->addComponent(ii.mStreamId, NULL, ii.mPort4, ii.mPort6);
// See what remote peer offers - offer only single ice component if it relies on multiplexing
if (!targetAddr.multiplexed() && !mUserAgent->mConfig[CONFIG_MULTIPLEXING].asBool())
ii.mComponentId.mRtcp = mIceStack->addComponent(ii.mStreamId, NULL, stream.socket4().mRtcp->localport(), stream.socket6().mRtcp->localport());
stream.setIceInfo(ii);
}
if (iceAvailable)
{
if (mIceStack->remotePassword(stream.iceInfo().mStreamId) != icePwd || mIceStack->remoteUfrag(stream.iceInfo().mStreamId) != iceUfrag)
{
iceRestart = true;
mIceStack->setRemotePassword(icePwd, stream.iceInfo().mStreamId);
mIceStack->setRemoteUfrag(iceUfrag, stream.iceInfo().mStreamId);
}
}
// Get remote ICE candidates vector
const std::list<resip::Data> candidateList = remoteStream.getValues("candidate");
// Repackage information about remote candidates
std::vector<std::string> candidateVector;
std::list<resip::Data>::const_iterator cit = candidateList.begin();
for (; cit != candidateList.end(); ++cit)
candidateVector.push_back(cit->c_str());
if (candidateVector.empty())
iceAvailable = false;
// Ask ICE stack to process this information. This call will remove also second component if it is not defined in remote sdp.
if (iceAvailable)
iceAvailable = mIceStack->processSdpOffer(stream.iceInfo().mStreamId, candidateVector, remoteIp, remotePort, mUserAgent->mConfig[CONFIG_DEFERRELAYED].asBool());
}
// See if there are compatible media streams
if (!mediaCompatible)
return 488; // Not acceptable media
// Start ICE check connectivity if required
if (iceRestart && iceAvailable)
{
if (mIceStack->state() > ice::IceGathering)
mIceStack->checkConnectivity();
else
mIceStack->gatherCandidates();
}
return 200;
}
int Session::increaseSdpVersion()
{
return ++mOriginVersion;
}
void Session::setUserAgent(UserAgent* agent)
{
mUserAgent = agent;
}
UserAgent* Session::userAgent()
{
return mUserAgent;
}
int Session::addRef()
{
return ++mRefCount;
}
int Session::release()
{
mRefCount--;
return mRefCount;
}
void Session::clearProvidersAndSockets()
{
for (unsigned i=0; i<mStreamList.size(); i++)
{
Session::Stream& ds = mStreamList[i];
if (ds.provider())
{
ds.provider()->sessionDeleted();
SocketHeap::instance().freeSocketPair( ds.socket4() );
SocketHeap::instance().freeSocketPair( ds.socket6() );
}
}
}
void Session::clearProviders()
{
for (unsigned i=0; i<mStreamList.size(); i++)
{
Session::Stream& ds = mStreamList[i];
if (ds.provider())
ds.provider()->sessionTerminated();
}
}
#pragma endregion
void Session::enqueueOffer()
{
mHasToSendOffer = true;
processQueuedOffer();
}
void Session::processQueuedOffer()
{
if (!mHasToSendOffer)
return;
if (mInviteHandle.isValid())
{
if (mInviteHandle->canProvideOffer())
{
mUserAgent->sendOffer(this);
mHasToSendOffer = false;
}
}
}
//-------------- ResipSessionFactory ---------
#pragma region ResipSessionFactory
ResipSessionFactory::ResipSessionFactory(UserAgent* agent)
:mAgent(agent)
{}
resip::AppDialogSet* ResipSessionFactory::createAppDialogSet(resip::DialogUsageManager& dum, const resip::SipMessage& msg)
{
ResipSession* s = new ResipSession(dum);
s->setUa( mAgent );
return s;
}
#pragma endregion