Updated Jingle implementation. SMACK-240. Thanks to Jeff Williams.

git-svn-id: http://svn.igniterealtime.org/svn/repos/smack/trunk@10419 b35dd754-fafc-0310-a699-88a17e54d16e
This commit is contained in:
Gaston Dombiak 2008-05-21 04:35:42 +00:00 committed by gato
parent 1cbfdcc7db
commit 646271abac
12 changed files with 1199 additions and 0 deletions

View File

@ -0,0 +1,49 @@
package org.jivesoftware.smackx.jingle;
/**
* The "action" in the jingle packet, as an enum.
*
* Changed to reflect XEP-166 rev: 20JUN07
*
* @author Jeff Williams
*/
public enum JingleActionEnum {
UNKNOWN("unknown"),
CONTENT_ACCEPT("content-accept"),
CONTENT_ADD("content-add"),
CONTENT_MODIFY("content-modify"),
CONTENT_REMOVE("content-remove"),
SESSION_ACCEPT("session-accept"),
SESSION_INFO("session-info"),
SESSION_INITIATE("session-initiate"),
SESSION_TERMINATE("session-terminate"),
TRANSPORT_INFO("transport-info");
private String actionCode;
private JingleActionEnum(String inActionCode) {
actionCode = inActionCode;
}
/**
* Returns the String value for an Action.
*/
public String toString() {
return actionCode;
}
/**
* Returns the Action enum for a String action value.
*/
public static JingleActionEnum getAction(String inActionCode) {
for (JingleActionEnum jingleAction : JingleActionEnum.values()) {
if (jingleAction.actionCode.equals(inActionCode)) {
return jingleAction;
}
}
return null;
}
}

View File

@ -0,0 +1,52 @@
package org.jivesoftware.smackx.jingle;
import org.jivesoftware.smack.XMPPException;
import org.jivesoftware.smackx.packet.JingleError;
/**
* A Jingle exception.
*
* @author Alvaro Saurin <alvaro.saurin@gmail.com>
*/
public class JingleException extends XMPPException {
private final JingleError error;
/**
* Default constructor.
*/
public JingleException() {
super();
error = null;
}
/**
* Constructor with an error message.
*
* @param msg The message.
*/
public JingleException(String msg) {
super(msg);
error = null;
}
/**
* Constructor with an error response.
*
* @param error The error message.
*/
public JingleException(JingleError error) {
super();
this.error = error;
}
/**
* Return the error message.
*
* @return the error
*/
public JingleError getError() {
return error;
}
}

View File

@ -0,0 +1,10 @@
package org.jivesoftware.smackx.jingle;
/**
* @author Jeff Williams
*/
public enum JingleNegotiatorState {
PENDING,
FAILED,
SUCCEEDED
}

View File

@ -0,0 +1,49 @@
package org.jivesoftware.smackx.jingle;
import org.jivesoftware.smack.packet.IQ;
import org.jivesoftware.smackx.packet.Jingle;
/**
* Implement the Jingle Session state using the State Behavioral pattern.
* (From the book Design Patterns, AKA GoF.)
* These classes also employ the Flyweight and Singleton patterns as recommended for the State pattern by GoF.
*
* There seems to be three ways to go with the State pattern in Java: interface, abstract class and enums.
* Most of the accepted models use abstract classes. It wasn't clear to me that any of the three models was
* superior, so I went with the most common example.
*
* @author Jeff Williams
*/
public abstract class JingleSessionState {
/**
* Called when entering the state.
*/
public static JingleSessionState getInstance() {
// Since we can never instantiate this class there is nothing to return (ever).
return null;
}
/**
* Called when entering the state.
*/
public abstract void enter();
/**
* Called when exiting the state.
*/
public abstract void exit();
/**
* Process an incoming Jingle Packet.
* When you look at the GoF State pattern this method roughly corresponds to example on p310: ProcessOctect().
*/
public abstract IQ processJingle(JingleSession session, Jingle jingle, JingleActionEnum action);
/**
* For debugging just emit the short name of the class.
*/
public String toString() {
return this.getClass().getSimpleName();
}
}

View File

@ -0,0 +1,92 @@
package org.jivesoftware.smackx.jingle;
import org.jivesoftware.smack.XMPPException;
import org.jivesoftware.smack.packet.IQ;
import org.jivesoftware.smackx.packet.Jingle;
import org.jivesoftware.smackx.packet.JingleError;
/**
* @author Jeff Williams
* @see JingleSessionState
*/
public class JingleSessionStateActive extends JingleSessionState {
private static JingleSessionStateActive INSTANCE = null;
protected JingleSessionStateActive() {
// Prevent instantiation of the class.
}
/**
* A thread-safe means of getting the one instance of this class.
* @return The singleton instance of this class.
*/
public synchronized static JingleSessionState getInstance() {
if (INSTANCE == null) {
INSTANCE = new JingleSessionStateActive();
}
return INSTANCE;
}
public void enter() {
// TODO Auto-generated method stub
}
public void exit() {
// TODO Auto-generated method stub
}
public IQ processJingle(JingleSession session, Jingle jingle, JingleActionEnum action) {
IQ response = null;
switch (action) {
case CONTENT_ACCEPT:
break;
case CONTENT_ADD:
break;
case CONTENT_MODIFY:
break;
case CONTENT_REMOVE:
break;
case SESSION_INFO:
break;
case SESSION_TERMINATE:
receiveSessionTerminateAction(session, jingle);
break;
case TRANSPORT_INFO:
break;
default:
// Anything other action is an error.
response = session.createJingleError(jingle, JingleError.OUT_OF_ORDER);
break;
}
return response;
}
/**
* Receive and process the <session-terminate> action.
*/
private IQ receiveSessionTerminateAction(JingleSession session, Jingle jingle) {
// According to XEP-166 the only thing we can do is ack.
IQ response = session.createAck(jingle);
try {
session.terminate("Closed remotely");
} catch (XMPPException e) {
e.printStackTrace();
}
return response;
}
}

View File

@ -0,0 +1,51 @@
package org.jivesoftware.smackx.jingle;
import org.jivesoftware.smack.packet.IQ;
import org.jivesoftware.smackx.packet.Jingle;
import org.jivesoftware.smackx.packet.JingleError;
/**
* @author Jeff Williams
* @see JingleSessionState
*/
public class JingleSessionStateEnded extends JingleSessionState {
private static JingleSessionStateEnded INSTANCE = null;
protected JingleSessionStateEnded() {
// Prevent instantiation of the class.
}
/**
* A thread-safe means of getting the one instance of this class.
* @return The singleton instance of this class.
*/
public synchronized static JingleSessionState getInstance() {
if (INSTANCE == null) {
INSTANCE = new JingleSessionStateEnded();
}
return INSTANCE;
}
public void enter() {
System.out.println("Session Ended");
System.out.println("-------------------------------------------------------------------");
}
public void exit() {
// TODO Auto-generated method stub
}
/**
* Pretty much nothing is valid for receiving once we've ended the session.
*/
public IQ processJingle(JingleSession session, Jingle jingle, JingleActionEnum action) {
IQ response = null;
response = session.createJingleError(jingle, JingleError.MALFORMED_STANZA);
return response;
}
}

View File

@ -0,0 +1,117 @@
package org.jivesoftware.smackx.jingle;
import org.jivesoftware.smack.XMPPException;
import org.jivesoftware.smack.packet.IQ;
import org.jivesoftware.smackx.packet.Jingle;
/**
* @author Jeff Williams
* @see JingleSessionState
*/
public class JingleSessionStatePending extends JingleSessionState {
private static JingleSessionStatePending INSTANCE = null;
protected JingleSessionStatePending() {
// Prevent instantiation of the class.
}
/**
* A thread-safe means of getting the one instance of this class.
* @return The singleton instance of this class.
*/
public synchronized static JingleSessionState getInstance() {
if (INSTANCE == null) {
INSTANCE = new JingleSessionStatePending();
}
return INSTANCE;
}
public void enter() {
// TODO Auto-generated method stub
}
public void exit() {
// TODO Auto-generated method stub
}
public IQ processJingle(JingleSession session, Jingle jingle, JingleActionEnum action) {
IQ response = null;
switch (action) {
case CONTENT_ACCEPT:
response = receiveContentAcceptAction(jingle);
break;
case CONTENT_MODIFY:
break;
case CONTENT_REMOVE:
break;
case SESSION_ACCEPT:
response = receiveSessionAcceptAction(session, jingle);
break;
case SESSION_INFO:
break;
case SESSION_TERMINATE:
response = receiveSessionTerminateAction(session, jingle);
break;
case TRANSPORT_INFO:
break;
default:
// Anything other action is an error.
//response = createJingleError(inJingle, JingleError.OUT_OF_ORDER);
break;
}
return response;
}
/**
* Receive and process the <session-accept> action.
*/
private IQ receiveContentAcceptAction(Jingle inJingle) {
// According to XEP-167 the only thing we can do is ack.
//setSessionState(JingleSessionStateEnum.ACTIVE);
//return createAck(inJingle);
// This is now handled by the media negotiator for the matching <content> segment.
return null;
}
/**
* Receive and process the <session-accept> action.
*/
private IQ receiveSessionAcceptAction(JingleSession session, Jingle inJingle) {
// According to XEP-166 the only thing we can do is ack.
session.setSessionState(JingleSessionStateActive.getInstance());
return session.createAck(inJingle);
}
/**
* Receive and process the <session-terminate> action.
*/
private IQ receiveSessionTerminateAction(JingleSession session, Jingle jingle) {
// According to XEP-166 the only thing we can do is ack.
IQ response = session.createAck(jingle);
try {
session.terminate("Closed remotely");
} catch (XMPPException e) {
e.printStackTrace();
}
return response;
}
}

View File

@ -0,0 +1,195 @@
package org.jivesoftware.smackx.jingle;
import org.jivesoftware.smack.XMPPException;
import org.jivesoftware.smack.packet.IQ;
import org.jivesoftware.smackx.jingle.media.JingleMediaManager;
import org.jivesoftware.smackx.jingle.media.MediaNegotiator;
import org.jivesoftware.smackx.jingle.media.PayloadType;
import org.jivesoftware.smackx.jingle.nat.JingleTransportManager;
import org.jivesoftware.smackx.jingle.nat.TransportNegotiator;
import org.jivesoftware.smackx.jingle.nat.TransportResolver;
import org.jivesoftware.smackx.packet.Jingle;
import org.jivesoftware.smackx.packet.JingleContent;
import org.jivesoftware.smackx.packet.JingleDescription;
import org.jivesoftware.smackx.packet.JingleError;
import org.jivesoftware.smackx.packet.JingleTransport;
/**
* @author Jeff Williams
* @see JingleSessionState
*/
public class JingleSessionStateUnknown extends JingleSessionState {
private static JingleSessionStateUnknown INSTANCE = null;
protected JingleSessionStateUnknown() {
// Prevent instantiation of the class.
}
/**
* A thread-safe means of getting the one instance of this class.
* @return The singleton instance of this class.
*/
public synchronized static JingleSessionState getInstance() {
if (INSTANCE == null) {
INSTANCE = new JingleSessionStateUnknown();
}
return INSTANCE;
}
public void enter() {
// TODO Auto-generated method stub
}
public void exit() {
// TODO Auto-generated method stub
}
public IQ processJingle(JingleSession session, Jingle jingle, JingleActionEnum action) {
IQ response = null;
switch (action) {
case SESSION_INITIATE:
response = receiveSessionInitiateAction(session, jingle);
break;
case SESSION_TERMINATE:
response = receiveSessionTerminateAction(session, jingle);
break;
default:
// Anything other than session-initiate is an error.
response = session.createJingleError(jingle, JingleError.MALFORMED_STANZA);
break;
}
return response;
}
/**
* In the UNKNOWN state we received a <session-initiate> action.
* This method processes that action.
*/
private IQ receiveSessionInitiateAction(JingleSession session, Jingle inJingle) {
IQ response = null;
boolean shouldAck = true;
// According to XEP-166 when we get a session-initiate we need to check for:
// 1. Initiator unknown
// 2. Receiver redirection
// 3. Does not support Jingle
// 4. Does not support any <description> formats
// 5. Does not support any <transport> formats
// If all of the above are OK then we send an IQ type = result to ACK the session-initiate.
// 1. Initiator unknown
// TODO
// 2. Receiver redirection
// TODO
// 3. Does not support Jingle
// Handled by Smack's lower layer.
// 4. Does not support any <description> formats
// TODO
// 5. Does not support any <transport> formats
// TODO
if (!shouldAck) {
response = session.createJingleError(inJingle, JingleError.NEGOTIATION_ERROR);
} else {
// Create the Ack
response = session.createAck(inJingle);
session.setSessionState(JingleSessionStatePending.getInstance());
// Now set up all of the initial content negotiators for the session.
for (JingleContent jingleContent : inJingle.getContentsList()) {
// First create the content negotiator for this <content> section.
ContentNegotiator contentNeg = new ContentNegotiator(session, jingleContent.getCreator(), jingleContent
.getName());
// Get the media negotiator that goes with the <description> of this content.
JingleDescription jingleDescription = jingleContent.getDescription();
// Loop through each media manager looking for the ones that matches the incoming
// session-initiate <content> choices.
// (Set the first media manager as the default, so that in case things don't match we can still negotiate.)
JingleMediaManager chosenMediaManager = session.getMediaManagers().get(0);
for (JingleMediaManager mediaManager : session.getMediaManagers()) {
boolean matches = true;
for (PayloadType mediaPayloadType : mediaManager.getPayloads()) {
for (PayloadType descPayloadType2 : jingleDescription.getPayloadTypesList()) {
if (mediaPayloadType.getId() != descPayloadType2.getId()) {
matches = false;
}
}
if (matches) {
chosenMediaManager = mediaManager;
}
}
}
// Create the media negotiator for this content description.
contentNeg.setMediaNegotiator(new MediaNegotiator(session, chosenMediaManager, jingleDescription
.getPayloadTypesList(), contentNeg));
// For each transport type in this content, try to find the corresponding transport manager.
// Then create a transport negotiator for that transport.
for (JingleTransport jingleTransport : jingleContent.getJingleTransportsList()) {
for (JingleMediaManager mediaManager : session.getMediaManagers()) {
JingleTransportManager transportManager = mediaManager.getTransportManager();
TransportResolver resolver = null;
try {
resolver = transportManager.getResolver(session);
} catch (XMPPException e) {
e.printStackTrace();
}
if (resolver.getType().equals(TransportResolver.Type.rawupd)) {
contentNeg.setTransportNegotiator(new TransportNegotiator.RawUdp(session, resolver, contentNeg));
}
if (resolver.getType().equals(TransportResolver.Type.ice)) {
contentNeg.setTransportNegotiator(new TransportNegotiator.Ice(session, resolver, contentNeg));
}
}
}
// Add the content negotiator to the session.
session.addContentNegotiator(contentNeg);
}
// Now setup to track the media negotiators, so that we know when (if) to send a session-accept.
session.setupListeners();
}
return response;
}
/**
* Receive and process the <session-terminate> action.
*/
private IQ receiveSessionTerminateAction(JingleSession session, Jingle jingle) {
// According to XEP-166 the only thing we can do is ack.
IQ response = session.createAck(jingle);
try {
session.terminate("Closed remotely");
} catch (XMPPException e) {
e.printStackTrace();
}
return response;
}
}

View File

@ -0,0 +1,186 @@
/**
* $RCSfile: JingleContent.java,v $
* $Revision: 1.2 $
* $Date: 2007/07/02 22:45:36 $
*
* Copyright 2003-2005 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 java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import org.jivesoftware.smack.packet.PacketExtension;
/**
* Jingle content.
*
* @author Jeff Williams
*/
public class JingleContent implements PacketExtension {
public static final String NODENAME = "content";
public static final String CREATOR = "creator";
public static final String NAME = "name";
private String creator;
private String name;
private JingleDescription description;
private final List<JingleTransport> transports = new ArrayList<JingleTransport>();
/**
* Creates a content description..
*/
public JingleContent(String creator, String name) {
super();
this.creator = creator;
this.name = name;
}
public String getCreator() {
return creator;
}
public String getName() {
return name;
}
/**
* 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 String getNamespace() {
// There is no namespace for <content>
return "";
}
/**
* Sets the description for this Jingle content.
*
* @param description
* The description
*/
public void setDescription(JingleDescription description) {
this.description = description;
}
/**
* Gets the description for this Jingle content.
*
* @return The description.
*/
public JingleDescription getDescription() {
return description;
}
/**
* Adds a JingleTransport type to the packet.
*
* @param transport
* the JignleTransport to add.
*/
public void addJingleTransport(final JingleTransport transport) {
synchronized (transports) {
transports.add(transport);
}
}
/**
* Adds a list of transports to add to the packet.
*
* @param transports
* the transports to add.
*/
public void addTransports(final List<JingleTransport> transports) {
synchronized (transports) {
for (JingleTransport transport : transports) {
addJingleTransport(transport);
}
}
}
/**
* Returns an Iterator for the JingleTransports in the packet.
*
* @return an Iterator for the JingleTransports in the packet.
*/
public Iterator<JingleTransport> getJingleTransports() {
return Collections.unmodifiableList(getJingleTransportsList()).iterator();
}
/**
* Returns a list for the JingleTransports in the packet.
*
* @return a list for the JingleTransports in the packet.
*/
public List<JingleTransport> getJingleTransportsList() {
synchronized (transports) {
return new ArrayList<JingleTransport>(transports);
}
}
/**
* Returns a count of the JingleTransports in the Jingle packet.
*
* @return the number of the JingleTransports in the Jingle packet.
*/
public int getJingleTransportsCount() {
synchronized (transports) {
return transports.size();
}
}
/**
* Convert a Jingle description to XML.
*
* @return a string with the XML representation
*/
public String toXML() {
StringBuilder buf = new StringBuilder();
synchronized (transports) {
buf.append("<").append(getElementName());
buf.append(" creator='" + creator + "' name='" + name + "'>");
// Add the description.
if (description != null) {
buf.append(description.toXML());
}
// Add all of the transports.
for (JingleTransport transport : transports) {
buf.append(transport.toXML());
}
buf.append("</").append(getElementName()).append(">");
}
return buf.toString();
}
}

View File

@ -0,0 +1,197 @@
/**
* $RCSfile: JingleDescription.java,v $
* $Revision: 1.1 $
* $Date: 2007/07/02 17:41:08 $
*
* Copyright 2003-2005 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.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 JingleDescription implements PacketExtension {
// static
public static final String NODENAME = "description";
// non-static
private final List<PayloadType> payloads = new ArrayList<PayloadType>();
/**
* Creates a content description..
*/
public JingleDescription() {
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 addPayloadType(final PayloadType pt) {
synchronized (payloads) {
if (pt == null) {
System.err.println("Null payload type");
} else {
payloads.add(pt);
}
}
}
/**
* Adds a list of payloads to the packet.
*
* @param pts the payloads to add.
*/
public void addAudioPayloadTypes(final List<PayloadType> pts) {
synchronized (payloads) {
Iterator ptIter = pts.iterator();
while (ptIter.hasNext()) {
PayloadType.Audio pt = (PayloadType.Audio) ptIter.next();
addPayloadType(new PayloadType.Audio(pt));
}
}
}
/**
* Returns an Iterator for the audio payloads in the packet.
*
* @return an Iterator for the audio payloads in the packet.
*/
public Iterator<PayloadType> getPayloadTypes() {
return Collections.unmodifiableList(getPayloadTypesList()).iterator();
}
/**
* Returns a list for the audio payloads in the packet.
*
* @return a list for the audio payloads in the packet.
*/
public List<PayloadType> getPayloadTypesList() {
synchronized (payloads) {
return new ArrayList<PayloadType>(payloads);
}
}
/**
* Return the list of Payload types contained in the description.
*
* @return a list of PayloadType.Audio
*/
public List<PayloadType> getAudioPayloadTypesList() {
ArrayList<PayloadType> result = new ArrayList<PayloadType>();
Iterator<PayloadType> jinglePtsIter = getPayloadTypes();
while (jinglePtsIter.hasNext()) {
PayloadType jpt = (PayloadType) jinglePtsIter.next();
if (jpt instanceof PayloadType.Audio) {
PayloadType.Audio jpta = (PayloadType.Audio) jpt;
result.add(jpta);
}
}
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 getPayloadTypesCount() {
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("\" >");
for (PayloadType payloadType : payloads) {
if (payloadType != null) {
buf.append(payloadType.toXML());
}
}
buf.append("</").append(getElementName()).append(">");
}
}
return buf.toString();
}
/**
* Jingle audio description
*/
public static class Audio extends JingleDescription {
public static final String NAMESPACE = "http://www.xmpp.org/extensions/xep-0167.html#ns";
public Audio() {
super();
}
/**
* Utility constructor, with a PayloadType
*/
public Audio(final PayloadType pt) {
super();
addPayloadType(pt);
}
public String getNamespace() {
return NAMESPACE;
}
}
}

View File

@ -0,0 +1,58 @@
/**
* $RCSfile: JingleContentProvider.java,v $
* $Revision: 1.2 $
* $Date: 2007/07/04 00:52:33 $
*
* Copyright 2003-2005 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.provider;
import org.jivesoftware.smack.packet.PacketExtension;
import org.jivesoftware.smack.provider.PacketExtensionProvider;
import org.jivesoftware.smackx.packet.JingleContent;
import org.xmlpull.v1.XmlPullParser;
/**
* Jingle <content> provider
*
* @author Jeff Williams
*/
public class JingleContentProvider implements PacketExtensionProvider {
/**
* Creates a new provider. ProviderManager requires that every
* PacketExtensionProvider has a public, no-argument constructor
*/
public JingleContentProvider() {
super();
}
/**
* Parse a JingleContent extension.
*/
public PacketExtension parseExtension(final XmlPullParser parser) throws Exception {
PacketExtension result = null;
String elementName = parser.getName();
String creator = parser.getAttributeValue("", JingleContent.CREATOR);
String name = parser.getAttributeValue("", JingleContent.NAME);
// Try to get an Audio content info
result = new JingleContent(creator, name);
return result;
}
}

View File

@ -0,0 +1,143 @@
/**
* $RCSfile: JingleDescriptionProvider.java,v $
* $Revision: 1.1 $
* $Date: 2007/07/02 17:41:11 $
*
* Copyright 2003-2005 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.provider;
import org.jivesoftware.smack.packet.PacketExtension;
import org.jivesoftware.smack.provider.PacketExtensionProvider;
import org.jivesoftware.smackx.jingle.media.PayloadType;
import org.jivesoftware.smackx.packet.JingleDescription;
import org.xmlpull.v1.XmlPullParser;
/**
* Parser for a Jingle description
*
* @author Alvaro Saurin <alvaro.saurin@gmail.com>
*/
public abstract class JingleDescriptionProvider implements PacketExtensionProvider {
/**
* Default constructor
*/
public JingleDescriptionProvider() {
super();
}
/**
* Parse a iq/jingle/description/payload-type element.
*
* @param parser
* the input to parse
* @return a payload type element
* @throws Exception
*/
protected PayloadType parsePayload(final XmlPullParser parser) throws Exception {
int ptId = 0;
String ptName;
int ptChannels = 0;
try {
ptId = Integer.parseInt(parser.getAttributeValue("", "id"));
} catch (Exception e) {
}
ptName = parser.getAttributeValue("", "name");
try {
ptChannels = Integer.parseInt(parser.getAttributeValue("", "channels"));
} catch (Exception e) {
}
return new PayloadType(ptId, ptName, ptChannels);
}
/**
* Parse a iq/jingle/description element.
*
* @param parser
* the input to parse
* @return a description element
* @throws Exception
*/
public PacketExtension parseExtension(final XmlPullParser parser) throws Exception {
boolean done = false;
JingleDescription desc = getInstance();
while (!done) {
int eventType = parser.next();
String name = parser.getName();
if (eventType == XmlPullParser.START_TAG) {
if (name.equals(PayloadType.NODENAME)) {
desc.addPayloadType(parsePayload(parser));
} else {
throw new Exception("Unknow element \"" + name + "\" in content.");
}
} else if (eventType == XmlPullParser.END_TAG) {
if (name.equals(JingleDescription.NODENAME)) {
done = true;
}
}
}
return desc;
}
/**
* Return a new instance of this class. Subclasses must overwrite this
* method.
*/
protected abstract JingleDescription getInstance();
/**
* Jingle audio
*/
public static class Audio extends JingleDescriptionProvider {
/**
* Default constructor
*/
public Audio() {
super();
}
/**
* Parse an audio payload type.
*/
public PayloadType parsePayload(final XmlPullParser parser) throws Exception {
PayloadType pte = super.parsePayload(parser);
PayloadType.Audio pt = new PayloadType.Audio(pte);
int ptClockRate = 0;
try {
ptClockRate = Integer.parseInt(parser.getAttributeValue("", "clockrate"));
} catch (Exception e) {
}
pt.setClockRate(ptClockRate);
return pt;
}
/**
* Get a new instance of this object.
*/
protected JingleDescription getInstance() {
return new JingleDescription.Audio();
}
}
}