Avoid resetting started RTP when handling re-invite/update containing currently used codec.

git-svn-id: http://yate.null.ro/svn/yate/trunk@6420 acf43c95-373e-0410-b603-e72c3f656dc1
This commit is contained in:
marian 2020-08-21 13:58:46 +00:00
parent 80cfdf66de
commit 6031f15896
4 changed files with 128 additions and 25 deletions

View File

@ -66,6 +66,54 @@ const char* SDPMedia::fmtList() const
return 0;
}
// Compare this media with another one
bool SDPMedia::sameAs(const SDPMedia* other, bool ignorePort, bool checkStarted) const
{
if (!other)
return false;
const SDPMedia& m = *other;
if (m.transport() != m_transport)
return false;
if (m.remotePort() != m_rPort)
return false;
checkStarted = checkStarted && isStarted();
if (!checkStarted) {
return (m.formats() == m_formats) &&
((ignorePort && m.remotePort() && m_rPort) || (m.remotePort() == m_rPort));
}
// Check format
ObjList* lst = m.formats().split(',',false);
bool found = lst->find(m_format);
TelEngine::destruct(lst);
if (!found) {
XDebug(DebugAll,"SDPMedia::sameAs(%p) format='%s' other_formats='%s': not found [%p]",
other,m_format.c_str(),m.formats().c_str(),this);
return false;
}
// Check payload format
int pLoad = SDPMedia::payloadMapping(mappings(),m_format);
int oPLoad = SDPMedia::payloadMapping(m.mappings(),m_format);
if (pLoad == -1 || oPLoad == -1 || pLoad != oPLoad) {
XDebug(DebugAll,
"SDPMedia::sameAs(%p) format='%s' pload=%d (%s) other_pload=%d (%s): not matched [%p]",
other,m_format.c_str(),pLoad,mappings().c_str(),oPLoad,m.mappings().c_str(),this);
return false;
}
// Check RFC 2833
if (m_rfc2833 != m.m_rfc2833) {
XDebug(DebugAll,
"SDPMedia::sameAs(%p) rfc2833=%s other_rfc2833=%s: not matched [%p]",
other,m_rfc2833.c_str(),m.m_rfc2833.c_str(),this);
return false;
}
// TODO: Check crypto
return true;
}
// Update members with data taken from a SDP, return true if something changed
bool SDPMedia::update(const char* formats, int rport, int lport, bool force)
{
@ -210,6 +258,40 @@ void SDPMedia::putMedia(NamedList& msg, bool putPort)
}
}
// Copy RTP related data from old media
void SDPMedia::keepRtp(const SDPMedia& other)
{
m_formats = other.m_formats;
m_format = other.m_format;
m_rfc2833 = other.m_rfc2833;
m_id = other.m_id;
m_rPort = other.m_rPort;
m_lPort = other.m_lPort;
crypto(other.m_rCrypto,true);
crypto(other.m_lCrypto,false);
}
int SDPMedia::payloadMapping(const String& mappings, const String& fmt)
{
if (!(mappings && fmt))
return -2;
String tmp = fmt;
tmp << "=";
ObjList* lst = mappings.split(',',false);
int payload = -2;
for (ObjList* pl = lst; pl; pl = pl->next()) {
String* mapping = static_cast<String*>(pl->get());
if (!mapping)
continue;
if (mapping->startsWith(tmp)) {
payload = mapping->substr(tmp.length()).toInteger(-1);
break;
}
}
TelEngine::destruct(lst);
return payload;
}
}; // namespace TelEngine
/* vi: set ts=8 sw=4 sts=4 noet: */

View File

@ -56,7 +56,7 @@ SDPSession::~SDPSession()
}
// Set new media list. Return true if changed
bool SDPSession::setMedia(ObjList* media)
bool SDPSession::setMedia(ObjList* media, bool preserveExisting)
{
if (media == m_rtpMedia)
return false;
@ -68,8 +68,19 @@ bool SDPSession::setMedia(ObjList* media)
chg = false;
for (ObjList* o = tmp->skipNull(); o; o = o->skipNext()) {
SDPMedia* m = static_cast<SDPMedia*>(o->get());
if (media && m->sameAs(static_cast<SDPMedia*>((*media)[*m]),m_parser->ignorePort()))
continue;
if (media) {
ObjList* l = media->find(*m);
SDPMedia* newMedia = l ? static_cast<SDPMedia*>(l->get()) : 0;
if (newMedia && m->sameAs(newMedia,m_parser->ignorePort(),preserveExisting)) {
if (preserveExisting && m->isStarted()) {
XDebug(m_enabler,DebugAll,
"SDPSession::setMedia(%p) keeping existing media='%s' format='%s' [%p]",
media,m->c_str(),m->format().c_str(),m_ptr);
newMedia->keepRtp(*m);
}
continue;
}
}
chg = true;
mediaChanged(*m);
}
@ -843,22 +854,10 @@ Message* SDPSession::buildChanRtp(SDPMedia* media, const char* addr, bool start,
m->addParam("remoteip",addr);
if (start) {
m->addParam("remoteport",media->remotePort());
String tmp = media->format();
tmp << "=";
ObjList* mappings = media->mappings().split(',',false);
for (ObjList* pl = mappings; pl; pl = pl->next()) {
String* mapping = static_cast<String*>(pl->get());
if (!mapping)
continue;
if (mapping->startsWith(tmp)) {
tmp = *mapping;
tmp >> "=";
m->addParam("payload",tmp);
break;
}
}
int payload = SDPMedia::payloadMapping(media->mappings(),media->format());
if (payload >= 0)
m->addParam("payload",String(payload));
m->addParam("evpayload",media->rfc2833());
TelEngine::destruct(mappings);
}
if (m_secure) {
if (media->remoteCrypto()) {

View File

@ -112,6 +112,13 @@ public:
inline const String& suffix() const
{ return m_suffix; }
/**
* Check if media is started
* @return True if started, false otherwise
*/
inline bool isStarted() const
{ return m_id && m_transport && m_format && m_lPort; }
/**
* Retrieve the media transport name
* @return The media transport name
@ -213,13 +220,10 @@ public:
* Compare this media with another one
* @param other The media to compare with
* @param ignorePort Ignore differences caused only by port number
* @param checkStarted Check started related parameters: true when media should be kept if started and matched
* @return True if both media have the same formats, transport and remote port
*/
inline bool sameAs(const SDPMedia* other, bool ignorePort = false) const
{ return other && (other->formats() == m_formats) &&
(other->transport() == m_transport) &&
((ignorePort && other->remotePort() && m_rPort) ||
(other->remotePort() == m_rPort)); }
bool sameAs(const SDPMedia* other, bool ignorePort = false, bool checkStarted = false) const;
/**
* Check if local part of this media changed
@ -289,6 +293,21 @@ public:
*/
void putMedia(NamedList& msg, bool putPort = true);
/**
* Copy RTP related data from old media
* @param msg Destination list
* @param putPort True to add remote media port
*/
void keepRtp(const SDPMedia& other);
/**
* Retrieve format mapping to payload
* @param mappings Mappings list
* @param fmt Format name
* @return -1:incorrect mapping value, -2:format not found, payload number otherwise (>=0)
*/
static int payloadMapping(const String& mappings, const String& fmt);
private:
bool m_audio;
bool m_video;
@ -373,9 +392,10 @@ public:
/**
* Set a new media list
* @param media New media list
* @param preserveExisting Try to preserve existing started media
* @return True if media changed
*/
bool setMedia(ObjList* media);
bool setMedia(ObjList* media, bool preserveExisting = false);
/**
* Put specified media parameters into a list of parameters

View File

@ -7490,6 +7490,7 @@ bool YateSIPConnection::reInviteProxy(SIPTransaction* t, MimeSdpBody* sdp, int i
bool audioChg = (getMedia(YSTRING("audio")) != 0);
audioChg ^= ((*lst)[YSTRING("audio")] != 0);
bool keepExisting = true;
Message ver("call.update");
if (s_update_verify) {
complete(ver);
@ -7513,6 +7514,7 @@ bool YateSIPConnection::reInviteProxy(SIPTransaction* t, MimeSdpBody* sdp, int i
m_reInviting = invite;
return true;
}
keepExisting = ver.getBoolValue(YSTRING("keep_media"),keepExisting);
}
if (m_rtpAddr != addr) {
@ -7522,7 +7524,7 @@ bool YateSIPConnection::reInviteProxy(SIPTransaction* t, MimeSdpBody* sdp, int i
if (!s_rtp_preserve)
setMedia(0);
}
setMedia(lst);
setMedia(lst,keepExisting);
m_mediaStatus = MediaMissing;
// let RTP guess again the local interface or use the enforced address