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

git-svn-id: http://svn.igniterealtime.org/svn/repos/smack/trunk@10424 b35dd754-fafc-0310-a699-88a17e54d16e
This commit is contained in:
Gaston Dombiak 2008-05-21 16:48:06 +00:00 committed by gato
parent 646271abac
commit d23d36974f
4 changed files with 575 additions and 0 deletions

View File

@ -0,0 +1,322 @@
package org.jivesoftware.smackx.jingle;
import java.util.ArrayList;
import java.util.List;
import org.jivesoftware.smack.XMPPException;
import org.jivesoftware.smack.packet.IQ;
import org.jivesoftware.smackx.jingle.listeners.JingleListener;
import org.jivesoftware.smackx.jingle.listeners.JingleSessionListener;
import org.jivesoftware.smackx.jingle.media.JingleMediaManager;
import org.jivesoftware.smackx.jingle.media.JingleMediaSession;
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.TransportCandidate;
import org.jivesoftware.smackx.jingle.nat.TransportNegotiator;
import org.jivesoftware.smackx.packet.Jingle;
import org.jivesoftware.smackx.packet.JingleContent;
/**
* @author Jeff Williams
*/
public class ContentNegotiator extends JingleNegotiator {
public static final String INITIATOR = "initiator";
public static final String RESPONDER = "responder";
private List<TransportNegotiator> transportNegotiators;
private MediaNegotiator mediaNeg; // The description...
private TransportNegotiator transNeg; // and transport negotiators
private JingleTransportManager jingleTransportManager;
private String creator;
private String name;
private JingleMediaSession jingleMediaSession = null;
public ContentNegotiator(JingleSession session, String inCreator, String inName) {
super(session);
creator = inCreator;
name = inName;
transportNegotiators = new ArrayList<TransportNegotiator>();
}
public List<IQ> dispatchIncomingPacket(IQ iq, String id) throws XMPPException {
List<IQ> responses = new ArrayList<IQ>();
// First only process IQ packets that contain <content> stanzas that
// match this media manager.
if (iq != null) {
if (iq.getType().equals(IQ.Type.ERROR)) {
// Process errors
// TODO getState().eventError(iq);
} else if (iq.getType().equals(IQ.Type.RESULT)) {
// Process ACKs
if (isExpectedId(iq.getPacketID())) {
removeExpectedId(iq.getPacketID());
}
} else if (iq instanceof Jingle) {
Jingle jingle = (Jingle) iq;
// There are 1 or more <content> sections in a Jingle packet.
// Find out which <content> section belongs to this content negotiator, and
// then dispatch the Jingle packet to the media and transport negotiators.
for (JingleContent jingleContent : jingle.getContentsList()) {
if (jingleContent.getName().equals(name)) {
if (mediaNeg != null) {
responses.addAll(mediaNeg.dispatchIncomingPacket(iq, id));
}
if (transNeg != null) {
responses.addAll(transNeg.dispatchIncomingPacket(iq, id));
}
}
}
}
}
return responses;
}
public String getCreator() {
return creator;
}
public String getName() {
return name;
}
/**
* Get the JingleMediaSession of this Jingle Session
*
* @return the JingleMediaSession
*/
public JingleMediaSession getJingleMediaSession() {
return jingleMediaSession;
}
public void addTransportNegotiator(TransportNegotiator transportNegotiator) {
transportNegotiators.add(transportNegotiator);
}
/**
* @param jingleTransportManager
*/
public void setJingleTransportManager(JingleTransportManager jingleTransportManager) {
this.jingleTransportManager = jingleTransportManager;
}
/**
* @return
*/
public JingleTransportManager getTransportManager() {
return jingleTransportManager;
}
/**
* Called from above when starting a new session.
*/
public void start() {
JingleContent result = new JingleContent(creator, name);
// result.setDescription(mediaNeg.start());
// result.addJingleTransport(transNeg.start());
//
// return result;
mediaNeg.start();
transNeg.start();
}
/**
* Prepare to close the media manager.
*/
public void close() {
destroyMediaNegotiator();
destroyTransportNegotiator();
}
/**
* Obtain the description negotiator for this session
*
* @return the description negotiator
*/
public MediaNegotiator getMediaNegotiator() {
return mediaNeg;
}
/**
* Set the jmf negotiator.
*
* @param mediaNeg
* the description negotiator to set
*/
protected void setMediaNegotiator(MediaNegotiator mediaNeg) {
destroyMediaNegotiator();
this.mediaNeg = mediaNeg;
}
/**
* Destroy the jmf negotiator.
*/
protected void destroyMediaNegotiator() {
if (mediaNeg != null) {
mediaNeg.close();
mediaNeg = null;
}
}
/**
* Obtain the transport negotiator for this session.
*
* @return the transport negotiator instance
*/
public TransportNegotiator getTransportNegotiator() {
return transNeg;
}
/**
* Set TransportNegociator
*
* @param transNeg
* the transNeg to set
*/
protected void setTransportNegotiator(TransportNegotiator transNeg) {
destroyTransportNegotiator();
this.transNeg = transNeg;
}
/**
* Destroy the transport negotiator.
*/
protected void destroyTransportNegotiator() {
if (transNeg != null) {
transNeg.close();
transNeg = null;
}
}
/**
* Return true if the transport and content negotiators have finished
*/
public boolean isFullyEstablished() {
boolean result = true;
MediaNegotiator mediaNeg = getMediaNegotiator();
if ((mediaNeg == null) || (!mediaNeg.isFullyEstablished())) {
result = false;
}
TransportNegotiator transNeg = getTransportNegotiator();
if ((transNeg == null) || (!transNeg.isFullyEstablished())) {
result = false;
}
return result;
}
public JingleContent getJingleContent() {
JingleContent result = new JingleContent(creator, name);
// PayloadType.Audio bestCommonAudioPt = getMediaNegotiator().getBestCommonAudioPt();
// TransportCandidate bestRemoteCandidate = getTransportNegotiator().getBestRemoteCandidate();
//
// // Ok, send a packet saying that we accept this session
// // with the audio payload type and the transport
// // candidate
// result.setDescription(new JingleDescription.Audio(new PayloadType(bestCommonAudioPt)));
// result.addJingleTransport(this.getTransportNegotiator().getJingleTransport(bestRemoteCandidate));
if (mediaNeg != null) {
result.setDescription(mediaNeg.getJingleDescription());
}
if (transNeg != null) {
result.addJingleTransport(transNeg.getJingleTransport());
}
return result;
}
public void triggerContentEstablished() {
PayloadType bestCommonAudioPt = getMediaNegotiator().getBestCommonAudioPt();
TransportCandidate bestRemoteCandidate = getTransportNegotiator().getBestRemoteCandidate();
TransportCandidate acceptedLocalCandidate = getTransportNegotiator().getAcceptedLocalCandidate();
// Trigger the session established flag
triggerContentEstablished(bestCommonAudioPt, bestRemoteCandidate, acceptedLocalCandidate);
}
/**
* Trigger a session established event.
*/
private void triggerContentEstablished(PayloadType pt, TransportCandidate rc, TransportCandidate lc) {
// Let the session know that we've established a content/media segment.
JingleSession session = getSession();
if (session != null) {
List<JingleListener> listeners = session.getListenersList();
for (JingleListener li : listeners) {
if (li instanceof JingleSessionListener) {
JingleSessionListener sli = (JingleSessionListener) li;
sli.sessionEstablished(pt, rc, lc, session);
}
}
}
// Create a media session for each media manager in the session.
if (mediaNeg.getMediaManager() != null) {
rc.removeCandidateEcho();
lc.removeCandidateEcho();
jingleMediaSession = getMediaNegotiator().getMediaManager().createMediaSession(pt, rc, lc, session);
jingleMediaSession.addMediaReceivedListener(session);
if (jingleMediaSession != null) {
jingleMediaSession.startTrasmit();
jingleMediaSession.startReceive();
for (TransportCandidate candidate : getTransportNegotiator().getOfferedCandidates())
candidate.removeCandidateEcho();
}
JingleMediaManager mediaManager = getMediaNegotiator().getMediaManager();
getSession().addJingleMediaSession(mediaManager.getName(), jingleMediaSession);
}
}
/**
* Stop a Jingle media session.
*/
public void stopJingleMediaSession() {
if (jingleMediaSession != null) {
jingleMediaSession.stopTrasmit();
jingleMediaSession.stopReceive();
}
}
/**
* The negotiator state for the ContentNegotiators is a special case.
* It is a roll-up of the sub-negotiator states.
*/
public JingleNegotiatorState getNegotiatorState() {
JingleNegotiatorState result = JingleNegotiatorState.PENDING;
if ((mediaNeg != null) && (transNeg != null)) {
if ((mediaNeg.getNegotiatorState() == JingleNegotiatorState.SUCCEEDED)
|| (transNeg.getNegotiatorState() == JingleNegotiatorState.SUCCEEDED))
result = JingleNegotiatorState.SUCCEEDED;
if ((mediaNeg.getNegotiatorState() == JingleNegotiatorState.FAILED)
|| (transNeg.getNegotiatorState() == JingleNegotiatorState.FAILED))
result = JingleNegotiatorState.FAILED;
}
// Store the state (to make it easier to know when debugging.)
setNegotiatorState(result);
return result;
}
}

View File

@ -0,0 +1,93 @@
/**
* $RCSfile: TestMediaManager.java,v $
* $Revision: 1.3 $
* $Date: 25/12/2006
* <p/>
* Copyright 2003-2006 Jive Software.
* <p/>
* 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
* <p/>
* http://www.apache.org/licenses/LICENSE-2.0
* <p/>
* 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.jingle.mediaimpl.test;
import org.jivesoftware.smackx.jingle.media.JingleMediaManager;
import org.jivesoftware.smackx.jingle.media.JingleMediaSession;
import org.jivesoftware.smackx.jingle.media.PayloadType;
import org.jivesoftware.smackx.jingle.nat.JingleTransportManager;
import org.jivesoftware.smackx.jingle.nat.TransportCandidate;
import org.jivesoftware.smackx.jingle.JingleSession;
import java.util.*;
/**
* Implements a MediaManager for test purposes.
*
* @author Thiago Camargo
*/
public class TestMediaManager extends JingleMediaManager {
public static final String MEDIA_NAME = "TestMedia";
private List<PayloadType> payloads = new ArrayList<PayloadType>();
private PayloadType preferredPayloadType = null;
public TestMediaManager(JingleTransportManager transportManager) {
super(transportManager);
}
/**
* Return all supported Payloads for this Manager.
*
* @return The Payload List
*/
public List<PayloadType> getPayloads() {
return payloads;
}
public void setPayloads(List<PayloadType> payloads) {
this.payloads.addAll(payloads);
}
/**
* Returns a new JingleMediaSession
*
* @param payloadType payloadType
* @param remote remote Candidate
* @param local local Candidate
* @return JingleMediaSession JingleMediaSession
*/
public JingleMediaSession createMediaSession(PayloadType payloadType, final TransportCandidate remote,
final TransportCandidate local, final JingleSession jingleSession) {
TestMediaSession session = null;
session = new TestMediaSession(payloadType, remote, local, "", jingleSession);
return session;
}
public PayloadType getPreferredPayloadType() {
if (preferredPayloadType != null)
return preferredPayloadType;
return super.getPreferredPayloadType();
}
public void setPreferredPayloadType(PayloadType preferredPayloadType) {
this.preferredPayloadType = preferredPayloadType;
}
public String getName() {
return MEDIA_NAME;
}
}

View File

@ -0,0 +1,92 @@
/**
* $RCSfile: TestMediaSession.java,v $
* $Revision: 1.1 $
* $Date: 08/11/2006
* <p/>
* Copyright 2003-2006 Jive Software.
* <p/>
* 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
* <p/>
* http://www.apache.org/licenses/LICENSE-2.0
* <p/>
* 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.jingle.mediaimpl.test;
import org.jivesoftware.smackx.jingle.JingleSession;
import org.jivesoftware.smackx.jingle.media.JingleMediaSession;
import org.jivesoftware.smackx.jingle.media.PayloadType;
import org.jivesoftware.smackx.jingle.nat.TransportCandidate;
/**
* This Class implements a complete JingleMediaSession for unit testing.
*
* @author Thiago Camargo
*/
public class TestMediaSession extends JingleMediaSession {
/**
* Creates a TestMediaSession with defined payload type, remote and local candidates
*
* @param payloadType Payload of the jmf
* @param remote the remote information. The candidate that the jmf will be sent to.
* @param local the local information. The candidate that will receive the jmf
* @param locator media locator
*/
public TestMediaSession(final PayloadType payloadType, final TransportCandidate remote, final TransportCandidate local,
final String locator, JingleSession jingleSession) {
super(payloadType, remote, local, "Test", jingleSession);
initialize();
}
/**
* Initialize the screen share channels.
*/
public void initialize() {
}
/**
* Starts transmission and for NAT Traversal reasons start receiving also.
*/
public void startTrasmit() {
}
/**
* Set transmit activity. If the active is true, the instance should trasmit.
* If it is set to false, the instance should pause transmit.
*
* @param active active state
*/
public void setTrasmit(boolean active) {
}
/**
* For NAT Reasons this method does nothing. Use startTransmit() to start transmit and receive jmf
*/
public void startReceive() {
// Do nothing
}
/**
* Stops transmission and for NAT Traversal reasons stop receiving also.
*/
public void stopTrasmit() {
}
/**
* For NAT Reasons this method does nothing. Use startTransmit() to start transmit and receive jmf
*/
public void stopReceive() {
}
}

View File

@ -0,0 +1,68 @@
package org.jivesoftware.smackx.jingle.nat;
import org.jivesoftware.smack.XMPPException;
import org.jivesoftware.smackx.jingle.ContentNegotiator;
import org.jivesoftware.smackx.jingle.JingleSession;
import org.jivesoftware.smackx.jingle.listeners.CreatedJingleSessionListener;
import org.jivesoftware.smackx.jingle.listeners.JingleSessionListener;
import org.jivesoftware.smackx.jingle.media.PayloadType;
/**
* $RCSfile: FixedTransportManager.java,v $
* $Revision: 1.1 $
* $Date: 15/11/2006
*
* Copyright 2003-2006 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.
*/
/**
* A Fixed Jingle Transport Manager implementation.
*
*/
public class FixedTransportManager extends JingleTransportManager implements JingleSessionListener, CreatedJingleSessionListener {
FixedResolver resolver;
public FixedTransportManager(FixedResolver inResolver) {
resolver = inResolver;
}
protected TransportResolver createResolver(JingleSession session) {
return resolver;
}
public void sessionEstablished(PayloadType pt, TransportCandidate rc, TransportCandidate lc, JingleSession jingleSession) {
}
public void sessionDeclined(String reason, JingleSession jingleSession) {
}
public void sessionRedirected(String redirection, JingleSession jingleSession) {
}
public void sessionClosed(String reason, JingleSession jingleSession) {
}
public void sessionClosedOnError(XMPPException e, JingleSession jingleSession) {
}
public void sessionMediaReceived(JingleSession jingleSession, String participant) {
// Do Nothing
}
public void sessionCreated(JingleSession jingleSession) {
jingleSession.addListener(this);
}
}