Commits work in progress on Google Talk voice support.

cusax-fix
Sebastien Vincent 15 years ago
parent b95675bb3d
commit 3d232caf52

@ -275,7 +275,8 @@ public void securityOn(CallPeerSecurityOnEvent securityOnEvent)
renderer.setEncryptionCipher(securityOnEvent.getCipher());
switch (securityOnEvent.getSessionType()) {
switch (securityOnEvent.getSessionType())
{
case CallPeerSecurityOnEvent.AUDIO_SESSION:
renderer.setAudioSecurityOn(true);
break;

@ -22,6 +22,11 @@ public class SecurityStatusLabel
extends JLabel
implements Skinnable
{
/**
* Serial version UID.
*/
private static final long serialVersionUID = 0L;
/**
* Indicates the state of the audio security (on or off).
*/

@ -83,6 +83,11 @@ public class ScServiceDiscoveryManager
*/
private final List<DiscoverInfo.Identity> identities;
/**
* Capabilities to put in ext attribute of capabilities stanza.
*/
private final List<String> extCapabilities = new ArrayList<String>();
/**
* Creates a new <tt>ScServiceDiscoveryManager</tt> wrapping the default
* discovery manager of the specified <tt>connection</tt>.
@ -308,6 +313,50 @@ public void removeFeature(String feature)
updateEntityCapsVersion();
}
/**
* Add feature to put in "ext" attribute.
*
* @param ext ext feature to add
*/
public void addExtFeature(String ext)
{
synchronized(extCapabilities)
{
extCapabilities.add(ext);
}
}
/**
* Remove "ext" feature.
*
* @param ext ext feature to remove
*/
public void removeExtFeature(String ext)
{
synchronized(extCapabilities)
{
extCapabilities.remove(ext);
}
}
/**
* Get "ext" value.
*
* @return string that represents "ext" value
*/
public synchronized String getExtFeatures()
{
StringBuilder bldr = new StringBuilder("");
for(String e : extCapabilities)
{
bldr.append(e);
bldr.append(" ");
}
return bldr.toString();
}
/**
* Intercepts outgoing presence packets and adds entity capabilities at
* their ends.
@ -322,7 +371,7 @@ public void interceptPacket(Packet packet)
String ver = getEntityCapsVersion();
CapsPacketExtension caps
= new CapsPacketExtension(
null,
getExtFeatures(),
capsManager.getNode(),
CapsPacketExtension.HASH_METHOD,
ver);
@ -423,9 +472,12 @@ public DiscoverInfo discoverInfo(String entityID)
if ((caps != null) && !caps.isValid(discoverInfo))
{
logger.error(
"Invalid DiscoverInfo for " + caps.getNodeVer() + ": "
+ discoverInfo);
if(!caps.hash.equals(""))
{
logger.error(
"Invalid DiscoverInfo for " + caps.getNodeVer() + ": "
+ discoverInfo);
}
caps = null;
}

@ -29,7 +29,7 @@ public abstract class AbstractPacketExtension
* The name space of this packet extension. Should remain <tt>null</tt> if
* there's no namespace associated with this element.
*/
private final String namespace;
private String namespace;
/**
* The name space of this packet extension. Should remain <tt>null</tt> if
@ -77,6 +77,16 @@ public String getElementName()
return elementName;
}
/**
* Set the XML namespace for this element.
*
* @param namespace the XML namespace for this element.
*/
public void setNamespace(String namespace)
{
this.namespace = namespace;
}
/**
* Returns the XML namespace for this element or <tt>null</tt> if the
* element does not live in a namespace of its own.

@ -103,6 +103,15 @@ public C parseExtension(XmlPullParser parser) throws Exception
{
PacketExtension childExtension
= provider.parseExtension(parser);
if(namespace != null)
{
if(childExtension instanceof AbstractPacketExtension)
{
((AbstractPacketExtension)childExtension).
setNamespace(namespace);
}
}
packetExtension.addChildExtension(childExtension);
}
}

@ -179,12 +179,14 @@ private static String getCapsPropertyName(Caps caps)
* @param node the node (of the caps packet extension)
* @param hash the hashing algorithm used to calculate <tt>ver</tt>
* @param ver the version (of the caps packet extension)
* @param ext the ext (of the caps packet extension)
* @param online indicates if the user is online
*/
private void addUserCapsNode( String user,
String node,
String hash,
String ver,
String ext,
boolean online)
{
if ((user != null) && (node != null) && (hash != null) && (ver != null))
@ -196,7 +198,7 @@ private void addUserCapsNode( String user,
|| !caps.hash.equals(hash)
|| !caps.ver.equals(ver))
{
caps = new Caps(node, hash, ver);
caps = new Caps(node, hash, ver, ext);
userCaps.put(user, caps);
}
@ -230,7 +232,7 @@ private void addUserCapsNode( String user,
*
* @param listener the <tt>UserCapsNodeListener</tt> which is interested in
* events notifying about changes in the list of user caps nodes of this
* <tt>EntityCapsManager</tt>
* <tt>EntityCapsManager</tt>
*/
public void addUserCapsNodeListener(UserCapsNodeListener listener)
{
@ -281,7 +283,7 @@ public void removeUserCapsNode(String user)
*
* @param listener the <tt>UserCapsNodeListener</tt> which is no longer
* interested in events notifying about changes in the list of user caps
* nodes of this <tt>EntityCapsManager</tt>
* nodes of this <tt>EntityCapsManager</tt>
*/
public void removeUserCapsNodeListener(UserCapsNodeListener listener)
{
@ -365,7 +367,7 @@ public static DiscoverInfo getDiscoverInfoByCaps(Caps caps)
/*
* If we don't have the discoverInfo in the runtime cache yet, we
* may have it remembered in a previous application instance.
* may have it remembered in a previous application instance.
*/
if (discoverInfo == null)
{
@ -577,7 +579,7 @@ private void fireCapsVerChanged()
* the specified <tt>hashAlgorithm</tt>.
*
* @param hashAlgorithm the name of the algorithm to be used to generate the
* hash
* hash
* @param capsString the capabilities string that we'd like to compute a
* hash for.
*
@ -667,7 +669,7 @@ public int compare(
*
* Since sort by xml:lang is currently missing,
* use the last supported sort criterion i.e.
* type.
* type.
*/
return type;
}
@ -778,7 +780,8 @@ public void setCurrentCapsVersion(DiscoverInfo discoverInfo,
String capsVersion)
{
Caps caps
= new Caps(getNode(), CapsPacketExtension.HASH_METHOD, capsVersion);
= new Caps(getNode(), CapsPacketExtension.HASH_METHOD, capsVersion,
null);
/*
* DiscoverInfo carries the node and the ver and we're now setting a new
@ -827,10 +830,16 @@ public void processPacket(Packet packet)
* validate the DiscoverInfo sent by the client. If
* EntityCapsManager receives no 'hash' attribute, it will assume
* the legacy format and will not cache it because the DiscoverInfo
* to be received from the client later on will not be trustworthy.
* to be received from the client later on will not be trustworthy.
*/
String hash = ext.getHash();
/* Google Talk web does not set hash but we need it to be cached */
if(hash == null)
{
hash = "";
}
if (hash != null)
{
// Check it the packet indicates that the user is online. We
@ -841,8 +850,9 @@ public void processPacket(Packet packet)
online = ((Presence) packet).isAvailable();
addUserCapsNode(
packet.getFrom(),
ext.getNode(), hash, ext.getVersion(), online);
packet.getFrom(),
ext.getNode(), hash, ext.getVersion(),
ext.getExtensions(), online);
}
}
}
@ -850,7 +860,7 @@ public void processPacket(Packet packet)
/**
* Implements an immutable value which stands for a specific node, a
* specific hash (algorithm) and a specific ver.
*
*
* @author Lubomir Marinov
*/
public static class Caps
@ -861,6 +871,9 @@ public static class Caps
/** The node of this <tt>Caps</tt> value. */
public final String node;
/** The ext info of this <tt>Caps</tt> value. */
public String ext;
/**
* The String which is the concatenation of {@link #node} and the
* {@link #ver} separated by the character '#'. Cached for the sake of
@ -879,8 +892,9 @@ public static class Caps
* @param hash the hash (algorithm) to be represented by the new
* instance
* @param ver the ver to be represented by the new instance
* @param ext the ext to be represented by the new instance
*/
public Caps(String node, String hash, String ver)
public Caps(String node, String hash, String ver, String ext)
{
if (node == null)
throw new NullPointerException("node");
@ -892,6 +906,7 @@ public Caps(String node, String hash, String ver)
this.node = node;
this.hash = hash;
this.ver = ver;
this.ext = ext;
this.nodeVer = this.node + '#' + this.ver;
}
@ -931,6 +946,7 @@ public boolean isValid(DiscoverInfo discoverInfo)
return
(discoverInfo != null)
&& getNodeVer().equals(discoverInfo.getNode())
&& !hash.equals("")
&& ver.equals(
capsToHash(
hash,

@ -0,0 +1,183 @@
/*
* Jitsi, the OpenSource Java VoIP and Instant Messaging client.
*
* Distributable under LGPL license.
* See terms of license at gnu.org.
*/
package net.java.sip.communicator.impl.protocol.jabber.extensions.gtalk;
import net.java.sip.communicator.impl.protocol.jabber.extensions.jingle.*;
/**
* Google Talk version of Candidate packet extension.
*
* @author Sebastien Vincent
*/
public class GTalkCandidatePacketExtension
extends CandidatePacketExtension
{
/**
* Address attribute name.
*/
public static final String ADDRESS_ATTR_NAME = "address";
/**
* The name of the "preference" element.
*/
public static final String PREFERENCE_ATTR_NAME = "preference";
/**
* Name attribute name.
*/
public static final String NAME_ATTR_NAME = "name";
/**
* Username attribute name.
*/
public static final String USERNAME_ATTR_NAME = "username";
/**
* Password attribute name.
*/
public static final String PASSWORD_ATTR_NAME = "password";
/**
* Name for candidate audio RTP.
*/
public static final String AUDIO_RTP_NAME = "rtp";
/**
* Name for candidate audio RTCP.
*/
public static final String AUDIO_RTCP_NAME = "rtcp";
/**
* Name for candidate video RTP.
*/
public static final String VIDEO_RTP_NAME = "video_rtp";
/**
* Name for candidate video RTCP.
*/
public static final String VIDEO_RTCP_NAME = "video_rtcp";
/**
* Constructs a new <tt>GTalkCandidatePacketExtension</tt>.
*/
public GTalkCandidatePacketExtension()
{
}
/**
* Sets a Candidate Type as defined in ICE-CORE.
*
* @param type this candidates' type as per ICE's Google dialect.
*/
public void setType(String type)
{
super.setAttribute(TYPE_ATTR_NAME, type);
}
/**
* Sets this candidate's name.
*
* @param name this candidate's name
*/
public void setName(String name)
{
super.setAttribute(NAME_ATTR_NAME, name);
}
/**
* Returns this candidate's name.
*
* @return this candidate's name
*/
public String getName()
{
return super.getAttributeAsString(NAME_ATTR_NAME);
}
/**
* Sets this candidate's preference.
*
* @param preference this candidate's preference
*/
public void setPreference(double preference)
{
super.setAttribute(PREFERENCE_ATTR_NAME, Double.toString((preference)));
}
/**
* Returns this candidate's preference.
*
* @return this candidate's preference
*/
public double getPreference()
{
return Float.parseFloat(
super.getAttributeAsString(PREFERENCE_ATTR_NAME));
}
/**
* Sets this candidate's username.
*
* @param username this candidate's username
*/
public void setUsername(String username)
{
super.setAttribute(USERNAME_ATTR_NAME, username);
}
/**
* Returns this candidate's username.
*
* @return this candidate's username
*/
public String getUsername()
{
return super.getAttributeAsString(USERNAME_ATTR_NAME);
}
/**
* Sets this candidate's password.
*
* @param password this candidate's password
*/
public void setPassword(String password)
{
super.setAttribute(PASSWORD_ATTR_NAME, password);
}
/**
* Returns this candidate's password.
*
* @return this candidate's password
*/
public String getPassword()
{
return super.getAttributeAsString(PASSWORD_ATTR_NAME);
}
/**
* Sets this candidate's Internet Protocol (IP) address; this can be either
* an IPv4 address or an IPv6 address.
*
* @param ip this candidate's IPv4 or IPv6 address.
*/
public void setAddress(String ip)
{
super.setAttribute(ADDRESS_ATTR_NAME, ip);
}
/**
* Returns this candidate's Internet Protocol (IP) address; this can be
* either an IPv4 address or an IPv6 address.
*
* @return this candidate's IPv4 or IPv6 address.
*/
public String getAddress()
{
return super.getAttributeAsString(ADDRESS_ATTR_NAME);
}
}

@ -0,0 +1,347 @@
/*
* Jitsi, the OpenSource Java VoIP and Instant Messaging client.
*
* Distributable under LGPL license.
* See terms of license at gnu.org.
*/
package net.java.sip.communicator.impl.protocol.jabber.extensions.gtalk;
import java.util.*;
import net.java.sip.communicator.impl.protocol.jabber.extensions.jingle.*;
import net.java.sip.communicator.impl.protocol.jabber.extensions.jingle.CandidateType;
import org.ice4j.*;
import org.ice4j.ice.*;
import org.jivesoftware.smack.packet.*;
/**
* A utility class containing methods for creating {@link SessionIQ}
* instances for various situations.
*
* @author Sebastien Vincent
*/
public class GTalkPacketFactory
{
/**
* Creates a {@link SessionIQ} <tt>reject</tt> packet.
*
* @param from our JID
* @param to the destination JID
* @param sid the ID of the Google Talk session that this message will be
* rejecting.
*
* @return a {@link SessionIQ} <tt>reject</tt> packet.
*/
public static SessionIQ createReject(String from, String to, String sid)
{
SessionIQ reject = new SessionIQ();
reject.setTo(to);
reject.setFrom(from);
reject.setType(IQ.Type.SET);
reject.setID(sid);
reject.setGTalkType(GTalkType.REJECT);
return reject;
}
/**
* Creates a {@link SessionIQ} <tt>terminate</tt> packet carrying a
* {@link Reason#BUSY} payload.
*
* @param from our JID
* @param to the destination JID
* @param sid the ID of the Google Talk session that this message will be
* terminating.
*
* @return a {@link SessionIQ} <tt>terminate</tt> packet.
*/
public static SessionIQ createBusy(String from, String to, String sid)
{
return createSessionTerminate(from, to, sid, Reason.BUSY, null);
}
/**
* Creates a {@link SessionIQ} <tt>session-terminate</tt> packet that is
* meant to terminate an on-going, well established session (similar to a SIP
* BYE request).
*
* @param from our JID
* @param to the destination JID
* @param sid the ID of the Google Talk session that this message will be
* terminating.
*
* @return a {@link SessionIQ} <tt>terminate</tt> packet
* .
*/
public static SessionIQ createBye(String from, String to, String sid)
{
return createSessionTerminate(from, to, sid, Reason.SUCCESS,
"Nice talking to you!");
}
/**
* Creates a {@link SessionIQ} <tt>terminate</tt> packet that is
* meant to terminate a not yet established session.
*
* @param from our JID
* @param to the destination JID
* @param sid the ID of the Google Talk session that this message will be
* terminating.
*
* @return a {@link SessionIQ} <tt>terminate</tt> packet
* .
*/
public static SessionIQ createCancel(String from, String to, String sid)
{
return createSessionTerminate(from, to, sid, Reason.CANCEL, "Oops!");
}
/**
* Creates a {@link SessionIQ} <tt>terminate</tt> packet with the
* specified src, dst, sid, and reason.
*
* @param from our JID
* @param to the destination JID
* @param sid the ID of the Google Talk session that this message will be
* terminating.
* @param reason the reason for the termination
* @param reasonText a human readable reason for the termination or
* <tt>null</tt> for none.
*
* @return the newly constructed {@link SessionIQ} <tt>terminate</tt>
* packet.
* .
*/
public static SessionIQ createSessionTerminate(String from,
String to,
String sid,
Reason reason,
String reasonText)
{
SessionIQ terminate = new SessionIQ();
terminate.setTo(to);
terminate.setFrom(from);
terminate.setType(IQ.Type.SET);
terminate.setID(sid);
terminate.setGTalkType(GTalkType.TERMINATE);
ReasonPacketExtension reasonPacketExt
= new ReasonPacketExtension(reason, reasonText, null);
terminate.setReason(reasonPacketExt);
return terminate;
}
/**
* Creates a {@link SessionIQ} <tt>accept</tt> packet with the
* specified <tt>from</tt>, <tt>to</tt>, <tt>sid</tt>, and <tt>content</tt>.
* Given our role in a conversation, we would assume that the <tt>from</tt>
* value should also be used for the value of the Google Talk <tt>responder</tt>.
*
* @param from our JID
* @param to the destination JID
* @param sid the ID of the Google Talk session that this message will be
* terminating.
* @param description description containing payload types list
* descriptions.
*
* @return the newly constructed {@link SessionIQ} <tt>accept</tt>
* packet.
* .
*/
public static SessionIQ createSessionAccept(
String from,
String to,
String sid,
RtpDescriptionPacketExtension description)
{
SessionIQ sessionAccept = new SessionIQ();
sessionAccept.setTo(to);
sessionAccept.setFrom(from);
sessionAccept.setType(IQ.Type.SET);
sessionAccept.setInitiator(to);
sessionAccept.setID(sid);
sessionAccept.setGTalkType(GTalkType.ACCEPT);
sessionAccept.addExtension(description);
return sessionAccept;
}
/**
* Creates a new {@link SessionIQ} with the <tt>initiate</tt> type.
*
* @param from our JID
* @param to the destination JID
* @param sid the ID of the Google Talk session that this message will be
* terminating.
* @param description description containing payload types list.
*
* @return the newly constructed {@link SessionIQ} <tt>terminate</tt>
* packet.
*/
public static SessionIQ createSessionInitiate(
String from,
String to,
String sid,
RtpDescriptionPacketExtension description)
{
SessionIQ sessionInitiate = new SessionIQ();
sessionInitiate.setTo(to);
sessionInitiate.setFrom(from);
sessionInitiate.setInitiator(from);
sessionInitiate.setType(IQ.Type.SET);
sessionInitiate.setID(sid);
sessionInitiate.setGTalkType(GTalkType.INITIATE);
sessionInitiate.addExtension(description);
return sessionInitiate;
}
/**
* Creates a new {@link SessionIQ} with the <tt>candidates</tt> type.
*
* @param from our JID
* @param to the destination JID
* @param sid the ID of the Google Talk session.
* @param candidate a <tt>GTalkCandidatePacketExtension</tt>.
*
* @return the newly constructed {@link SessionIQ} <tt>terminate</tt>
* packet.
*/
public static SessionIQ createSessionCandidates(
String from,
String to,
String sid,
GTalkCandidatePacketExtension candidate)
{
SessionIQ sessionInitiate = new SessionIQ();
sessionInitiate.setTo(to);
sessionInitiate.setFrom(from);
sessionInitiate.setInitiator(from);
sessionInitiate.setType(IQ.Type.SET);
sessionInitiate.setID(sid);
sessionInitiate.setGTalkType(GTalkType.CANDIDATES);
sessionInitiate.addExtension(candidate);
return sessionInitiate;
}
/**
* Converts the ICE media <tt>stream</tt> and its local candidates into a
* list of Google Talk candidates.
*
* @param name of the stream
* @param stream the {@link IceMediaStream} that we'd like to describe in
* XML.
*
* @return the list of Google Talk candidates
*/
public static List<GTalkCandidatePacketExtension> createCandidates(
String name,
IceMediaStream stream)
{
List<GTalkCandidatePacketExtension> exts = new
ArrayList<GTalkCandidatePacketExtension>();
for(Component component : stream.getComponents())
{
String mediaName = null;
if(name.equals("rtp"))
{
if(component.getComponentID() == 1)
{
mediaName = name;
}
else
{
mediaName = "rtcp";
// Audio RTCP is never used in Google Talk and it is also
// never transmitted by Gmail client
}
}
else if(name.equals("video_rtp"))
{
if(component.getComponentID() == 1)
{
mediaName = name;
}
else
{
mediaName = "video_rtcp";
}
}
for(Candidate candidate : component.getLocalCandidates())
{
exts.add(createCandidate(candidate, mediaName, stream));
}
}
return exts;
}
/**
* Creates a {@link GTalkCandidatePacketExtension} and initializes it so
* that it would describe the state of <tt>candidate</tt>
*
* @param candidate the ICE4J {@link Candidate} that we'd like to convert
* into an Google Talk packet extension.
* @param name name of the candidate extension
* @param stream ICE stream
*
* @return a new {@link GTalkCandidatePacketExtension} corresponding to the
* state of the <tt>candidate</tt> candidate.
*/
private static GTalkCandidatePacketExtension createCandidate(
Candidate candidate, String name, IceMediaStream stream)
{
GTalkCandidatePacketExtension packet =
new GTalkCandidatePacketExtension();
Component component = candidate.getParentComponent();
packet.setName(name);
packet.setProtocol(candidate.getTransport().toString());
packet.setGeneration(
component.getParentStream().getParentAgent().getGeneration());
TransportAddress transportAddress = candidate.getTransportAddress();
// XXX different username/password for each candidate ?
packet.setUsername(stream.getParentAgent().getLocalUfrag());
packet.setPassword("");
packet.setAddress(transportAddress.getHostAddress());
packet.setPort(transportAddress.getPort());
packet.setNetwork(0);
packet.setFoundation(0);
packet.setComponent(component.getComponentID());
CandidateType candType = CandidateType.valueOf(
candidate.getType().toString());
if(candType == CandidateType.srflx)
{
candType = CandidateType.stun;
}
else if(candType == CandidateType.host)
{
candType = CandidateType.local;
}
packet.setType(candType);
packet.setPreference(candidate.getPriority() / 1000);
return packet;
}
}

@ -0,0 +1,92 @@
/*
* Jitsi, the OpenSource Java VoIP and Instant Messaging client.
*
* Distributable under LGPL license.
* See terms of license at gnu.org.
*/
package net.java.sip.communicator.impl.protocol.jabber.extensions.gtalk;
/**
* Enumeration of all possible type field value for Google Talk session IQ.
*
* @author Sebastien Vincent
*/
public enum GTalkType
{
/**
* Initiate type.
*/
INITIATE("initiate"),
/**
* Accept type.
*/
ACCEPT("accept"),
/**
* Candidate type.
*/
CANDIDATES("candidates"),
/**
* Reject type.
*/
REJECT("reject"),
/**
* Terminate type.
*/
TERMINATE("terminate");
/**
* The name of this type.
*/
private final String typeName;
/**
* Creates a <tt>GTalkType</tt> instance with the specified name.
*
* @param typeName the name of the <tt>GTalkType</tt> we'd like
* to create.
*/
private GTalkType(String typeName)
{
this.typeName = typeName;
}
/**
* Returns the name of this <tt>GTalkType</tt> (e.g. "initiate"
* or "accept"). The name returned by this method is meant for
* use directly in the XMPP XML string.
*
* @return Returns the name of this <tt>GTalkType</tt>
*/
@Override
public String toString()
{
return typeName;
}
/**
* Returns a <tt>GTalkType</tt> value corresponding to the specified
* <tt>gtalkTypeStr</tt>.
*
* @param gtalkTypeStr the action <tt>String</tt> that we'd like to
* parse.
* @return a <tt>GTalkType</tt> value corresponding to the specified
* <tt>GTalkTypeStr</tt>.
*
* @throws IllegalArgumentException in case <tt>GTalkTypeStr</tt> is
* not a valid media direction.
*/
public static GTalkType parseString(String gtalkTypeStr)
throws IllegalArgumentException
{
for (GTalkType value : values())
if (value.toString().equals(gtalkTypeStr))
return value;
throw new IllegalArgumentException(
gtalkTypeStr + " is not a valid Google Talk type");
}
}

@ -0,0 +1,225 @@
/*
* Jitsi, the OpenSource Java VoIP and Instant Messaging client.
*
* Distributable under LGPL license.
* See terms of license at gnu.org.
*/
package net.java.sip.communicator.impl.protocol.jabber.extensions.gtalk;
import java.math.*;
import java.security.*;
import net.java.sip.communicator.impl.protocol.jabber.extensions.jingle.*;
import org.jivesoftware.smack.packet.*;
import org.jivesoftware.smack.util.*;
/**
* A straightforward extension of the IQ. A <tt>SessionIQ</tt> object is created
* by smack via the {@link SessionIQProvider}. It contains all the information
* extracted from a <tt>Session</tt> IQ.
*
* @author Sebastien Vincent
*/
public class SessionIQ
extends IQ
{
/**
* The name space that session belongs to.
*/
public static final String NAMESPACE = "http://www.google.com/session";
/**
* The name of the element that contains the session data.
*/
public static final String ELEMENT_NAME = "session";
/**
* The name of the argument that contains the session type value.
*/
public static final String TYPE_ATTR_NAME = "type";
/**
* The name of the argument that contains the "initiator" jid.
*/
public static final String INITIATOR_ATTR_NAME = "initiator";
/**
* The name of the argument that contains the session id.
*/
public static final String ID_ATTR_NAME = "id";
/**
* The <tt>GTalkType</tt> that describes the purpose of this
* <tt>session</tt> element.
*/
private GTalkType gtalkType;
/**
* The full JID of the entity that has initiated the session flow.
*/
private String initiator = null;
/**
* The ID of the GTalk session that this IQ belongs to.
*/
private String id = null;
/**
* The <tt>reason</tt> extension in a <tt>session</tt> IQ providers machine
* and possibly human-readable information about the reason for the action.
*/
private ReasonPacketExtension reason = null;
/**
* Sets this element's session ID value.
*
* @param id the session ID to set
*/
public void setID(String id)
{
this.id = id;
}
/**
* Returns this element's session ID value.
*
* @return this element's session ID.
*/
public String getID()
{
return id;
}
/**
* Generates a random <tt>String</tt> usable as a session ID.
*
* @return a newly generated random sid <tt>String</tt>
*/
public static String generateSID()
{
return new BigInteger(64, new SecureRandom()).toString(32);
}
/**
* Sets the full JID of the entity that has initiated the session flow. Only
* present when the <tt>GTalkType</tt> is <tt>accept</tt>.
*
* @param initiator the full JID of the initiator.
*/
public void setInitiator(String initiator)
{
this.initiator = initiator;
}
/**
* Returns the full JID of the entity that has initiated the session flow.
* Only present when the <tt>GTalkType</tt> is <tt>session-accept</tt>.
*
* @return the full JID of the initiator.
*/
public String getInitiator()
{
return initiator;
}
/**
* Sets the value of this element's <tt>action</tt> attribute. The value of
* the 'action' attribute MUST be one of the values enumerated here. If an
* entity receives a value not defined here, it MUST ignore the attribute
* and MUST return a <tt>bad-request</tt> error to the sender. There is no
* default value for the 'action' attribute.
*
* @param gtalkType the value of the <tt>action</tt> attribute.
*/
public void setGTalkType(GTalkType gtalkType)
{
this.gtalkType = gtalkType;
}
/**
* Returns the value of this element's <tt>action</tt> attribute. The value
* of the 'action' attribute MUST be one of the values enumerated here. If
* an entity receives a value not defined here, it MUST ignore the attribute
* and MUST return a <tt>bad-request</tt> error to the sender. There is no
* default value for the 'action' attribute.
*
* @return the value of the <tt>action</tt> attribute.
*/
public GTalkType getGTalkType()
{
return gtalkType;
}
/**
* Specifies this IQ's <tt>reason</tt> extension. The <tt>reason</tt>
* extension in a <tt>session</tt> IQ provides machine and possibly human
* -readable information about the reason for the action.
*
* @param reason this IQ's <tt>reason</tt> extension.
*/
public void setReason(ReasonPacketExtension reason)
{
this.reason = reason;
}
/**
* Returns this IQ's <tt>reason</tt> extension. The <tt>reason</tt>
* extension in a <tt>session</tt> IQ provides machine and possibly human
* -readable information about the reason for the action.
*
* @return this IQ's <tt>reason</tt> extension.
*/
public ReasonPacketExtension getReason()
{
return reason;
}
/**
* Returns the XML string of this GTalk session IQ's "section" sub-element.
*
* Extensions of this class must override this method.
*
* @return the child element section of the IQ XML.
*/
@Override
public String getChildElementXML()
{
StringBuilder bldr = new StringBuilder("<" + ELEMENT_NAME);
bldr.append(" xmlns='" + NAMESPACE + "'");
bldr.append(" " + TYPE_ATTR_NAME + "='" + getGTalkType() + "'");
if( initiator != null)
bldr.append(" " + INITIATOR_ATTR_NAME
+ "='" + getInitiator() + "'");
bldr.append(" " + ID_ATTR_NAME
+ "='" + getID() + "'");
String extensionsXML = getExtensionsXML();
if ((extensionsXML == null) || (extensionsXML.length() == 0) &&
reason == null)
{
bldr.append("/>");
}
else
{
bldr.append(">");//it is possible to have empty session elements
//reason
if (reason != null)
bldr.append(reason.toXML());
// extensions
if ((extensionsXML != null) && (extensionsXML.length() != 0))
bldr.append(extensionsXML);
bldr.append("</" + ELEMENT_NAME + ">");
}
return bldr.toString();
}
}

@ -0,0 +1,198 @@
/*
* Jitsi, the OpenSource Java VoIP and Instant Messaging client.
*
* Distributable under LGPL license.
* See terms of license at gnu.org.
*/
package net.java.sip.communicator.impl.protocol.jabber.extensions.gtalk;
import net.java.sip.communicator.impl.protocol.jabber.extensions.*;
import net.java.sip.communicator.impl.protocol.jabber.extensions.jingle.*;
import org.jivesoftware.smack.packet.*;
import org.jivesoftware.smack.provider.*;
import org.xmlpull.v1.*;
/**
* An implementation of a GTalk session IQ provider that parses incoming session IQs.
*
* @author Sebastien Vincent
*/
public class SessionIQProvider
implements IQProvider
{
/**
* Namespace for "audio" description.
*/
public static final String GTALK_AUDIO_NAMESPACE =
"http://www.google.com/session/phone";
/**
* Namespace for "video" description.
*/
public static final String GTALK_VIDEO_NAMESPACE =
"http://www.google.com/session/video";
/**
* Creates a new instance of the <tt>SessionIQProvider</tt> and register all
* GTalk related extension providers. It is the responsibility of the
* application to register the <tt>SessionIQProvider</tt> itself.
*/
public SessionIQProvider()
{
ProviderManager providerManager = ProviderManager.getInstance();
providerManager.addExtensionProvider(
RtpDescriptionPacketExtension.ELEMENT_NAME,
GTALK_AUDIO_NAMESPACE,
new DefaultPacketExtensionProvider
<RtpDescriptionPacketExtension>(
RtpDescriptionPacketExtension.class));
providerManager.addExtensionProvider(
RtpDescriptionPacketExtension.ELEMENT_NAME,
GTALK_VIDEO_NAMESPACE,
new DefaultPacketExtensionProvider
<RtpDescriptionPacketExtension>(
RtpDescriptionPacketExtension.class));
providerManager.addExtensionProvider(
PayloadTypePacketExtension.ELEMENT_NAME,
GTALK_AUDIO_NAMESPACE,
new DefaultPacketExtensionProvider
<PayloadTypePacketExtension>(
PayloadTypePacketExtension.class));
providerManager.addExtensionProvider(
PayloadTypePacketExtension.ELEMENT_NAME,
GTALK_VIDEO_NAMESPACE,
new DefaultPacketExtensionProvider
<PayloadTypePacketExtension>(
PayloadTypePacketExtension.class));
providerManager.addExtensionProvider(
EncryptionPacketExtension.ELEMENT_NAME,
null,
new DefaultPacketExtensionProvider<EncryptionPacketExtension>(
EncryptionPacketExtension.class));
providerManager.addExtensionProvider(
SrcIdPacketExtension.ELEMENT_NAME,
GTALK_AUDIO_NAMESPACE,
new SrcIdProvider());
providerManager.addExtensionProvider(
SrcIdPacketExtension.ELEMENT_NAME,
GTALK_VIDEO_NAMESPACE,
new SrcIdProvider());
providerManager.addExtensionProvider(
UsagePacketExtension.ELEMENT_NAME,
null,
new DefaultPacketExtensionProvider<UsagePacketExtension>(
UsagePacketExtension.class));
}
/**
* Parses a GTalk session IQ sub-document and returns a {@link SessionIQ}
* instance.
*
* @param parser an XML parser.
*
* @return a new {@link SessionIQ} instance.
*
* @throws Exception if an error occurs parsing the XML.
*/
@Override
public IQ parseIQ(XmlPullParser parser) throws Exception
{
SessionIQ sessionIQ = new SessionIQ();
boolean done = false;
//let's first handle the "session" element params.
GTalkType type = GTalkType.parseString(parser
.getAttributeValue("", SessionIQ.TYPE_ATTR_NAME));
String initiator = parser
.getAttributeValue("", SessionIQ.INITIATOR_ATTR_NAME);
String id = parser
.getAttributeValue("", SessionIQ.ID_ATTR_NAME);
sessionIQ.setGTalkType(type);
sessionIQ.setInitiator(initiator);
sessionIQ.setID(id);
// Sub-elements providers
DefaultPacketExtensionProvider<GTalkCandidatePacketExtension>
candidateProvider
= new DefaultPacketExtensionProvider<
GTalkCandidatePacketExtension>(
GTalkCandidatePacketExtension.class);
DefaultPacketExtensionProvider<RtpDescriptionPacketExtension>
descriptionProvider
= new
DefaultPacketExtensionProvider<RtpDescriptionPacketExtension>(
RtpDescriptionPacketExtension.class);
ReasonProvider reasonProvider = new ReasonProvider();
//int nbTab = 0;
// Now go on and parse the session element's content.
while (!done)
{
int eventType = parser.next();
String elementName = parser.getName();
if (eventType == XmlPullParser.START_TAG)
{
/*
String namespace = parser.getNamespace();;
String tab = "";
nbTab++;
for(int ii = 0 ; ii < nbTab ; ii++)
tab += "\t";
System.out.println(tab + parser.getName() + " " +
parser.getNamespace());
for(int i = 0 ; i < parser.getAttributeCount() ; i++)
{
System.out.print(tab + "\t");
System.out.println(parser.getAttributeName(i) + "=" +
parser.getAttributeValue(i));
}
*/
if(elementName.equals(CandidatePacketExtension.ELEMENT_NAME))
{
sessionIQ.addExtension(
candidateProvider.parseExtension(parser));
}
else if(elementName.equals(
RtpDescriptionPacketExtension.ELEMENT_NAME))
{
RtpDescriptionPacketExtension ext =
descriptionProvider.parseExtension(parser);
sessionIQ.addExtension(ext);
}
else if(elementName.equals(ReasonPacketExtension.ELEMENT_NAME))
{
ReasonPacketExtension reason
= reasonProvider.parseExtension(parser);
sessionIQ.setReason(reason);
}
}
if (eventType == XmlPullParser.END_TAG)
{
//nbTab--;
if (parser.getName().equals(SessionIQ.ELEMENT_NAME))
{
done = true;
}
}
}
return sessionIQ;
}
}

@ -0,0 +1,48 @@
/*
* Jitsi, the OpenSource Java VoIP and Instant Messaging client.
*
* Distributable under LGPL license.
* See terms of license at gnu.org.
*/
package net.java.sip.communicator.impl.protocol.jabber.extensions.gtalk;
import net.java.sip.communicator.impl.protocol.jabber.extensions.*;
/**
* SRC-ID packet extension.
*
* @author Sebastien Vincent
*/
public class SrcIdPacketExtension
extends AbstractPacketExtension
{
/**
* The namespace that URIs belongs to.
*/
public static final String NAMESPACE = "";
/**
* The name of the element that contains the URIs data.
*/
public static final String ELEMENT_NAME = "src-id";
/**
* Constructor.
*
* @param namespace namespace
*/
public SrcIdPacketExtension(String namespace)
{
super(namespace, ELEMENT_NAME);
}
/**
* Set source ID.
*
* @param srcId source ID
*/
public void setSrcId(String srcId)
{
this.setText(srcId);
}
}

@ -0,0 +1,67 @@
/*
* Jitsi, the OpenSource Java VoIP and Instant Messaging client.
*
* Distributable under LGPL license.
* See terms of license at gnu.org.
*/
package net.java.sip.communicator.impl.protocol.jabber.extensions.gtalk;
import net.java.sip.communicator.impl.protocol.jabber.extensions.jingle.*;
import org.jivesoftware.smack.packet.*;
import org.jivesoftware.smack.provider.*;
import org.xmlpull.v1.*;
/**
* Parser for src-id packet extension.
*
* @author Sebastien Vincent
*/
public class SrcIdProvider
implements PacketExtensionProvider
{
/**
* Parses a reason extension sub-packet and creates a {@link
* ReasonPacketExtension} instance. At the beginning of the method call,
* the xml parser will be positioned on the opening element of the packet
* extension. As required by the smack API, at the end of the method call,
* the parser will be positioned on the closing element of the packet
* extension.
*
* @param parser an XML parser positioned at the opening <tt>reason</tt>
* element.
*
* @return a new {@link ReasonPacketExtension} instance.
* @throws java.lang.Exception if an error occurs parsing the XML.
*/
public PacketExtension parseExtension(XmlPullParser parser)
throws Exception
{
boolean done = false;
int eventType;
String ns = parser.getNamespace();
SrcIdPacketExtension ext
= new SrcIdPacketExtension(ns);
while (!done)
{
eventType = parser.next();
if (eventType == XmlPullParser.TEXT)
{
ext.setText(parser.getText());
}
else if (eventType == XmlPullParser.END_TAG)
{
if (parser.getName().equals(
SrcIdPacketExtension.ELEMENT_NAME))
{
done = true;
}
}
}
return ext;
}
}

@ -0,0 +1,36 @@
/*
* Jitsi, the OpenSource Java VoIP and Instant Messaging client.
*
* Distributable under LGPL license.
* See terms of license at gnu.org.
*/
package net.java.sip.communicator.impl.protocol.jabber.extensions.gtalk;
import net.java.sip.communicator.impl.protocol.jabber.extensions.*;
/**
* URIs packet extension.
*
* @author Sebastien Vincent
*/
public class UsagePacketExtension
extends AbstractPacketExtension
{
/**
* The namespace that URIs belongs to.
*/
public static final String NAMESPACE = "";
/**
* The name of the element that contains the URIs data.
*/
public static final String ELEMENT_NAME = "usage";
/**
* Constructor.
*/
public UsagePacketExtension()
{
super(NAMESPACE, ELEMENT_NAME);
}
}

@ -48,5 +48,15 @@ public enum CandidateType
* Binding request, or TURN servers, which provides both a relayed and
* server reflexive candidate.
*/
srflx;
srflx,
/**
* Old name for Server Reflexive Candidate used by Google Talk.
*/
stun,
/**
* Old name for Host Candidate used by Google Talk.
*/
local;
}

@ -46,7 +46,6 @@ public EncryptionPacketExtension()
super(null, ELEMENT_NAME);
}
/**
* Adds a new <tt>crypto</tt> element to this encryption element.
*

@ -6,8 +6,6 @@
*/
package net.java.sip.communicator.impl.protocol.jabber.extensions.jingle;
import java.util.logging.*;
import net.java.sip.communicator.impl.protocol.jabber.extensions.*;
import org.jivesoftware.smack.provider.*;
@ -20,13 +18,6 @@
*/
public class JingleIQProvider implements IQProvider
{
/**
* The <tt>Logger</tt> used by the <tt>JingleIQProvider</tt>
* class and its instances for logging output.
*/
private static final Logger logger = Logger
.getLogger(JingleIQProvider.class.getName());
/**
* Creates a new instance of the <tt>JingleIQProvider</tt> and register all
* jingle related extension providers. It is the responsibility of the

@ -194,9 +194,8 @@ public static JingleIQ createSessionTerminate(String from,
* @param contentList the content elements containing media and transport
* descriptions.
*
* @return the newly constructed {@link JingleIQ} <tt>session-terminate</tt>
* @return the newly constructed {@link JingleIQ} <tt>session-accept</tt>
* packet.
* .
*/
public static JingleIQ createSessionAccept(
String from,
@ -230,7 +229,7 @@ public static JingleIQ createSessionAccept(
* @param contentList the content elements containing media and transport
* descriptions.
*
* @return the newly constructed {@link JingleIQ} <tt>session-terminate</tt>
* @return the newly constructed {@link JingleIQ} <tt>session-initiate</tt>
* packet.
*/
public static JingleIQ createSessionInitiate(

@ -78,6 +78,17 @@ public RtpDescriptionPacketExtension()
super(NAMESPACE, ELEMENT_NAME);
}
/**
* Create a new <tt>RtpDescriptionPacketExtension</tt> with a different
* namespace.
*
* @param namespace namespace to use
*/
public RtpDescriptionPacketExtension(String namespace)
{
super(namespace, ELEMENT_NAME);
}
/**
* Specifies the media type for the stream that this description element
* represents, such as "audio" or "video".
@ -177,6 +188,8 @@ public List<? extends PacketExtension> getChildExtensions()
if (extmapList != null)
children.addAll(extmapList);
children.addAll(super.getChildExtensions());
return children;
}
@ -199,6 +212,8 @@ else if (childExtension instanceof BandwidthPacketExtension)
else if (childExtension instanceof RTPHdrExtPacketExtension)
this.addExtmap((RTPHdrExtPacketExtension)childExtension);
else
super.addChildExtension(childExtension);
}
/**

Loading…
Cancel
Save