mirror of
https://codeberg.org/Mercury-IM/Smack
synced 2025-12-06 05:01:12 +01:00
Jingle Extension added to Smack Repository
git-svn-id: http://svn.igniterealtime.org/svn/repos/smack/trunk@6517 b35dd754-fafc-0310-a699-88a17e54d16e
This commit is contained in:
parent
f1972c2571
commit
4b6de6647b
104 changed files with 16411 additions and 0 deletions
|
|
@ -0,0 +1,504 @@
|
|||
/**
|
||||
* $RCSfile$
|
||||
* $Revision: 2407 $
|
||||
* $Date: 2004-11-02 23:37:00 +0000 (Tue, 02 Nov 2004) $
|
||||
*
|
||||
* Copyright 2003-2004 Jive Software.
|
||||
*
|
||||
* All rights reserved. Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.jivesoftware.smackx.packet;
|
||||
|
||||
import org.jivesoftware.smack.packet.IQ;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* An Jingle sub-packet, which is used by XMPP clients to exchange info like
|
||||
* descriptions and transports. <p/> The following link summarizes the
|
||||
* requirements of Jingle IM: <a
|
||||
* href="http://www.jabber.org/jeps/jep-0166.html">Valid tags</a>.
|
||||
* <p/>
|
||||
* <p/> Warning: this is an non-standard protocol documented by <a
|
||||
* href="http://www.jabber.org/jeps/jep-0166.html">JEP-166</a>. Because this is
|
||||
* a non-standard protocol, it is subject to change.
|
||||
*
|
||||
* @author Alvaro Saurin
|
||||
*/
|
||||
public class Jingle extends IQ {
|
||||
|
||||
// static
|
||||
|
||||
public static final String NAMESPACE = "http://jabber.org/protocol/jingle";
|
||||
|
||||
public static final String NODENAME = "jingle";
|
||||
|
||||
// non-static
|
||||
|
||||
private String sid; // The session id
|
||||
|
||||
private Action action; // The action associated to the Jingle
|
||||
|
||||
private String initiator; // The initiator as a "user@host/resource"
|
||||
|
||||
private String responder; // The responder
|
||||
|
||||
// Sub-elements of a Jingle object.
|
||||
|
||||
private final List descriptions = new ArrayList();
|
||||
|
||||
private final List transports = new ArrayList();
|
||||
|
||||
private JingleContentInfo contentInfo;
|
||||
|
||||
/**
|
||||
* A constructor where the main components can be initialized.
|
||||
*/
|
||||
public Jingle(final List descs, final List trans, final JingleContentInfo mi,
|
||||
final String sid) {
|
||||
super();
|
||||
|
||||
if (descs != null) {
|
||||
descriptions.addAll(descs);
|
||||
}
|
||||
|
||||
if (trans != null) {
|
||||
transports.addAll(trans);
|
||||
}
|
||||
|
||||
setContentInfo(mi);
|
||||
setSid(sid);
|
||||
|
||||
// Set null all other fields in the packet
|
||||
initiator = null;
|
||||
responder = null;
|
||||
action = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor with a description.
|
||||
*
|
||||
* @param descr a description
|
||||
*/
|
||||
public Jingle(final JingleContentDescription descr) {
|
||||
super();
|
||||
|
||||
addDescription(descr);
|
||||
|
||||
// Set null all other fields in the packet
|
||||
initiator = null;
|
||||
responder = null;
|
||||
|
||||
// Some default values for the most common situation...
|
||||
action = Jingle.Action.DESCRIPTIONINFO;
|
||||
this.setType(IQ.Type.SET);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor with a transport.
|
||||
*
|
||||
* @param trans a transport
|
||||
*/
|
||||
public Jingle(final JingleTransport trans) {
|
||||
super();
|
||||
|
||||
addTransport(trans);
|
||||
|
||||
// Set null all other fields in the packet
|
||||
initiator = null;
|
||||
responder = null;
|
||||
|
||||
// Some default values for the most common situation...
|
||||
action = Jingle.Action.TRANSPORTINFO;
|
||||
this.setType(IQ.Type.SET);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor with a content info.
|
||||
*
|
||||
* @param info The content info
|
||||
*/
|
||||
public Jingle(final JingleContentInfo info) {
|
||||
super();
|
||||
|
||||
setContentInfo(info);
|
||||
|
||||
// Set null all other fields in the packet
|
||||
initiator = null;
|
||||
responder = null;
|
||||
|
||||
// Some default values for the most common situation...
|
||||
action = Jingle.Action.DESCRIPTIONINFO;
|
||||
this.setType(IQ.Type.SET);
|
||||
}
|
||||
|
||||
/**
|
||||
* A constructor where the action can be specified.
|
||||
*
|
||||
* @param action The action.
|
||||
*/
|
||||
public Jingle(final Jingle.Action action) {
|
||||
this(null, null, null, null);
|
||||
this.action = action;
|
||||
|
||||
// In general, a Jingle with an action is used in a SET packet...
|
||||
this.setType(IQ.Type.SET);
|
||||
}
|
||||
|
||||
/**
|
||||
* A constructor where the session ID can be specified.
|
||||
*
|
||||
* @param sid The session ID related to the negotiation.
|
||||
* @see #setSid(String)
|
||||
*/
|
||||
public Jingle(final String sid) {
|
||||
this(null, null, null, sid);
|
||||
}
|
||||
|
||||
/**
|
||||
* The default constructor
|
||||
*/
|
||||
public Jingle() {
|
||||
super();
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the session ID related to this session. The session ID is a unique
|
||||
* identifier generated by the initiator. This should match the XML Nmtoken
|
||||
* production so that XML character escaping is not needed for characters
|
||||
* such as &.
|
||||
*
|
||||
* @param sid the session ID
|
||||
*/
|
||||
public final void setSid(final String sid) {
|
||||
this.sid = sid;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the session ID related to the session. The session ID is a unique
|
||||
* identifier generated by the initiator. This should match the XML Nmtoken
|
||||
* production so that XML character escaping is not needed for characters
|
||||
* such as &.
|
||||
*
|
||||
* @return Returns the session ID related to the session.
|
||||
* @see #setSid(String)
|
||||
*/
|
||||
public String getSid() {
|
||||
|
||||
return sid;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the XML element name of the extension sub-packet root element.
|
||||
* Always returns "jingle"
|
||||
*
|
||||
* @return the XML element name of the packet extension.
|
||||
*/
|
||||
public static String getElementName() {
|
||||
return NODENAME;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the XML namespace of the extension sub-packet root element.
|
||||
* According the specification the namespace is always
|
||||
* "http://jabber.org/protocol/jingle"
|
||||
*
|
||||
* @return the XML namespace of the packet extension.
|
||||
*/
|
||||
public static String getNamespace() {
|
||||
return NAMESPACE;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the audioInfo
|
||||
*/
|
||||
public JingleContentInfo getContentInfo() {
|
||||
return contentInfo;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param contentInfo the audioInfo to set
|
||||
*/
|
||||
public void setContentInfo(final JingleContentInfo contentInfo) {
|
||||
this.contentInfo = contentInfo;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get an iterator for the content descriptions
|
||||
*
|
||||
* @return the descriptions
|
||||
*/
|
||||
public Iterator getDescriptions() {
|
||||
synchronized (descriptions) {
|
||||
return Collections.unmodifiableList(new ArrayList(descriptions)).iterator();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get an iterator for the content descriptions
|
||||
*
|
||||
* @return the descriptions
|
||||
*/
|
||||
public ArrayList getDescriptionsList() {
|
||||
synchronized (descriptions) {
|
||||
return new ArrayList(descriptions);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a new content description.
|
||||
*
|
||||
* @param desc the descriptions to add
|
||||
*/
|
||||
public void addDescription(final JingleContentDescription desc) {
|
||||
if (desc != null) {
|
||||
synchronized (descriptions) {
|
||||
descriptions.add(desc);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a list of JingleContentDescription elements
|
||||
*
|
||||
* @param descsList the list of transports to add
|
||||
*/
|
||||
public void addDescriptions(final List descsList) {
|
||||
if (descsList != null) {
|
||||
synchronized (descriptions) {
|
||||
descriptions.addAll(descsList);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get an iterator for the transport.
|
||||
*
|
||||
* @return the transports
|
||||
*/
|
||||
public Iterator getTransports() {
|
||||
synchronized (transports) {
|
||||
return Collections.unmodifiableList(new ArrayList(transports)).iterator();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the list of transports.
|
||||
*
|
||||
* @return the transports list.
|
||||
*/
|
||||
public ArrayList getTransportsList() {
|
||||
synchronized (transports) {
|
||||
return new ArrayList(transports);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a new TransportNegotiator element
|
||||
*
|
||||
* @param trans the transports to add
|
||||
*/
|
||||
public void addTransport(final JingleTransport trans) {
|
||||
if (trans != null) {
|
||||
synchronized (transports) {
|
||||
transports.add(trans);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a list of TransportNegotiator elements
|
||||
*
|
||||
* @param transList the list of transports to add
|
||||
*/
|
||||
public void addTransports(final List transList) {
|
||||
if (transList != null) {
|
||||
synchronized (transports) {
|
||||
transports.addAll(transList);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the action specified in the packet
|
||||
*
|
||||
* @return the action
|
||||
*/
|
||||
public Action getAction() {
|
||||
return action;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the action in the packet
|
||||
*
|
||||
* @param action the action to set
|
||||
*/
|
||||
public void setAction(final Action action) {
|
||||
this.action = action;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the initiator. The initiator will be the full JID of the entity that
|
||||
* has initiated the flow (which may be different to the "from" address in
|
||||
* the IQ)
|
||||
*
|
||||
* @return the initiator
|
||||
*/
|
||||
public String getInitiator() {
|
||||
return initiator;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the initiator. The initiator must be the full JID of the entity that
|
||||
* has initiated the flow (which may be different to the "from" address in
|
||||
* the IQ)
|
||||
*
|
||||
* @param initiator the initiator to set
|
||||
*/
|
||||
public void setInitiator(final String initiator) {
|
||||
this.initiator = initiator;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the responder. The responder is the full JID of the entity that has
|
||||
* replied to the initiation (which may be different to the "to" addresss in
|
||||
* the IQ).
|
||||
*
|
||||
* @return the responder
|
||||
*/
|
||||
public String getResponder() {
|
||||
return responder;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the responder. The responder must be the full JID of the entity that
|
||||
* has replied to the initiation (which may be different to the "to"
|
||||
* addresss in the IQ).
|
||||
*
|
||||
* @param resp the responder to set
|
||||
*/
|
||||
public void setResponder(final String resp) {
|
||||
responder = resp;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a hash key for the session this packet belongs to.
|
||||
*
|
||||
* @param sid The session id
|
||||
* @param initiator The initiator
|
||||
* @return A hash key
|
||||
*/
|
||||
public static int getSessionHash(final String sid, final String initiator) {
|
||||
final int PRIME = 31;
|
||||
int result = 1;
|
||||
result = PRIME * result + (initiator == null ? 0 : initiator.hashCode());
|
||||
result = PRIME * result + (sid == null ? 0 : sid.hashCode());
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the XML representation of the packet.
|
||||
*
|
||||
* @return the XML string
|
||||
*/
|
||||
public String getChildElementXML() {
|
||||
StringBuilder buf = new StringBuilder();
|
||||
|
||||
buf.append("<").append(getElementName());
|
||||
buf.append(" xmlns=\"").append(getNamespace()).append("\"");
|
||||
if (getInitiator() != null) {
|
||||
buf.append(" initiator=\"").append(getInitiator()).append("\"");
|
||||
}
|
||||
if (getResponder() != null) {
|
||||
buf.append(" responder=\"").append(getResponder()).append("\"");
|
||||
}
|
||||
if (getAction() != null) {
|
||||
buf.append(" action=\"").append(getAction()).append("\"");
|
||||
}
|
||||
if (getSid() != null) {
|
||||
buf.append(" sid=\"").append(getSid()).append("\"");
|
||||
}
|
||||
buf.append(">");
|
||||
//TODO Update to accept more than one content per session (XEP-0166)
|
||||
|
||||
buf.append("<content name='Audio-Content'>");
|
||||
// Look for possible payload types, and dump them.
|
||||
synchronized (descriptions) {
|
||||
for (int i = 0; i < descriptions.size(); i++) {
|
||||
JingleContentDescription desc = (JingleContentDescription) descriptions
|
||||
.get(i);
|
||||
buf.append(desc.toXML());
|
||||
}
|
||||
}
|
||||
|
||||
// If the packet has transports, dump them.
|
||||
synchronized (transports) {
|
||||
for (int i = 0; i < transports.size(); i++) {
|
||||
JingleTransport trans = (JingleTransport) transports.get(i);
|
||||
buf.append(trans.toXML());
|
||||
}
|
||||
}
|
||||
buf.append("</content>");
|
||||
|
||||
// and the same for audio jmf info
|
||||
if (contentInfo != null) {
|
||||
buf.append(contentInfo.toXML());
|
||||
}
|
||||
|
||||
buf.append("</").append(getElementName()).append(">");
|
||||
return buf.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* The "action" in the jingle packet, as an enum.
|
||||
*/
|
||||
public static enum Action {
|
||||
|
||||
CONTENTACCEPT, CONTENTADD, CONTENTDECLINE, CONTENTMODIFY,
|
||||
CONTENTREMOVE, DESCRIPTIONADD, DESCRIPTIONDECLINE,
|
||||
DESCRIPTIONINFO, DESCRIPTIONMODIFY, SESSIONACCEPT,
|
||||
SESSIONINFO, SESSIONINITIATE, SESSIONREDIRECT,
|
||||
SESSIONTERMINATE, TRANSPORTACCEPT, TRANSPORTDECLINE,
|
||||
TRANSPORTINFO, TRANSPORTMODIFY;
|
||||
|
||||
private static String names[] = {"content-accept", "content-add", "content-decline", "content-modify",
|
||||
"content-remove", "description-accept", "description-decline", "description-info",
|
||||
"description-modify", "session-accept", "session-info", "session-initiate",
|
||||
"session-redirect", "session-terminate", "transport-accept", "transport-decline",
|
||||
"transport-info", "transport-modify"};
|
||||
|
||||
/**
|
||||
* Returns the String value for an Action.
|
||||
*/
|
||||
|
||||
public String toString() {
|
||||
return names[this.ordinal()];
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the Action for a String value.
|
||||
*/
|
||||
public static Action getAction(String str) {
|
||||
for (int i = 0; i < names.length; i++) {
|
||||
if (names[i].equals(str)) return Action.values()[i];
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,278 @@
|
|||
package org.jivesoftware.smackx.packet;
|
||||
|
||||
import org.jivesoftware.smack.packet.PacketExtension;
|
||||
import org.jivesoftware.smackx.jingle.media.PayloadType;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Jingle content description.
|
||||
*
|
||||
* @author Alvaro Saurin <alvaro.saurin@gmail.com>
|
||||
*/
|
||||
public abstract class JingleContentDescription implements PacketExtension {
|
||||
|
||||
// static
|
||||
|
||||
public static final String NODENAME = "description";
|
||||
|
||||
// non-static
|
||||
|
||||
private final List payloads = new ArrayList();
|
||||
|
||||
/**
|
||||
* Creates a content description..
|
||||
*/
|
||||
public JingleContentDescription() {
|
||||
super();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the XML element name of the element.
|
||||
*
|
||||
* @return the XML element name of the element.
|
||||
*/
|
||||
public String getElementName() {
|
||||
return NODENAME;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the namespace.
|
||||
*
|
||||
* @return The namespace
|
||||
*/
|
||||
public abstract String getNamespace();
|
||||
|
||||
/**
|
||||
* Adds a audio payload type to the packet.
|
||||
*
|
||||
* @param pt the audio payload type to add.
|
||||
*/
|
||||
public void addJinglePayloadType(final JinglePayloadType pt) {
|
||||
synchronized (payloads) {
|
||||
payloads.add(pt);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a list of payloads to the packet.
|
||||
*
|
||||
* @param pts the payloads to add.
|
||||
*/
|
||||
public void addAudioPayloadTypes(final List pts) {
|
||||
synchronized (payloads) {
|
||||
Iterator ptIter = pts.iterator();
|
||||
while (ptIter.hasNext()) {
|
||||
PayloadType.Audio pt = (PayloadType.Audio) ptIter.next();
|
||||
addJinglePayloadType(new JinglePayloadType.Audio(pt));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an Iterator for the audio payloads in the packet.
|
||||
*
|
||||
* @return an Iterator for the audio payloads in the packet.
|
||||
*/
|
||||
public Iterator getJinglePayloadTypes() {
|
||||
return Collections.unmodifiableList(getJinglePayloadTypesList()).iterator();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a list for the audio payloads in the packet.
|
||||
*
|
||||
* @return a list for the audio payloads in the packet.
|
||||
*/
|
||||
public ArrayList getJinglePayloadTypesList() {
|
||||
synchronized (payloads) {
|
||||
return new ArrayList(payloads);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the list of Payload types contained in the description.
|
||||
*
|
||||
* @return a list of PayloadType.Audio
|
||||
*/
|
||||
public ArrayList getAudioPayloadTypesList() {
|
||||
ArrayList result = new ArrayList();
|
||||
Iterator jinglePtsIter = getJinglePayloadTypes();
|
||||
|
||||
while (jinglePtsIter.hasNext()) {
|
||||
JinglePayloadType jpt = (JinglePayloadType) jinglePtsIter.next();
|
||||
if (jpt instanceof JinglePayloadType.Audio) {
|
||||
JinglePayloadType.Audio jpta = (JinglePayloadType.Audio) jpt;
|
||||
result.add(jpta.getPayloadType());
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a count of the audio payloads in the Jingle packet.
|
||||
*
|
||||
* @return the number of audio payloads in the Jingle packet.
|
||||
*/
|
||||
public int getJinglePayloadTypesCount() {
|
||||
synchronized (payloads) {
|
||||
return payloads.size();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert a Jingle description to XML.
|
||||
*
|
||||
* @return a string with the XML representation
|
||||
*/
|
||||
public String toXML() {
|
||||
StringBuilder buf = new StringBuilder();
|
||||
|
||||
synchronized (payloads) {
|
||||
if (payloads.size() > 0) {
|
||||
buf.append("<").append(getElementName());
|
||||
buf.append(" xmlns=\"").append(getNamespace()).append("\" >");
|
||||
|
||||
Iterator pt = payloads.listIterator();
|
||||
while (pt.hasNext()) {
|
||||
JinglePayloadType pte = (JinglePayloadType) pt.next();
|
||||
buf.append(pte.toXML());
|
||||
}
|
||||
buf.append("</").append(getElementName()).append(">");
|
||||
}
|
||||
}
|
||||
|
||||
return buf.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Jingle audio description
|
||||
*/
|
||||
public static class Audio extends JingleContentDescription {
|
||||
|
||||
public static final String NAMESPACE = "http://jabber.org/protocol/jingle/description/audio";
|
||||
|
||||
public Audio() {
|
||||
super();
|
||||
}
|
||||
|
||||
/**
|
||||
* Utility constructor, with a JinglePayloadType
|
||||
*/
|
||||
public Audio(final JinglePayloadType pt) {
|
||||
super();
|
||||
addJinglePayloadType(pt);
|
||||
}
|
||||
|
||||
public String getNamespace() {
|
||||
return NAMESPACE;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A payload type, contained in a descriptor.
|
||||
*
|
||||
* @author Alvaro Saurin
|
||||
*/
|
||||
public static class JinglePayloadType {
|
||||
|
||||
public static final String NODENAME = "payload-type";
|
||||
|
||||
private PayloadType payload;
|
||||
|
||||
/**
|
||||
* Create a payload type.
|
||||
*
|
||||
* @param payload the payload
|
||||
*/
|
||||
public JinglePayloadType(final PayloadType payload) {
|
||||
super();
|
||||
this.payload = payload;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an empty payload type.
|
||||
*/
|
||||
public JinglePayloadType() {
|
||||
this(null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the XML element name of the element.
|
||||
*
|
||||
* @return the XML element name of the element.
|
||||
*/
|
||||
public static String getElementName() {
|
||||
return NODENAME;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the payload represented.
|
||||
*
|
||||
* @return the payload
|
||||
*/
|
||||
public PayloadType getPayloadType() {
|
||||
return payload;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the payload represented.
|
||||
*
|
||||
* @param payload the payload to set
|
||||
*/
|
||||
public void setPayload(final PayloadType payload) {
|
||||
this.payload = payload;
|
||||
}
|
||||
|
||||
protected String getChildAttributes() {
|
||||
return null;
|
||||
}
|
||||
|
||||
public String toXML() {
|
||||
StringBuilder buf = new StringBuilder();
|
||||
|
||||
if (payload != null) {
|
||||
buf.append("<").append(getElementName()).append(" ");
|
||||
|
||||
// We covert here the payload type to XML
|
||||
if (payload.getId() != PayloadType.INVALID_PT) {
|
||||
buf.append(" id=\"").append(payload.getId()).append("\"");
|
||||
}
|
||||
if (payload.getName() != null) {
|
||||
buf.append(" name=\"").append(payload.getName()).append("\"");
|
||||
}
|
||||
if (payload.getChannels() != 0) {
|
||||
buf.append(" channels=\"").append(payload.getChannels()).append("\"");
|
||||
}
|
||||
if (getChildAttributes() != null) {
|
||||
buf.append(getChildAttributes());
|
||||
}
|
||||
buf.append("/>");
|
||||
}
|
||||
return buf.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Audio payload type element
|
||||
*/
|
||||
public static class Audio extends JinglePayloadType {
|
||||
public Audio(final PayloadType.Audio audio) {
|
||||
super(audio);
|
||||
}
|
||||
|
||||
protected String getChildAttributes() {
|
||||
StringBuilder buf = new StringBuilder();
|
||||
PayloadType pt = getPayloadType();
|
||||
if (pt instanceof PayloadType.Audio) {
|
||||
PayloadType.Audio pta = (PayloadType.Audio) pt;
|
||||
|
||||
buf.append(" clockrate=\"").append(pta.getClockRate()).append("\" ");
|
||||
}
|
||||
return buf.toString();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,138 @@
|
|||
package org.jivesoftware.smackx.packet;
|
||||
|
||||
import org.jivesoftware.smack.packet.PacketExtension;
|
||||
import org.jivesoftware.smackx.jingle.media.ContentInfo;
|
||||
|
||||
/**
|
||||
* Jingle content info
|
||||
*
|
||||
* @author Alvaro Saurin <alvaro.saurin@gmail.com>
|
||||
*/
|
||||
public class JingleContentInfo implements PacketExtension {
|
||||
|
||||
protected ContentInfo mediaInfoElement;
|
||||
|
||||
private String namespace;
|
||||
|
||||
/**
|
||||
* Empty constructor, with no jmf info.
|
||||
*/
|
||||
public JingleContentInfo() {
|
||||
this(null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor with a jmf info
|
||||
*
|
||||
* @param mediaInfoElement MediaInfo element
|
||||
*/
|
||||
public JingleContentInfo(final ContentInfo mediaInfoElement) {
|
||||
super();
|
||||
this.mediaInfoElement = mediaInfoElement;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the jmf info element.
|
||||
*
|
||||
* @return the mediaInfoElement
|
||||
*/
|
||||
public ContentInfo getMediaInfo() {
|
||||
return mediaInfoElement;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the element name
|
||||
*/
|
||||
public String getElementName() {
|
||||
// Media info is supposed to be just a single-word command...
|
||||
return getMediaInfo().toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the name space.
|
||||
*
|
||||
* @param ns the namespace
|
||||
*/
|
||||
protected void setNamespace(final String ns) {
|
||||
namespace = ns;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the publilc namespace
|
||||
*/
|
||||
public String getNamespace() {
|
||||
return namespace;
|
||||
}
|
||||
|
||||
public String toXML() {
|
||||
StringBuilder buf = new StringBuilder();
|
||||
buf.append("<").append(getElementName()).append(" xmlns=\"");
|
||||
buf.append(getNamespace()).append("\" ");
|
||||
buf.append("/>");
|
||||
return buf.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Transport part of a Jingle packet.
|
||||
*/
|
||||
public static class Audio extends JingleContentInfo {
|
||||
|
||||
public static final String NAMESPACE = "http://jabber.org/protocol/jingle/info/audio";
|
||||
|
||||
public Audio(final ContentInfo mi) {
|
||||
super(mi);
|
||||
setNamespace(NAMESPACE);
|
||||
}
|
||||
|
||||
public String getNamespace() {
|
||||
return NAMESPACE;
|
||||
}
|
||||
|
||||
// Subclasses: specialize the Audio jmf info...
|
||||
|
||||
/**
|
||||
* Busy jmf info.
|
||||
*/
|
||||
public static class Busy extends Audio {
|
||||
public Busy() {
|
||||
super(ContentInfo.Audio.BUSY);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Hold jmf info.
|
||||
*/
|
||||
public static class Hold extends Audio {
|
||||
public Hold() {
|
||||
super(ContentInfo.Audio.HOLD);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Mute jmf info.
|
||||
*/
|
||||
public static class Mute extends Audio {
|
||||
public Mute() {
|
||||
super(ContentInfo.Audio.MUTE);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Queued jmf info.
|
||||
*/
|
||||
public static class Queued extends Audio {
|
||||
public Queued() {
|
||||
super(ContentInfo.Audio.QUEUED);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Ringing jmf info.
|
||||
*/
|
||||
public static class Ringing extends Audio {
|
||||
public Ringing() {
|
||||
super(ContentInfo.Audio.RINGING);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,102 @@
|
|||
package org.jivesoftware.smackx.packet;
|
||||
|
||||
import org.jivesoftware.smack.packet.PacketExtension;
|
||||
|
||||
public class JingleError implements PacketExtension {
|
||||
|
||||
public static String NAMESPACE = "http://jabber.org/protocol/jingle#error";
|
||||
|
||||
public static final JingleError OUT_OF_ORDER = new JingleError("out-of-order");
|
||||
|
||||
public static final JingleError UNKNOWN_SESSION = new JingleError("unknown-session");
|
||||
|
||||
public static final JingleError UNSUPPORTED_CONTENT = new JingleError(
|
||||
"unsupported-content");
|
||||
|
||||
public static final JingleError UNSUPPORTED_TRANSPORTS = new JingleError(
|
||||
"unsupported-transports");
|
||||
|
||||
// Non standard error messages
|
||||
|
||||
public static final JingleError NO_COMMON_PAYLOAD = new JingleError(
|
||||
"no-common-payload");
|
||||
|
||||
public static final JingleError NEGOTIATION_ERROR = new JingleError(
|
||||
"negotiation-error");
|
||||
|
||||
public static final JingleError MALFORMED_STANZA = new JingleError("malformed-stanza");
|
||||
|
||||
private String message;
|
||||
|
||||
/**
|
||||
* Creates a new error with the specified code and message.
|
||||
*
|
||||
* @param message a message describing the error.
|
||||
*/
|
||||
public JingleError(final String message) {
|
||||
this.message = message;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the message describing the error, or null if there is no message.
|
||||
*
|
||||
* @return the message describing the error, or null if there is no message.
|
||||
*/
|
||||
public String getMessage() {
|
||||
return message;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the error as XML.
|
||||
*
|
||||
* @return the error as XML.
|
||||
*/
|
||||
public String toXML() {
|
||||
StringBuilder buf = new StringBuilder();
|
||||
if (message != null) {
|
||||
buf.append("<error type=\"cancel\">");
|
||||
buf.append("<").append(message).append(" xmlns=\"").append(NAMESPACE).append(
|
||||
"\"/>");
|
||||
buf.append("</error>");
|
||||
}
|
||||
return buf.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a Action instance associated with the String value.
|
||||
*/
|
||||
public static JingleError fromString(String value) {
|
||||
if (value != null) {
|
||||
value = value.toLowerCase();
|
||||
if (value.equals("out-of-order")) {
|
||||
return OUT_OF_ORDER;
|
||||
} else if (value.equals("unknown-session")) {
|
||||
return UNKNOWN_SESSION;
|
||||
} else if (value.equals("unsupported-content")) {
|
||||
return UNSUPPORTED_CONTENT;
|
||||
} else if (value.equals("unsupported-transports")) {
|
||||
return UNSUPPORTED_TRANSPORTS;
|
||||
} else if (value.equals("no-common-payload")) {
|
||||
return NO_COMMON_PAYLOAD;
|
||||
} else if (value.equals("negotiation-error")) {
|
||||
return NEGOTIATION_ERROR;
|
||||
} else if (value.equals("malformed-stanza")) {
|
||||
return MALFORMED_STANZA;
|
||||
}
|
||||
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return getMessage();
|
||||
}
|
||||
|
||||
public String getElementName() {
|
||||
return message;
|
||||
}
|
||||
|
||||
public String getNamespace() {
|
||||
return NAMESPACE;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,409 @@
|
|||
package org.jivesoftware.smackx.packet;
|
||||
|
||||
import org.jivesoftware.smack.packet.PacketExtension;
|
||||
import org.jivesoftware.smackx.jingle.nat.TransportCandidate;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* A jingle transport extension
|
||||
*
|
||||
* @author Alvaro Saurin <alvaro.saurin@gmail.com>
|
||||
*/
|
||||
public class JingleTransport implements PacketExtension {
|
||||
|
||||
// static
|
||||
|
||||
public static final String NODENAME = "transport";
|
||||
|
||||
// non-static
|
||||
|
||||
protected String namespace;
|
||||
|
||||
protected final List candidates = new ArrayList();
|
||||
|
||||
/**
|
||||
* Default constructor.
|
||||
*/
|
||||
public JingleTransport() {
|
||||
super();
|
||||
}
|
||||
|
||||
/**
|
||||
* Utility constructor, with a transport candidate element.
|
||||
*
|
||||
* @param candidate A transport candidate element to add.
|
||||
*/
|
||||
public JingleTransport(final JingleTransportCandidate candidate) {
|
||||
super();
|
||||
addCandidate(candidate);
|
||||
}
|
||||
|
||||
/**
|
||||
* Copy constructor.
|
||||
*
|
||||
* @param tr the other jingle transport.
|
||||
*/
|
||||
public JingleTransport(final JingleTransport tr) {
|
||||
if (tr != null) {
|
||||
namespace = tr.namespace;
|
||||
|
||||
if (tr.candidates.size() > 0) {
|
||||
candidates.addAll(tr.candidates);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a transport candidate.
|
||||
*
|
||||
* @param candidate the candidate
|
||||
*/
|
||||
public void addCandidate(final JingleTransportCandidate candidate) {
|
||||
if (candidate != null) {
|
||||
synchronized (candidates) {
|
||||
candidates.add(candidate);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get an iterator for the candidates
|
||||
*
|
||||
* @return an iterator
|
||||
*/
|
||||
public Iterator getCandidates() {
|
||||
return Collections.unmodifiableList(getCandidatesList()).iterator();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the list of candidates.
|
||||
*
|
||||
* @return The candidates list.
|
||||
*/
|
||||
public ArrayList getCandidatesList() {
|
||||
ArrayList res = null;
|
||||
synchronized (candidates) {
|
||||
res = new ArrayList(candidates);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the number of transport candidates.
|
||||
*
|
||||
* @return The number of transport candidates contained.
|
||||
*/
|
||||
public int getCandidatesCount() {
|
||||
return getCandidatesList().size();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the XML element name of the element.
|
||||
*
|
||||
* @return the XML element name of the element.
|
||||
*/
|
||||
public String getElementName() {
|
||||
return NODENAME;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the namespace.
|
||||
*
|
||||
* @param ns The namespace
|
||||
*/
|
||||
protected void setNamespace(final String ns) {
|
||||
namespace = ns;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the namespace.
|
||||
*
|
||||
* @return The namespace
|
||||
*/
|
||||
public String getNamespace() {
|
||||
return namespace;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the XML representation for this element.
|
||||
*/
|
||||
public String toXML() {
|
||||
StringBuilder buf = new StringBuilder();
|
||||
|
||||
buf.append("<").append(getElementName()).append(" xmlns=\"");
|
||||
buf.append(getNamespace()).append("\" ");
|
||||
|
||||
synchronized (candidates) {
|
||||
if (getCandidatesCount() > 0) {
|
||||
buf.append(">");
|
||||
Iterator iter = getCandidates();
|
||||
|
||||
while (iter.hasNext()) {
|
||||
JingleTransportCandidate candidate = (JingleTransportCandidate) iter
|
||||
.next();
|
||||
buf.append(candidate.toXML());
|
||||
}
|
||||
buf.append("</").append(getElementName()).append(">");
|
||||
} else {
|
||||
buf.append("/>");
|
||||
}
|
||||
}
|
||||
|
||||
return buf.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Candidate element in the transport. This class acts as a view of the
|
||||
* "TransportCandidate" in the Jingle space.
|
||||
*
|
||||
* @author Alvaro Saurin
|
||||
* @see TransportCandidate
|
||||
*/
|
||||
public static abstract class JingleTransportCandidate {
|
||||
|
||||
public static final String NODENAME = "candidate";
|
||||
|
||||
// The transport candidate contained in the element.
|
||||
protected TransportCandidate transportCandidate;
|
||||
|
||||
/**
|
||||
* Creates a new TransportNegotiator child.
|
||||
*/
|
||||
public JingleTransportCandidate() {
|
||||
super();
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new TransportNegotiator child.
|
||||
*
|
||||
* @param candidate the jmf transport candidate
|
||||
*/
|
||||
public JingleTransportCandidate(final TransportCandidate candidate) {
|
||||
super();
|
||||
setMediaTransport(candidate);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the XML element name of the element.
|
||||
*
|
||||
* @return the XML element name of the element.
|
||||
*/
|
||||
public static String getElementName() {
|
||||
return NODENAME;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the current transportElement candidate.
|
||||
*
|
||||
* @return the transportElement candidate
|
||||
*/
|
||||
public TransportCandidate getMediaTransport() {
|
||||
return transportCandidate;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the transportElement candidate.
|
||||
*
|
||||
* @param cand the transportElement candidate
|
||||
*/
|
||||
public void setMediaTransport(final TransportCandidate cand) {
|
||||
if (cand != null) {
|
||||
transportCandidate = cand;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the list of attributes.
|
||||
*
|
||||
* @return a string with the list of attributes.
|
||||
*/
|
||||
protected String getChildElements() {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Obtain a valid XML representation of a trancport candidate
|
||||
*
|
||||
* @return A string containing the XML dump of the transport candidate.
|
||||
*/
|
||||
public String toXML() {
|
||||
StringBuilder buf = new StringBuilder();
|
||||
String childElements = getChildElements();
|
||||
|
||||
if (transportCandidate != null && childElements != null) {
|
||||
buf.append("<").append(getElementName()).append(" ");
|
||||
buf.append(childElements);
|
||||
buf.append("/>");
|
||||
}
|
||||
|
||||
return buf.toString();
|
||||
}
|
||||
}
|
||||
|
||||
// Subclasses
|
||||
|
||||
/**
|
||||
* RTP-ICE profile
|
||||
*/
|
||||
public static class Ice extends JingleTransport {
|
||||
public static final String NAMESPACE = "http://jabber.org/protocol/jingle/transport/ice";
|
||||
|
||||
public Ice() {
|
||||
super();
|
||||
setNamespace(NAMESPACE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a transport candidate
|
||||
*
|
||||
* @see org.jivesoftware.smackx.packet.JingleTransport#addCandidate(org.jivesoftware.smackx.packet.JingleTransport.JingleTransportCandidate)
|
||||
*/
|
||||
public void addCandidate(final JingleTransportCandidate candidate) {
|
||||
super.addCandidate(candidate);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the list of candidates. As a "raw-udp" transport can only contain
|
||||
* one candidate, we use the first in the list...
|
||||
*
|
||||
* @see org.jivesoftware.smackx.packet.JingleTransport#getCandidates()
|
||||
*/
|
||||
public ArrayList getCandidatesList() {
|
||||
ArrayList copy = new ArrayList();
|
||||
ArrayList superCandidatesList = super.getCandidatesList();
|
||||
for (int i = 0; i < superCandidatesList.size(); i++) {
|
||||
copy.add(superCandidatesList.get(i));
|
||||
}
|
||||
|
||||
return copy;
|
||||
}
|
||||
|
||||
public static class Candidate extends JingleTransportCandidate {
|
||||
/**
|
||||
* Default constructor
|
||||
*/
|
||||
public Candidate() {
|
||||
super();
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor with a transport candidate.
|
||||
*/
|
||||
public Candidate(final TransportCandidate tc) {
|
||||
super(tc);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the elements of this candidate.
|
||||
*/
|
||||
protected String getChildElements() {
|
||||
StringBuilder buf = new StringBuilder();
|
||||
|
||||
if (transportCandidate != null) {// && transportCandidate instanceof TransportCandidate.Ice) {
|
||||
TransportCandidate.Ice tci = (TransportCandidate.Ice) transportCandidate;
|
||||
|
||||
// We convert the transportElement candidate to XML here...
|
||||
buf.append(" generation=\"").append(tci.getGeneration()).append("\"");
|
||||
buf.append(" ip=\"").append(tci.getIp()).append("\"");
|
||||
buf.append(" port=\"").append(tci.getPort()).append("\"");
|
||||
buf.append(" network=\"").append(tci.getNetwork()).append("\"");
|
||||
buf.append(" username=\"").append(tci.getUsername()).append("\"");
|
||||
buf.append(" password=\"").append(tci.getPassword()).append("\"");
|
||||
buf.append(" preference=\"").append(tci.getPreference()).append("\"");
|
||||
|
||||
// Optional elements
|
||||
if (transportCandidate.getName() != null) {
|
||||
buf.append(" name=\"").append(tci.getName()).append("\"");
|
||||
}
|
||||
}
|
||||
|
||||
return buf.toString();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Raw UDP profile.
|
||||
*/
|
||||
public static class RawUdp extends JingleTransport {
|
||||
public static final String NAMESPACE = "http://jabber.org/protocol/jingle/transport/raw-udp";
|
||||
|
||||
public RawUdp() {
|
||||
super();
|
||||
setNamespace(NAMESPACE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a transport candidate
|
||||
*
|
||||
* @see org.jivesoftware.smackx.packet.JingleTransport#addCandidate(org.jivesoftware.smackx.packet.JingleTransport.JingleTransportCandidate)
|
||||
*/
|
||||
public void addCandidate(final JingleTransportCandidate candidate) {
|
||||
candidates.clear();
|
||||
super.addCandidate(candidate);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the list of candidates. As a "raw-udp" transport can only contain
|
||||
* one candidate, we use the first in the list...
|
||||
*
|
||||
* @see org.jivesoftware.smackx.packet.JingleTransport#getCandidates()
|
||||
*/
|
||||
public ArrayList getCandidatesList() {
|
||||
ArrayList copy = new ArrayList();
|
||||
ArrayList superCandidatesList = super.getCandidatesList();
|
||||
if (superCandidatesList.size() > 0) {
|
||||
copy.add(superCandidatesList.get(0));
|
||||
}
|
||||
|
||||
return copy;
|
||||
}
|
||||
|
||||
/**
|
||||
* Raw-udp transport candidate.
|
||||
*/
|
||||
public static class Candidate extends JingleTransportCandidate {
|
||||
/**
|
||||
* Default constructor
|
||||
*/
|
||||
public Candidate() {
|
||||
super();
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor with a transport candidate.
|
||||
*/
|
||||
public Candidate(final TransportCandidate tc) {
|
||||
super(tc);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the elements of this candidate.
|
||||
*/
|
||||
protected String getChildElements() {
|
||||
StringBuilder buf = new StringBuilder();
|
||||
|
||||
if (transportCandidate != null && transportCandidate instanceof TransportCandidate.Fixed) {
|
||||
TransportCandidate.Fixed tcf = (TransportCandidate.Fixed) transportCandidate;
|
||||
|
||||
buf.append(" generation=\"").append(tcf.getGeneration()).append("\"");
|
||||
buf.append(" ip=\"").append(tcf.getIp()).append("\"");
|
||||
buf.append(" port=\"").append(tcf.getPort()).append("\"");
|
||||
|
||||
// Optional parameters
|
||||
String name = tcf.getName();
|
||||
if (name != null) {
|
||||
buf.append(" name=\"").append(name).append("\"");
|
||||
}
|
||||
}
|
||||
return buf.toString();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1 @@
|
|||
<body>XML packets that are part of the XMPP extension protocols.</body>
|
||||
Loading…
Add table
Add a link
Reference in a new issue