Implemented the new Jingle specifications.

git-svn-id: http://yate.null.ro/svn/yate/trunk@2382 acf43c95-373e-0410-b603-e72c3f656dc1
This commit is contained in:
marian 2008-12-01 00:37:18 +00:00
parent 80d0d5ec88
commit 6a28081b7e
10 changed files with 2144 additions and 907 deletions

View File

@ -3,6 +3,10 @@
[general]
; Global settings of Jabber and Jingle engines
; secure_rtp: boolean: Offer SRTP when negotiating Jingle sessions
; Defaults to disable
;secure_rtp=disable
; singletone: boolean: Send chan tones as single characters.
; If disabled, the whole text received as chan tone(s) will be sent
; in the same XML element

View File

@ -341,7 +341,12 @@ void JBEngine::initialize(const NamedList& params)
else
m_identity = new JIDIdentity(JIDIdentity::Account,JIDIdentity::AccountRegistered);
m_features.add(XMPPNamespace::Jingle);
m_features.add(XMPPNamespace::JingleAudio);
m_features.add(XMPPNamespace::JingleError);
m_features.add(XMPPNamespace::JingleAppsRtp);
m_features.add(XMPPNamespace::JingleAppsRtpInfo);
m_features.add(XMPPNamespace::JingleTransportIceUdp);
m_features.add(XMPPNamespace::JingleTransportRawUdp);
m_features.add(XMPPNamespace::JingleTransfer);
m_features.add(XMPPNamespace::Dtmf);
m_features.add(XMPPNamespace::DiscoInfo);

View File

@ -44,7 +44,7 @@ TokenDict JGEvent::s_typeName[] = {
*/
JGEngine::JGEngine(JBEngine* engine, const NamedList* params, int prio)
: JBService(engine,"jgengine",params,prio), m_sessionIdMutex(true),
m_sessionId(1), m_stanzaTimeout(20000), m_useSidAttr(false)
m_sessionId(1), m_stanzaTimeout(20000)
{
JBThreadList::setOwner(this);
}
@ -65,12 +65,10 @@ void JGEngine::initialize(const NamedList& params)
if (timeout < 10)
timeout = 10;
m_stanzaTimeout = timeout * 1000;
m_useSidAttr = params.getBoolValue("session_sid",false);
if (debugAt(DebugInfo)) {
String s;
s << " stanza_timeout=" << (unsigned int)m_stanzaTimeout;
s << " session_sid=" << m_useSidAttr;
Debug(this,DebugInfo,"Jabber Jingle service initialized:%s [%p]",
s.c_str(),this);
}
@ -85,8 +83,7 @@ void JGEngine::initialize(const NamedList& params)
// Make an outgoing call
JGSession* JGEngine::call(const String& localJID, const String& remoteJID,
XMLElement* media, XMLElement* transport, XMLElement* extra,
const char* message)
const ObjList& contents, XMLElement* extra, const char* message)
{
DDebug(this,DebugAll,"New outgoing call from '%s' to '%s'",
localJID.c_str(),remoteJID.c_str());
@ -102,24 +99,24 @@ JGSession* JGEngine::call(const String& localJID, const String& remoteJID,
}
// Create outgoing session
if (stream) {
bool hasStream = (0 != stream);
if (hasStream) {
JGSession* session = new JGSession(this,stream,localJID,remoteJID,
media,transport,m_useSidAttr,extra,message);
contents,extra,message);
TelEngine::destruct(stream);
if (session->state() != JGSession::Destroy) {
Lock lock(this);
m_sessions.append(session);
return (session && session->ref() ? session : 0);
return (session && session->ref()) ? session : 0;
}
TelEngine::destruct(session);
}
else {
TelEngine::destruct(media);
TelEngine::destruct(transport);
else
TelEngine::destruct(extra);
}
Debug(this,DebugNote,"Outgoing call from '%s' to '%s' failed: %s",
localJID.c_str(),remoteJID.c_str(),
!stream?"can't create stream":"failed to send data");
!hasStream? "can't create stream" : "failed to send data");
return 0;
}
@ -162,19 +159,6 @@ void JGEngine::defProcessEvent(JGEvent* event)
delete event;
}
// Utility: get the (s)id attribute: the session id
static inline bool getSid(XMLElement* xml, String& sid, bool& useSid)
{
if (!xml)
return false;
sid = xml->getAttribute("id");
if (!sid) {
sid = xml->getAttribute("sid");
useSid = true;
}
return !sid.null();
}
// Accept an event from the Jabber engine
bool JGEngine::accept(JBEvent* event, bool& processed, bool& insert)
{
@ -185,7 +169,6 @@ bool JGEngine::accept(JBEvent* event, bool& processed, bool& insert)
const char* errorText = 0;
bool respond = true;
String sid;
bool useSid = false;
Lock lock(this);
switch (event->type()) {
case JBEvent::IqJingleGet:
@ -199,9 +182,9 @@ bool JGEngine::accept(JBEvent* event, bool& processed, bool& insert)
return false;
}
// Jingle clients may send the session id as 'id' or 'sid'
getSid(child,sid,useSid);
DDebug(this,DebugAll,"Accepting event=%s child=%s id=%s useSid=%s",
event->name(),child->name(),sid.c_str(),String::boolText(useSid));
sid = child->getAttribute("sid");
DDebug(this,DebugAll,"Accepting event=%s child=%s sid=%s",
event->name(),child->name(),sid.c_str());
if (sid.null()) {
error = XMPPError::SBadRequest;
errorText = "Missing or empty session id";
@ -228,7 +211,7 @@ bool JGEngine::accept(JBEvent* event, bool& processed, bool& insert)
DDebug(this,DebugAll,"New incoming call from=%s to=%s sid=%s",
event->from().c_str(),event->to().c_str(),sid.c_str());
if (event->ref())
m_sessions.append(new JGSession(this,event,sid,useSid));
m_sessions.append(new JGSession(this,event,sid));
processed = true;
return true;
}

File diff suppressed because it is too large Load Diff

View File

@ -54,7 +54,7 @@ TokenDict XMLElement::s_names[] = {
{"error", Error},
{"query", Query},
{"vCard", VCard},
{"session", Jingle},
{"jingle", Jingle},
{"description", Description},
{"payload-type", PayloadType},
{"transport", Transport},
@ -83,6 +83,12 @@ TokenDict XMLElement::s_names[] = {
{"item", Item},
{"group", Group},
{"reason", Reason},
{"content", Content},
{"parameter", Parameter},
{"crypto", Crypto},
{"crypto-required", CryptoRequired},
{"trying", Trying},
{"received", Received},
{0,0}
};
@ -243,6 +249,16 @@ const char* XMLElement::getAttribute(const char* name) const
return 0;
}
// Fill a list with element's attributes
void XMLElement::getAttributes(NamedList& dest) const
{
if (!valid())
return;
const TiXmlAttribute* attr = m_element->FirstAttribute();
for (; attr; attr = attr->Next())
dest.addParam(attr->Name(),attr->Value());
}
bool XMLElement::hasAttribute(const char* name, const char* value) const
{
String tmp;

View File

@ -128,6 +128,12 @@ public:
Item, // item
Group, // group
Reason, // reason
Content, // content
Parameter, // parameter
Crypto, // crypto
CryptoRequired, // crypto-required
Trying, // trying
Received, // received
Unknown, // Any text
Invalid, // m_element is 0
};
@ -285,6 +291,12 @@ public:
return 0 != value.length();
}
/**
* Fill a list with element's attributes
* @param dest The destination list
*/
void getAttributes(NamedList& dest) const;
/**
* Check if an attribute with the given name and value exists
* @param name Attribute's name
@ -445,6 +457,11 @@ public:
static XMLElement* getXml(NamedList& list, bool stole = false,
const char* name = "xml", const char* value = 0);
/**
* Associations between XML element name and type
*/
static TokenDict s_names[];
protected:
/**
* Constructor.
@ -471,11 +488,6 @@ protected:
*/
TiXmlElement* releaseOwnership();
/**
* Associations between XML element name and type
*/
static TokenDict s_names[];
private:
// Set this object's type from m_element's name
inline void setType() {

View File

@ -67,17 +67,19 @@ TokenDict XMPPNamespace::s_value[] = {
{"urn:ietf:params:xml:ns:xmpp-session", Session},
{"urn:ietf:params:xml:ns:xmpp-bind", Bind},
{"jabber:iq:roster", Roster},
{"jabber:iq:roster-dynamic", DynamicRoster},
{"http://jabber.org/protocol/disco#info", DiscoInfo},
{"http://jabber.org/protocol/disco#items", DiscoItems},
{"vcard-temp", VCard},
{"http://www.google.com/session", Jingle},
{"urn:xmpp:jingle:errors", JingleError},
{"http://www.google.com/session/phone", JingleAudio},
{"http://www.google.com/transport/p2p", JingleTransport},
{"urn:xmpp:jingle:transfer", JingleTransfer},
{"urn:xmpp:jingle:apps:rtp:info", JingleRtpInfo},
{"http://jabber.org/protocol/jingle/info/dtmf", Dtmf},
{"http://jabber.org/protocol/jingle/info/dtmf#errors", DtmfError},
{"xmlns='urn:xmpp:jingle:0", Jingle},
{"urn:xmpp:jingle:errors:0", JingleError},
{"urn:xmpp:jingle:apps:rtp:0", JingleAppsRtp},
{"urn:xmpp:jingle:apps:rtp:info:0", JingleAppsRtpInfo},
{"urn:xmpp:jingle:transports:ice-udp:0", JingleTransportIceUdp},
{"urn:xmpp:jingle:transports:raw-udp:0", JingleTransportRawUdp},
{"urn:xmpp:jingle:transports:raw-udp:info:0", JingleTransportRawUdpInfo},
{"urn:xmpp:jingle:transfer:0", JingleTransfer},
{"urn:xmpp:jingle:dtmf:0", Dtmf},
{"http://jabber.org/protocol/commands", Command},
{"http://www.google.com/xmpp/protocol/voice/v1", CapVoiceV1},
{0,0}

View File

@ -193,17 +193,19 @@ public:
Session, // urn:ietf:params:xml:ns:xmpp-session
Bind, // urn:ietf:params:xml:ns:xmpp-bind
Roster, // jabber:iq:roster
DynamicRoster, // jabber:iq:roster-dynamic
DiscoInfo, // http://jabber.org/protocol/disco#info
DiscoItems, // http://jabber.org/protocol/disco#items
VCard, // vcard-temp
Jingle, // http://www.google.com/session
JingleError, // urn:xmpp:jingle:errors
JingleAudio, // http://www.google.com/session/phone
JingleTransport, // http://www.google.com/transport/p2p
JingleTransfer, // urn:xmpp:jingle:transfer
JingleRtpInfo, // urn:xmpp:jingle:apps:rtp:info
Dtmf, // http://jabber.org/protocol/jingle/info/dtmf
DtmfError, // http://jabber.org/protocol/jingle/info/dtmf#errors
Jingle, // xmlns='urn:xmpp:jingle:0
JingleError, // urn:xmpp:jingle:errors:0
JingleAppsRtp, // urn:xmpp:jingle:apps:rtp:0
JingleAppsRtpInfo, // urn:xmpp:jingle:apps:rtp:info:0
JingleTransportIceUdp, // urn:xmpp:jingle:transports:ice-udp:0
JingleTransportRawUdp, // urn:xmpp:jingle:transports:raw-udp:0
JingleTransportRawUdpInfo, // urn:xmpp:jingle:transports:raw-udp:info:0
JingleTransfer, // urn:xmpp:jingle:transfer:0
Dtmf, // urn:xmpp:jingle:dtmf:0
Command, // http://jabber.org/protocol/command
CapVoiceV1, // http://www.google.com/xmpp/protocol/voice/v1
Count,

View File

@ -32,9 +32,13 @@
*/
namespace TelEngine {
class JGAudio; // A Jingle data payload
class JGAudioList; // A List of Jingle data payloads
class JGTransport; // A Jingle transport description
class JGRtpMedia; // A Jingle RTP data payload
class JGCrypto; // Content crypto data
class JGRtpMediaList; // A list of Jingle RTP data payloads
class JGRtpCandidate; // A RTP transport candidate
class JGRtpCandidates; // A list of RTP transport candidates
class JGSessionContent; // A Jingle session content
class JGRtpContent; // A Jingle RTP session content
class JGSession; // A Jingle session
class JGEvent; // An event generated by a Jingle session
class JGEngine; // The Jingle engine
@ -45,49 +49,52 @@ class JGSentStanza; // Sent stanza timeout info
* This class holds a Jingle data payload description
* @short A Jingle data payload
*/
class YJINGLE_API JGAudio : public GenObject
class YJINGLE_API JGRtpMedia : public GenObject
{
public:
/**
* Constructor. Fill this object from the given attributes
* @param _id The 'id' attribute
* @param _name The 'name' attribute
* @param _clockrate The 'clockrate' attribute
* @param _bitrate The 'bitrate' attribute
* @param _synonym The 'synonym' attribute
* @param id The 'id' attribute
* @param name The 'name' attribute
* @param clockrate The 'clockrate' attribute
* @param channels The 'channels' attribute
* @param synonym The 'synonym' attribute
*/
inline JGAudio(const char* _id, const char* _name, const char* _clockrate,
const char* _bitrate, const char* _synonym)
{ set(_id,_name,_clockrate,_bitrate,_synonym); }
inline JGRtpMedia(const char* id, const char* name, const char* clockrate,
const char* channels, const char* synonym)
: m_params("")
{ set(id,name,clockrate,channels,synonym); }
/**
* Constructor. Fill this object from an XML element
* @param xml The element to fill from
*/
inline JGAudio(XMLElement* xml)
inline JGRtpMedia(XMLElement* xml)
: m_params("")
{ fromXML(xml); }
/**
* Copy constructor
*/
inline JGAudio(const JGAudio& src)
{ set(src.id,src.name,src.clockrate,src.bitrate,src.synonym); }
inline JGRtpMedia(const JGRtpMedia& src)
: m_params(src.m_params)
{ set(src.m_id,src.m_name,src.m_clockrate,src.m_channels,src.m_synonym); }
/**
* Set the data
* @param _id The 'id' attribute
* @param _name The 'name' attribute
* @param _clockrate The 'clockrate' attribute
* @param _bitrate The 'bitrate' attribute
* @param _synonym The 'synonym' attribute
* @param id The 'id' attribute
* @param name The 'name' attribute
* @param clockrate The 'clockrate' attribute
* @param channels The 'channels' attribute
* @param synonym The 'synonym' attribute
*/
inline void set(const char* _id, const char* _name, const char* _clockrate,
const char* _bitrate, const char* _synonym) {
id = _id;
name = _name;
clockrate = _clockrate;
bitrate = _bitrate;
synonym = _synonym;
inline void set(const char* id, const char* name, const char* clockrate,
const char* channels, const char* synonym) {
m_id = id;
m_name = name;
m_clockrate = clockrate;
m_channels = channels;
m_synonym = synonym;
}
/**
@ -95,13 +102,13 @@ public:
* @return The string repreasentation (id) of this payload
*/
virtual const String& toString() const
{ return id; }
{ return m_id; }
/**
* Create a 'payload-type' element from this object
* @return Valid XMLElement pointer
*/
XMLElement* toXML();
XMLElement* toXML() const;
/**
* Fill this object from a given element
@ -112,37 +119,110 @@ public:
/**
* The numeric id of this payload
*/
String id;
String m_id;
/**
* The Jingle name of this payload
*/
String name;
String m_name;
/**
* The clockrate of this payload
*/
String clockrate;
String m_clockrate;
/**
* The bitrate of this payload
* The number of channels
*/
String bitrate;
String m_channels;
/**
* A synonym of this payload's name
*/
String synonym;
String m_synonym;
/**
* List of optional parameters
*/
NamedList m_params;
};
/**
* Hold a list of data payloads
* @short A List of Jingle data payloads
* This class holds a content description's crypto data.
* The tag is kepti in the String component
* @short Content crypto data
*/
class JGAudioList : public ObjList
class YJINGLE_API JGCrypto : public String
{
public:
/**
* Constructor
* @param tag The tag parameter
* @param suite The crypto-suite paramter
* @param key The key-params parameter
* @param session The session-param parameter
*/
inline JGCrypto(const char* tag = "1", const char* suite = 0,
const char* key = 0, const char* session = 0)
: String(tag),
m_suite(suite), m_keyParams(key), m_sessionParams(session)
{}
/**
* Constructor. Build this element from a received element
* @param xml The received xml element
*/
inline JGCrypto(const XMLElement* xml)
{ fromXML(xml); }
/**
* Create a 'crypto' element from this object
* @return Valid XMLElement pointer
*/
XMLElement* toXML() const;
/**
* Build this element from a received element
* @param xml The received xml element
*/
void fromXML(const XMLElement* xml);
String m_suite;
String m_keyParams;
String m_sessionParams;
};
/**
* Hold a list of RTP data payloads
* @short A List of Jingle RTP data payloads
*/
class YJINGLE_API JGRtpMediaList : public ObjList
{
public:
/**
* Media type enumeration
*/
enum Media {
MediaMissing = -1,
MediaUnknown = 0,
Audio = 1,
};
/**
* Constructor
* @param t Media type as enumeration
*/
inline JGRtpMediaList(Media m = MediaMissing, bool cryptoMandatory = false)
: m_media(m), m_cryptoMandatory(cryptoMandatory)
{}
/**
* Get the media type of the payloads owned by this list
* @return Media type as enumeration
*/
inline Media media() const
{ return m_media; }
/**
* Append a new data payload
* @param id The payload's id
@ -153,21 +233,28 @@ public:
*/
inline void add(const char* id, const char* name, const char* clockrate,
const char* bitrate, const char* synonym)
{ append(new JGAudio(id,name,clockrate,bitrate,synonym)); }
{ append(new JGRtpMedia(id,name,clockrate,bitrate,synonym)); }
/**
* Find a data payload by its id
* @param value The value to compare with
* @return JGRtpMedia pointer or 0 if not found
*/
JGRtpMedia* findMedia(const String& id);
/**
* Find a data payload by its synonym
* @param value The value to compare with
* @return JGAudio pointer or 0 if not found
* @return JGRtpMedia pointer or 0 if not found
*/
JGAudio* findSynonym(const String& value);
JGRtpMedia* findSynonym(const String& value) const;
/**
* Create a 'description' element and add payload children to it
* @param telEvent True to append a telephone event data payload
* @return Valid XMLElement pointer
*/
XMLElement* toXML(bool telEvent = true);
XMLElement* toXML(bool telEvent = true) const;
/**
* Fill this list from an XML element's children. Clear before attempting to fill
@ -183,51 +270,129 @@ public:
* @return False if the list is empty
*/
bool createList(String& dest, bool synonym, const char* sep = ",");
/**
* The list of media type names
*/
static TokenDict s_media[];
/**
* The media type
*/
Media m_media;
/**
* Crypto (SRTP) params
*/
bool m_cryptoMandatory;
ObjList m_cryptoLocal;
ObjList m_cryptoRemote;
};
/**
* This class holds a Jingle transport description (protocol, address, port ...)
* @short A Jingle transport description
* This class holds a RTP transport candidate
* @short A RTP transport candidate
*/
class YJINGLE_API JGTransport : public RefObject
class JGRtpCandidate : public String
{
public:
/**
* Constructor
*/
inline JGTransport()
inline JGRtpCandidate(const char* id, const char* component = "1",
unsigned int generation = 0, unsigned int net = 0, int prio = 0)
: String(id),
m_port(0), m_component(component), m_generation(generation),
m_network(net), m_priority(prio), m_protocol("udp"), m_type("host")
{}
/**
* Copy constructor
* Constructor. Build a candidate from received data
* @param xml Received xml element
* @param container The transport container
*/
JGTransport(const JGTransport& src);
inline JGRtpCandidate(XMLElement* xml, const JGRtpCandidates& container)
{ fromXml(xml,container); }
/**
* Create a 'candidate' element from this object using local address/port
* @param container The transport container
* @return Valid XMLElement pointer if type is a known one
*/
XMLElement* toXml(const JGRtpCandidates& container) const;
/**
* Fill this object from a candidate element using remote address/port
* @param xml Received xml element
* @param container The transport container
*/
void fromXml(XMLElement* xml, const JGRtpCandidates& container);
String m_address;
String m_port;
String m_component; // Candidate component
String m_generation; // Candidate generation
String m_network; // NIC card (diagnostic only)
String m_priority; // Candidate priority
String m_protocol; // The only allowable value is "udp"
String m_type; // A Candidate Type as defined in ICE-CORE.
};
/**
* This class holds a list of jingle RTP transport candidates
* @short A list of RTP transport candidates
*/
class YJINGLE_API JGRtpCandidates : public ObjList
{
public:
/**
* Enumeration of transport types
*/
enum Type {
Unknown = -1,
RtpIceUdp = 1,
RtpRawUdp = 2,
};
/**
* Constructor. Fill this object from an XML element
* @param element The element to fill from
* @param t The transport type
*/
inline JGTransport(XMLElement* element)
{ fromXML(element); }
/**
* Destructor
*/
virtual ~JGTransport()
inline JGRtpCandidates(Type t = Unknown)
: m_type(t)
{}
/**
* Create a 'transport' element
* @return Valid XMLElement pointer
* Get the name of this list's type
* @return The name of this list's type
*/
static XMLElement* createTransport();
inline const char* typeName() const
{ return typeName(m_type); }
/**
* Create a 'candidate' element from this object
* Fill password and ufrag data
*/
inline void generateIceAuth() {
generateIceToken(m_password,true);
generateIceToken(m_ufrag,false);
}
/**
* Find a candidate by its component value
* @component The value to search
* @return JGRtpCandidate pointer or 0
*/
JGRtpCandidate* findByComponent(unsigned int component);
/**
* Create a 'transport' element from this object. Add candidates
* @addCandidates True to add the candidate children
* @addAuth RtpIceUdp only: add auth data
* @return Valid XMLElement pointer
*/
XMLElement* toXML();
XMLElement* toXML(bool addCandidates, bool addAuth) const;
/**
* Fill this object from a given element
@ -236,23 +401,172 @@ public:
void fromXML(XMLElement* element);
/**
* Create and add a 'candidate' child to the given element
* @param transport The element
* Generate a random password to be used with ICE-UDP transport
* @param dest Destination string
* @param pwd True to generate a password, false to generate an username (ufrag)
* @param max Maximum number of characters. The maxmimum value is 256.
* The minimum value is 22 for password and 4 for username
*/
inline void addTo(XMLElement* transport)
{ if (transport) transport->addChild(toXML()); }
static void generateIceToken(String& dest, bool pwd, unsigned int max = 0);
// Attributes
String name;
String address;
String port;
String preference;
String username;
String protocol;
String generation;
String password;
String type;
String network;
/**
* Get the name associated with a list's type
* @param t The desired type
* @param defVal Default value to return
* @return The name associated with a list's type
*/
static inline const char* typeName(int t, const char* defVal = "unknown")
{ return TelEngine::lookup(t,s_type,defVal); }
/**
* The list of type names
*/
static TokenDict s_type[];
Type m_type;
String m_password;
String m_ufrag;
};
/**
* This class holds a Jingle content negotiated during a session
* It can be built from a received xml element and
* it can build an xml element from itself
* @short A Jingle session content
*/
class YJINGLE_API JGSessionContent : public RefObject
{
public:
/**
* Enumeration values for the 'senders' attribute (required)
*/
enum Senders {
SendUnknown = 0,
SendBoth = 1,
SendInitiator = 2,
SendResponder = 3
};
/**
* Enumeration values for the 'creator' attribute (required)
*/
enum Creator {
CreatorUnknown = 0,
CreatorInitiator = 1,
CreatorResponder = 2
};
/**
* Constructor
* @param name Content name
* @param senders Content senders as enumeration
* @param creator Content creator as enumeration
* @param disposition Optional content disposition (defauls to 'session' if empty)
*/
JGSessionContent(const char* name, Senders senders,
Creator creator, const char* disposition = 0);
/**
* Get the senders
* @return Senders as enumeration
*/
inline Senders senders() const
{ return m_senders; }
/**
* Get the content creator
* @return Content creator as enumeration
*/
inline Creator creator() const
{ return m_creator; }
/**
* Check if this content is a valid audio one: it's media list type is Audio
* and the payload list is not empty
* @return True if this content can be used for audio purposes
*/
inline bool isValidAudio() const
{ return (m_rtpMedia.media() == JGRtpMediaList::Audio) && (0 != m_rtpMedia.skipNull()); }
/**
* Get the name of this content
*/
virtual const String& toString() const
{ return m_name; }
/**
* Check if the content disposition is session
* XEP-0166: true if disposition is missing
* @return True if this content should be processed at session level
*/
inline bool isSession() const
{ return !m_disposition || m_disposition == "session"; }
/**
* Check if the content disposition is early media
* @return True if this content is an early media one
*/
inline bool isEarlyMedia() const
{ return m_disposition == "early-session"; }
/**
* Set this content's disposition to early media
*/
inline void setEarlyMedia()
{ m_disposition = "early-session"; }
/**
* Build a 'content' XML element from this object
* @minimum Minimum data (only creator and name)
* @addDesc True to add the description child
* @addTrans True to add the transport child
* @addCandidates True to add the transport candidate children
* @addAuth RtpIceUdp only: add auth data
* @return Valid XMLElement pointer
*/
XMLElement* toXml(bool minimum, bool addDesc,
bool addTrans, bool addCandidates, bool addAuth) const;
/**
* Decode 'content' element attributes
* @param xml The XML element
* @param err The error on failure
* @param error Error text to be sent on failure
* @return Valid JGSessionContent pointer on success
*/
static JGSessionContent* fromXml(XMLElement* xml, XMPPError::Type& err,
String& error);
/**
* The list containing the text values for Senders enumeration
*/
static TokenDict s_senders[];
/**
* The list containing the text values for Creator enumeration
*/
static TokenDict s_creator[];
/**
* The RTP media description if used
*/
JGRtpMediaList m_rtpMedia;
/**
* The RTP local candidates
*/
JGRtpCandidates m_rtpLocalCandidates;
/**
* The RTP remote candidates
*/
JGRtpCandidates m_rtpRemoteCandidates;
private:
String m_name;
Senders m_senders;
Creator m_creator;
String m_disposition;
};
@ -280,35 +594,30 @@ public:
* Jingle action enumeration
*/
enum Action {
ActAccept, // accept
ActInitiate, // initiate
ActReject, // reject
ActTerminate, // terminate
ActAccept, // session-accept
ActInitiate, // session-initiate
ActTerminate, // session-terminate
ActInfo, // session-info
ActTransport, // Used to set/get transport info
ActTransportInfo, // transport-info
ActTransportCandidates, // candidates
ActTransportAccept, // transport-accept
ActContentInfo, // content-info
ActTransportReject, // transport-reject
ActTransportReplace, // transport-replace
ActContentAccept, // content-accept
ActContentAdd, // content-add
ActContentModify, // content-modify
ActContentReject, // content-reject
ActContentRemove, // content-remove
ActTransfer, // session-transfer
ActRinging, // session-info: Ringing
ActTrying, // session-info: Trying
ActReceived, // session-info: Received
ActHold, // session-info: Hold
ActActive, // session-info: Active
ActMute, // session-info: Mute
ActDtmf, // Used to set/get dtmf content-info element
ActDtmfMethod, // Used to set/get dtmf method content-info element
ActDtmf, // session-info: Dtmf
ActCount,
};
/**
* Jingle transport type enumeration
*/
enum TransportType {
TransportUnknown, // Detect transport type on incoming, sent both on outgoing
TransportInfo, // transport-info
TransportCandidates, // candidates
};
/**
* Jingle defined termination reasons
*/
@ -381,6 +690,13 @@ public:
inline void* userData()
{ return m_private; }
/**
* Set the arbitrary user data of this session
* @param userdata The new arbitrary user data's value
*/
inline void userData(void* userdata)
{ m_private = userdata; }
/**
* Ask this session to accept an event
* @param event The event to accept
@ -389,21 +705,14 @@ public:
*/
bool acceptEvent(JBEvent* event, const String& sid = String::empty());
/**
* Set the arbitrary user data of this session
* @param userdata The new arbitrary user data's value
*/
inline void userData(void* userdata)
{ m_private = userdata; }
/**
* Accept a Pending incoming session.
* This method is thread safe
* @param description The media description element to send
* @param contents The list of accepted contents
* @param stanzaId Optional string to be filled with sent stanza id (used to track the response)
* @return False if send failed
*/
bool accept(XMLElement* description, String* stanzaId = 0);
bool accept(const ObjList& contents, String* stanzaId = 0);
/**
* Close a Pending or Active session
@ -414,6 +723,35 @@ public:
*/
bool hangup(int reason, const char* msg = 0);
/**
* Send a stanza with session content(s)
* This method is thread safe
* @param action Must be a transport- or content- action
* @param contents Non empty list with content(s) to send
* @param stanzaId Optional string to be filled with sent
* stanza id (used to track the response)
* @return False if send failed
*/
bool sendContent(Action action, const ObjList& contents, String* stanzaId = 0);
/**
* Send a stanza with a session content
* This method is thread safe
* @param action Must be a transport- or content- action
* @param content The content to send
* @param stanzaId Optional string to be filled with sent
* stanza id (used to track the response)
* @return False if send failed
*/
inline bool sendContent(Action action, const JGSessionContent* content,
String* stanzaId = 0) {
if (!content)
return false;
ObjList tmp;
tmp.append(content)->setDelete(false);
return sendContent(action,tmp,stanzaId);
}
/**
* Confirm a received element. If the error is NoError a result stanza will be sent.
* Otherwise, an error stanza will be created and sent and the received element is
@ -428,49 +766,14 @@ public:
const char* text = 0, XMPPError::ErrorType type = XMPPError::TypeModify);
/**
* Send a dtmf string to remote peer. If the string's lenght is greater then 1, each
* Send a dtmf string to remote peer. If the string's length is greater then 1, each
* character is added as a 'dtmf' child of the jingle element
* @param dtmf The dtmf string
* @param buttonUp True to send button-up action. False to send button-down
* @param msDuration The tone duration in miliseconds. Ignored if 0
* @param stanzaId Optional string to be filled with sent stanza id (used to track the response)
* @return False if send failed
*/
bool sendDtmf(const char* dtmf, bool buttonUp = true, String* stanzaId = 0);
/**
* Send a dtmf method to remote peer
* @param method The method to send
* @param stanzaId Optional string to be filled with sent stanza id (used to track the response)
* @return False if send failed
*/
bool sendDtmfMethod(const char* method, String* stanzaId = 0);
/**
* Deny a dtmf method request from remote peer
* @param element The received 'iq' element with the method
* @return False if send failed
*/
bool denyDtmfMethod(XMLElement* element);
/**
* Send a 'transport-accept' element to the remote peer.
* This method is thread safe
* @param transport Optional transport data to send
* @param stanzaId Optional string to be filled with sent stanza id (used to track the response)
* @return False if send failed
*/
inline bool acceptTransport(JGTransport* transport = 0, String* stanzaId = 0)
{ return sendTransport(transport,ActTransportAccept,stanzaId); }
/**
* Send a 'transport-info' element to the remote peer.
* This method is thread safe
* @param transport The transport data
* @param stanzaId Optional string to be filled with sent stanza id (used to track the response)
* @return False if send failed
*/
inline bool sendTransport(JGTransport* transport, String* stanzaId = 0)
{ return sendTransport(transport,ActTransport,stanzaId); }
bool sendDtmf(const char* dtmf, unsigned int msDuration = 0, String* stanzaId = 0);
/**
* Send a message to the remote peer.
@ -546,25 +849,21 @@ protected:
* @param stream The stream this session is bound to
* @param callerJID The caller's full JID
* @param calledJID The called party's full JID
* @param media The session media description
* @param transport The session transport method(s)
* @param sid True to used 'sid' instead of 'id' as session id attribute
* @param contents The session contents to be sent with session initiate element
* @param extra Optional extra child to be added to the session initiate element
* @param msg Optional message to be sent before session initiate
*/
JGSession(JGEngine* engine, JBStream* stream,
const String& callerJID, const String& calledJID,
XMLElement* media, XMLElement* transport,
bool sid, XMLElement* extra = 0, const char* msg = 0);
const ObjList& contents, XMLElement* extra = 0, const char* msg = 0);
/**
* Constructor. Create an incoming session.
* @param engine The engine that owns this session
* @param event A valid Jabber Jingle event with action session initiate
* @param id Session id
* @param sid True to used 'sid' instead of 'id' as session id attribute
*/
JGSession(JGEngine* engine, JBEvent* event, const String& id, bool sid);
JGSession(JGEngine* engine, JBEvent* event, const String& id);
/**
* Release this session and its memory
@ -613,15 +912,6 @@ protected:
XMLElement* createJingle(Action action, XMLElement* element1 = 0,
XMLElement* element2 = 0, XMLElement* element3 = 0);
/**
* Send a transport related element to the remote peer
* @param transport Transport data to send
* @param act The element's type (info, accept, etc)
* @param stanzaId Optional string to be filled with sent stanza id (used to track the response)
* @return True on success
*/
bool sendTransport(JGTransport* transport, Action act, String* stanzaId = 0);
/**
* Get the name of a session state
* @return The name of a session state
@ -641,7 +931,6 @@ private:
// State info
State m_state; // Session state
TransportType m_transportType; // Remote client transport type
// Links
JGEngine* m_engine; // The engine that owns this session
JBStream* m_stream; // The stream this session is bound to
@ -650,7 +939,6 @@ private:
String m_sid; // Session id
JabberID m_localJID; // Local peer's JID
JabberID m_remoteJID; // Remote peer's JID
String m_sidAttr; // Session id attribute name
// Session data
ObjList m_events; // Incoming events from Jabber engine
JGEvent* m_lastEvent; // Last generated event
@ -673,13 +961,7 @@ public:
* Jingle events enumeration
*/
enum Type {
Jingle, // Actions:
// ActAccept
// ActInitiate
// ActTransport Transport candidade(s)
// ActTransportAccept
// ActDtmf m_reason is button-up/button-down. m_text is the dtmf
// ActDtmfMethod m_text is the dtmf method: rtp/xmpp
Jingle, //
ResultOk, // Response for a sent stanza (iq with type=result)
ResultError, // Response for a sent stanza (iq with type=error)
ResultWriteFail, // Response for a sent stanza (failed to send stanza)
@ -742,23 +1024,9 @@ public:
* Get the name of an action
* @return The name of an action
*/
inline const char* actionName()
inline const char* actionName() const
{ return JGSession::lookupAction(m_action); }
/**
* Get the audio payloads list
* @return The audio payloads list
*/
inline JGAudioList& audio()
{ return m_audio; }
/**
* Get the transports list
* @return The transports list
*/
inline ObjList& transport()
{ return m_transport; }
/**
* Get the id
* @return The id
@ -798,6 +1066,23 @@ public:
inline bool final() const
{ return m_type == Terminated || m_type == Destroy; }
/**
* Confirm the element carryied by this event. See JGSession::confirm() for details
* @param error The error condition
* @param text Optional text to add to the error element
* @param type Error type
* @return False if send failed or element is 0
*/
inline bool confirmElement(XMPPError::Type error = XMPPError::NoError,
const char* text = 0, XMPPError::ErrorType type = XMPPError::TypeModify) {
if (m_session && element()) {
if (error == XMPPError::NoError)
return m_session->confirm(element());
return m_session->confirm(releaseXML(),error,text,type);
}
return false;
}
/**
* Get the name of an event type
* @return The name of an event type
@ -810,6 +1095,11 @@ public:
*/
static TokenDict s_typeName[];
/**
* The list of session contents if used
*/
ObjList m_contents;
protected:
/**
* Constructor. Set the id parameter if the element is valid
@ -849,8 +1139,6 @@ private:
XMLElement* m_jingle; // The session child, if present
// Event specific
JGSession::Action m_action; // The action if type is Jingle
JGAudioList m_audio; // The received audio payloads
ObjList m_transport; // The received transport data
String m_id; // The element's id attribute
String m_reason; // The reason if type is Error or Terminated
String m_text; // Dtmf text
@ -904,15 +1192,13 @@ public:
* 'media' and 'transport' will be invalid on exit. Don't delete them
* @param callerName The local peer's username
* @param remoteJID The remote peer's JID
* @param media A valid 'description' XML element
* @param transport A valid 'transport' XML element
* @param contents The list of session content(s)
* @param extra Optional extra child for session initiate element
* @param msg Optional message to send before call
* @return Valid JGSession pointer (referenced) on success
*/
JGSession* call(const String& callerName, const String& remoteJID,
XMLElement* media, XMLElement* transport, XMLElement* extra = 0,
const char* msg = 0);
const ObjList& contents, XMLElement* extra = 0, const char* msg = 0);
/**
* Default event processor. Delete event.
@ -945,7 +1231,6 @@ private:
Mutex m_sessionIdMutex; // Session id counter lock
u_int32_t m_sessionId; // Session id counter
u_int64_t m_stanzaTimeout; // The timeout of a sent stanza
bool m_useSidAttr; // Use 'sid' for session id attribute name for outgoing calls
};
@ -985,7 +1270,7 @@ private:
bool m_notify; // Notify timeout to sender
};
}
};
#endif /* __YATEJINGLE_H */

File diff suppressed because it is too large Load Diff