mirror of
https://github.com/vanitasvitae/Smack.git
synced 2024-12-26 12:37:58 +01:00
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:
parent
646271abac
commit
d23d36974f
4 changed files with 575 additions and 0 deletions
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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() {
|
||||
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue