mirror of
https://github.com/vanitasvitae/Smack.git
synced 2024-11-29 15:32:06 +01:00
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:
parent
1cbfdcc7db
commit
646271abac
12 changed files with 1199 additions and 0 deletions
|
@ -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;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,10 @@
|
||||||
|
package org.jivesoftware.smackx.jingle;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Jeff Williams
|
||||||
|
*/
|
||||||
|
public enum JingleNegotiatorState {
|
||||||
|
PENDING,
|
||||||
|
FAILED,
|
||||||
|
SUCCEEDED
|
||||||
|
}
|
|
@ -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();
|
||||||
|
}
|
||||||
|
}
|
|
@ -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;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
|
@ -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;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -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();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -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;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -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();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in a new issue