diff --git a/lib/installer-exclude/ice4j.jar b/lib/installer-exclude/ice4j.jar
index 6893ed708..e29fa550a 100644
Binary files a/lib/installer-exclude/ice4j.jar and b/lib/installer-exclude/ice4j.jar differ
diff --git a/src/net/java/sip/communicator/impl/neomedia/MediaStreamImpl.java b/src/net/java/sip/communicator/impl/neomedia/MediaStreamImpl.java
index e4eb36890..acbb3a17e 100644
--- a/src/net/java/sip/communicator/impl/neomedia/MediaStreamImpl.java
+++ b/src/net/java/sip/communicator/impl/neomedia/MediaStreamImpl.java
@@ -724,6 +724,66 @@ private void deviceSessionSsrcListChanged(PropertyChangeEvent evt)
this.localContributingSourceIDList = csrcArray;
}
+ /**
+ * Sets the target of this MediaStream to which it is to send and
+ * from which it is to receive data (e.g. RTP) and control data (e.g. RTCP).
+ * In contrast to {@link #setTarget(MediaStreamTarget)}, sets the specified
+ * target on this MediaStreamImpl even if its current
+ * target is equal to the specified one.
+ *
+ * @param target the MediaStreamTarget describing the data
+ * (e.g. RTP) and the control data (e.g. RTCP) locations to which this
+ * MediaStream is to send and from which it is to receive
+ * @see MediaStreamImpl#setTarget(MediaStreamTarget)
+ */
+ private void doSetTarget(MediaStreamTarget target)
+ {
+ rtpConnector.removeTargets();
+ rtpConnectorTarget = null;
+
+ boolean targetIsSet;
+
+ if (target != null)
+ {
+ InetSocketAddress dataAddr = target.getDataAddress();
+ InetSocketAddress controlAddr = target.getControlAddress();
+
+ try
+ {
+ rtpConnector
+ .addTarget(
+ new SessionAddress(
+ dataAddr.getAddress(),
+ dataAddr.getPort(),
+ controlAddr.getAddress(),
+ controlAddr.getPort()));
+ targetIsSet = true;
+ }
+ catch (IOException ioe)
+ {
+ // TODO
+ targetIsSet = false;
+ logger.error("Failed to set target " + target, ioe);
+ }
+ }
+ else
+ targetIsSet = true;
+
+ if (targetIsSet)
+ {
+ rtpConnectorTarget = target;
+
+ if (logger.isTraceEnabled())
+ logger
+ .trace(
+ "Set target of "
+ + getClass().getSimpleName()
+ + " with hashCode "
+ + hashCode()
+ + " to "
+ + target);
+ }
+ }
/**
* Gets the MediaDevice that this stream uses to play back and
* capture media.
@@ -1091,8 +1151,17 @@ protected void rtpConnectorChanged(
{
zrtpControl.setConnector(newValue);
- // Register the transform engines that we will be using in this stream.
- rtpConnector.setEngine(createTransformEngineChain());
+ if (newValue != null)
+ {
+ /*
+ * Register the transform engines that we will be using in this
+ * stream.
+ */
+ newValue.setEngine(createTransformEngineChain());
+
+ if (rtpConnectorTarget != null)
+ doSetTarget(rtpConnectorTarget);
+ }
}
/**
@@ -1354,51 +1423,7 @@ public void setTarget(MediaStreamTarget target)
else if (target.equals(rtpConnectorTarget))
return;
- rtpConnector.removeTargets();
- rtpConnectorTarget = null;
-
- boolean targetIsSet;
-
- if (target != null)
- {
- InetSocketAddress dataAddr = target.getDataAddress();
- InetSocketAddress controlAddr = target.getControlAddress();
-
- try
- {
- rtpConnector
- .addTarget(
- new SessionAddress(
- dataAddr.getAddress(),
- dataAddr.getPort(),
- controlAddr.getAddress(),
- controlAddr.getPort()));
- targetIsSet = true;
- }
- catch (IOException ioe)
- {
- // TODO
- targetIsSet = false;
- logger.error("Failed to set target " + target, ioe);
- }
- }
- else
- targetIsSet = true;
-
- if (targetIsSet)
- {
- rtpConnectorTarget = target;
-
- if (logger.isTraceEnabled())
- logger
- .trace(
- "Set target of "
- + getClass().getSimpleName()
- + " with hashCode "
- + hashCode()
- + " to "
- + target);
- }
+ doSetTarget(target);
}
/**
diff --git a/src/net/java/sip/communicator/impl/protocol/jabber/CallJabberImpl.java b/src/net/java/sip/communicator/impl/protocol/jabber/CallJabberImpl.java
index eaf84af36..0c20f135a 100644
--- a/src/net/java/sip/communicator/impl/protocol/jabber/CallJabberImpl.java
+++ b/src/net/java/sip/communicator/impl/protocol/jabber/CallJabberImpl.java
@@ -15,26 +15,23 @@
import net.java.sip.communicator.util.*;
/**
- * A Jabber implementation of the Call abstract class encapsulating Jabber
- * jingle sessions.
+ * A Jabber implementation of the Call abstract class encapsulating
+ * Jabber jingle sessions.
*
* @author Emil Ivov
*/
-public class CallJabberImpl extends MediaAwareCall<
- CallPeerJabberImpl,
- OperationSetBasicTelephonyJabberImpl,
- ProtocolProviderServiceJabberImpl>
+public class CallJabberImpl
+ extends MediaAwareCall<
+ CallPeerJabberImpl,
+ OperationSetBasicTelephonyJabberImpl,
+ ProtocolProviderServiceJabberImpl>
{
/**
- * Logger of this class
+ * The Logger used by the CallJabberImpl class and its
+ * instances for logging output.
*/
private static final Logger logger = Logger.getLogger(CallJabberImpl.class);
- /**
- * The operation set that created us.
- */
- private final OperationSetBasicTelephonyJabberImpl parentOpSet;
-
/**
* Indicates if the CallPeer will support inputevt
* extension (i.e. will be able to be remote-controlled).
@@ -42,11 +39,11 @@ public class CallJabberImpl extends MediaAwareCall<
private boolean localInputEvtAware = false;
/**
- * Crates a CallJabberImpl instance belonging to sourceProvider and
- * associated with the jingle session with the specified jingleSID.
- * If this call corresponds to an incoming jingle session then the jingleSID
- * would come from there. Otherwise one could generate one using {@link
- * JingleIQ#generateSID()}
+ * Initializes a new CallJabberImpl instance belonging to
+ * sourceProvider and associated with the jingle session with the
+ * specified jingleSID. If the new instance corresponds to an
+ * incoming jingle session, then the jingleSID would come from there.
+ * Otherwise, one could generate one using {@link JingleIQ#generateSID()}.
*
* @param parentOpSet the {@link OperationSetBasicTelephonyJabberImpl}
* instance in the context of which this call has been created.
@@ -55,7 +52,6 @@ protected CallJabberImpl(
OperationSetBasicTelephonyJabberImpl parentOpSet)
{
super(parentOpSet);
- this.parentOpSet = parentOpSet;
//let's add ourselves to the calls repo. we are doing it ourselves just
//to make sure that no one ever forgets.
@@ -113,9 +109,7 @@ public CallPeerJabberImpl processSessionInitiate(JingleIQ jingleIQ)
// if this was the first peer we added in this call then the call is
// new and we also need to notify everyone of its creation.
if(this.getCallPeerCount() == 1)
- {
parentOpSet.fireCallEvent( CallEvent.CALL_RECEIVED, this);
- }
return callPeer;
}
@@ -142,6 +136,7 @@ public CallPeerJabberImpl initiateSession(String calleeJID,
{
// create the session-initiate IQ
CallPeerJabberImpl callPeer = new CallPeerJabberImpl(calleeJID, this);
+
callPeer.setDiscoverInfo(discoverInfo);
addCallPeer(callPeer);
@@ -151,9 +146,7 @@ public CallPeerJabberImpl initiateSession(String calleeJID,
// if this was the first peer we added in this call then the call is
// new and we also need to notify everyone of its creation.
if(this.getCallPeerCount() == 1)
- {
parentOpSet.fireCallEvent( (CallEvent.CALL_INITIATED), this);
- }
/* enable video if it is a videocall */
callPeer.getMediaHandler().setLocalVideoTransmissionEnabled(
@@ -163,7 +156,7 @@ public CallPeerJabberImpl initiateSession(String calleeJID,
//set call state to connecting so that the user interface would start
//playing the tones. we do that here because we may be harvesting
- //stun/turn addresses in initiateSession() which would take a while..
+ //STUN/TURN addresses in initiateSession() which would take a while.
callPeer.setState( CallPeerState.CONNECTING);
callPeer.initiateSession();
@@ -187,9 +180,7 @@ public void modifyVideoContent(boolean allowed)
"Stop local video streaming");
for(CallPeerJabberImpl peer : getCallPeersVector())
- {
peer.sendModifyVideoContent(allowed);
- }
}
/**
@@ -203,13 +194,7 @@ public void modifyVideoContent(boolean allowed)
*/
public boolean containsJingleSID(String sid)
{
- for(CallPeerJabberImpl peer : getCallPeersVector())
- {
- if (peer.getJingleSID().equals(sid))
- return true;
- }
-
- return false;
+ return (getPeer(sid) != null);
}
/**
@@ -228,7 +213,6 @@ public CallPeerJabberImpl getPeer(String sid)
if (peer.getJingleSID().equals(sid))
return peer;
}
-
return null;
}
}
diff --git a/src/net/java/sip/communicator/impl/protocol/jabber/CallPeerJabberImpl.java b/src/net/java/sip/communicator/impl/protocol/jabber/CallPeerJabberImpl.java
index cffe4e3b9..1ce5af63d 100644
--- a/src/net/java/sip/communicator/impl/protocol/jabber/CallPeerJabberImpl.java
+++ b/src/net/java/sip/communicator/impl/protocol/jabber/CallPeerJabberImpl.java
@@ -19,7 +19,7 @@
import net.java.sip.communicator.util.*;
/**
- * Our Jabber implementation of the default CallPeer;
+ * Implements a Jabber CallPeer.
*
* @author Emil Ivov
*/
@@ -29,11 +29,11 @@ public class CallPeerJabberImpl
ProtocolProviderServiceJabberImpl>
{
/**
- * The Logger used by the CallPeerJabberImpl
- * class and its instances for logging output.
+ * The Logger used by the CallPeerJabberImpl class and its
+ * instances for logging output.
*/
- private static final Logger logger = Logger
- .getLogger(CallPeerJabberImpl.class.getName());
+ private static final Logger logger
+ = Logger.getLogger(CallPeerJabberImpl.class);
/**
* The jabber address of this peer
@@ -99,7 +99,7 @@ public void setAddress(String address)
fireCallPeerChangeEvent(
CallPeerChangeEvent.CALL_PEER_ADDRESS_CHANGE,
oldAddress,
- address.toString());
+ address);
}
/**
@@ -111,15 +111,10 @@ public String getDisplayName()
{
if (getCall() != null)
{
- ProtocolProviderService pps = getCall().getProtocolProvider();
- OperationSetPresence opSetPresence
- = pps.getOperationSet(OperationSetPresence.class);
+ Contact contact = getContact();
- Contact cont = opSetPresence.findContactByID(getAddress());
- if (cont != null)
- {
- return cont.getDisplayName();
- }
+ if (contact != null)
+ return contact.getDisplayName();
}
return peerJID;
}
@@ -153,26 +148,30 @@ protected synchronized void processSessionInitiate(JingleIQ sessionInitIQ)
this.sessionInitIQ = sessionInitIQ;
this.isInitiator = true;
- // This is the SDP offer that came from the initial session-initiate,
- //contrary to sip we we are guaranteed to have content because XEP-0166
- //says: "A session consists of at least one content type at a time."
+ // This is the SDP offer that came from the initial session-initiate.
+ // Contrary to SIP, we are guaranteed to have content because XEP-0166
+ // says: "A session consists of at least one content type at a time."
List offer = sessionInitIQ.getContentList();
try
{
getMediaHandler().processOffer(offer);
}
- catch(Exception exc)
+ catch(Exception ex)
{
- logger.info("Failed to process an incoming session initiate", exc);
+ logger.info("Failed to process an incoming session initiate", ex);
//send an error response;
- JingleIQ errResp = JinglePacketFactory.createSessionTerminate(
- sessionInitIQ.getTo(), sessionInitIQ.getFrom(),
- sessionInitIQ.getSID(), Reason.INCOMPATIBLE_PARAMETERS,
- "Error: " + exc.getMessage());
-
- setState(CallPeerState.FAILED, "Error: " + exc.getMessage());
+ String reasonText = "Error: " + ex.getMessage();
+ JingleIQ errResp
+ = JinglePacketFactory.createSessionTerminate(
+ sessionInitIQ.getTo(),
+ sessionInitIQ.getFrom(),
+ sessionInitIQ.getSID(),
+ Reason.INCOMPATIBLE_PARAMETERS,
+ reasonText);
+
+ setState(CallPeerState.FAILED, reasonText);
getProtocolProvider().getConnection().sendPacket(errResp);
return;
}
@@ -196,19 +195,25 @@ protected synchronized void initiateSession()
throws OperationFailedException
{
isInitiator = false;
+
//Create the media description that we'd like to send to the other side.
- List offer = getMediaHandler()
- .createContentList();
+ List offer
+ = getMediaHandler().createContentList();
//send a ringing response
if (logger.isTraceEnabled())
logger.trace("will send ringing response: ");
- this.sessionInitIQ = JinglePacketFactory
- .createSessionInitiate( getProtocolProvider().getOurJID(),
- this.peerJID, JingleIQ.generateSID(), offer);
+ ProtocolProviderServiceJabberImpl protocolProvider
+ = getProtocolProvider();
- getProtocolProvider().getConnection().sendPacket(sessionInitIQ);
+ this.sessionInitIQ
+ = JinglePacketFactory.createSessionInitiate(
+ protocolProvider.getOurJID(),
+ this.peerJID,
+ JingleIQ.generateSID(),
+ offer);
+ protocolProvider.getConnection().sendPacket(sessionInitIQ);
}
/**
@@ -362,11 +367,11 @@ public void processSessionAccept(JingleIQ sessionInitIQ)
{
this.sessionInitIQ = sessionInitIQ;
- List offer = sessionInitIQ.getContentList();
+ List answer = sessionInitIQ.getContentList();
try
{
- getMediaHandler().processAnswer(offer);
+ getMediaHandler().processAnswer(answer);
}
catch(Exception exc)
{
@@ -495,8 +500,7 @@ private void sendAddVideoContent()
try
{
- contents = getMediaHandler().
- createContentList(MediaType.VIDEO);
+ contents = getMediaHandler().createContentList(MediaType.VIDEO);
}
catch(Exception exc)
{
@@ -504,11 +508,16 @@ private void sendAddVideoContent()
return;
}
- JingleIQ contentIQ = JinglePacketFactory
- .createContentAdd(getProtocolProvider().getOurJID(),
- this.peerJID, getJingleSID(), contents);
+ ProtocolProviderServiceJabberImpl protocolProvider
+ = getProtocolProvider();
+ JingleIQ contentIQ
+ = JinglePacketFactory.createContentAdd(
+ protocolProvider.getOurJID(),
+ this.peerJID,
+ getJingleSID(),
+ contents);
- getProtocolProvider().getConnection().sendPacket(contentIQ);
+ protocolProvider.getConnection().sendPacket(contentIQ);
}
/**
@@ -730,9 +739,7 @@ public void processContentRemove(JingleIQ content)
List contents = content.getContentList();
for(ContentPacketExtension ext : contents)
- {
getMediaHandler().removeRemoteContent(ext.getName());
- }
}
/**
diff --git a/src/net/java/sip/communicator/impl/protocol/jabber/CallPeerMediaHandlerJabberImpl.java b/src/net/java/sip/communicator/impl/protocol/jabber/CallPeerMediaHandlerJabberImpl.java
index 1ab2ae38c..f81bc2511 100644
--- a/src/net/java/sip/communicator/impl/protocol/jabber/CallPeerMediaHandlerJabberImpl.java
+++ b/src/net/java/sip/communicator/impl/protocol/jabber/CallPeerMediaHandlerJabberImpl.java
@@ -6,8 +6,11 @@
*/
package net.java.sip.communicator.impl.protocol.jabber;
+import java.lang.reflect.*;
import java.util.*;
+import org.jivesoftware.smackx.packet.*;
+
import net.java.sip.communicator.impl.protocol.jabber.extensions.jingle.*;
import net.java.sip.communicator.impl.protocol.jabber.extensions.jingle.ContentPacketExtension.*;
import net.java.sip.communicator.impl.protocol.jabber.jinglesdp.*;
@@ -22,6 +25,7 @@
* An XMPP specific extension of the generic media handler.
*
* @author Emil Ivov
+ * @author Lyubomir Marinov
*/
public class CallPeerMediaHandlerJabberImpl
extends CallPeerMediaHandler
@@ -34,10 +38,10 @@ public class CallPeerMediaHandlerJabberImpl
= Logger.getLogger(CallPeerMediaHandlerJabberImpl.class);
/**
- * A temporarily single transport manager that we use for generating
- * addresses until we properly implement both ICE and Raw UDP managers.
+ * The TransportManager implementation handling our address
+ * management.
*/
- private final TransportManagerJabberImpl transportManager;
+ private TransportManagerJabberImpl transportManager;
/**
* The current description of the streams that we have going toward the
@@ -76,8 +80,6 @@ public class CallPeerMediaHandlerJabberImpl
public CallPeerMediaHandlerJabberImpl(CallPeerJabberImpl peer)
{
super(peer, peer);
-
- transportManager = new IceUdpTransportManager(peer);
}
/**
@@ -94,12 +96,17 @@ public CallPeerMediaHandlerJabberImpl(CallPeerJabberImpl peer)
* @throws OperationFailedException the exception that we wanted this method
* to throw.
*/
- @Override
- protected void throwOperationFailedException(String message, int errorCode,
- Throwable cause) throws OperationFailedException
+ protected void throwOperationFailedException(
+ String message,
+ int errorCode,
+ Throwable cause)
+ throws OperationFailedException
{
ProtocolProviderServiceJabberImpl.throwOperationFailedException(
- message, errorCode, cause, logger);
+ message,
+ errorCode,
+ cause,
+ logger);
}
/**
@@ -188,8 +195,14 @@ protected MediaStream initStream(String streamName,
List rtpExtensions)
throws OperationFailedException
{
- MediaStream stream = super.initStream(connector, device, format,
- target, direction, rtpExtensions);
+ MediaStream stream
+ = super.initStream(
+ connector,
+ device,
+ format,
+ target,
+ direction,
+ rtpExtensions);
if(stream != null)
stream.setName(streamName);
@@ -218,8 +231,7 @@ public void processOffer(List offer)
{
// prepare to generate answers to all the incoming descriptions
List answerContentList
- = new ArrayList(offer.size());
-
+ = new ArrayList(offer.size());
boolean atLeastOneValidDescription = false;
for (ContentPacketExtension content : offer)
@@ -227,18 +239,19 @@ public void processOffer(List offer)
remoteContentMap.put(content.getName(), content);
RtpDescriptionPacketExtension description
- = JingleUtils.getRtpDescription(content);
+ = JingleUtils.getRtpDescription(content);
MediaType mediaType
- = MediaType.parseString( description.getMedia() );
+ = MediaType.parseString( description.getMedia() );
- List remoteFormats = JingleUtils.extractFormats(
- description, getDynamicPayloadTypes());
+ List remoteFormats
+ = JingleUtils.extractFormats(
+ description,
+ getDynamicPayloadTypes());
MediaDevice dev = getDefaultDevice(mediaType);
- MediaDirection devDirection = (dev == null)
- ? MediaDirection.INACTIVE
- : dev.getDirection();
+ MediaDirection devDirection
+ = (dev == null) ? MediaDirection.INACTIVE : dev.getDirection();
// Take the preference of the user with respect to streaming
// mediaType into account.
@@ -272,6 +285,22 @@ public void processOffer(List offer)
int targetDataPort = target.getDataAddress().getPort();
+ // transport
+ /*
+ * RawUdpTransportPacketExtension extends
+ * IceUdpTransportPacketExtension so getting
+ * IceUdpTransportPacketExtension should suffice.
+ */
+ IceUdpTransportPacketExtension transport
+ = content.getFirstChildOfType(
+ IceUdpTransportPacketExtension.class);
+
+ /*
+ * TODO If the offered transport is not supported, attempt to
+ * fall back to a supported one using transport-replace.
+ */
+ setTransportManager(transport.getNamespace());
+
if (mutuallySupportedFormats.isEmpty()
|| (devDirection == MediaDirection.INACTIVE)
|| (targetDataPort == 0))
@@ -331,10 +360,14 @@ public void processOffer(List offer)
}
if (!atLeastOneValidDescription)
- ProtocolProviderServiceJabberImpl
- .throwOperationFailedException("Offer contained no media "
- + " formats or no valid media descriptions.",
- OperationFailedException.ILLEGAL_ARGUMENT, null, logger);
+ {
+ ProtocolProviderServiceJabberImpl.throwOperationFailedException(
+ "Offer contained no media formats"
+ + " or no valid media descriptions.",
+ OperationFailedException.ILLEGAL_ARGUMENT,
+ null,
+ logger);
+ }
//now, before we go, tell the transport manager to start our candidate
//harvest
@@ -354,20 +387,22 @@ public void processOffer(List offer)
protected List generateSessionAccept()
throws OperationFailedException
{
+ TransportManagerJabberImpl transportManager = getTransportManager();
List sessAccept
- = getTransportManager().wrapupHarvest();
+ = transportManager.wrapupHarvest();
+ CallPeerJabberImpl peer = getPeer();
//user answered an incoming call so we go through whatever content
//entries we are initializing and init their corresponding streams
for(ContentPacketExtension ourContent : sessAccept)
{
RtpDescriptionPacketExtension description
- = JingleUtils.getRtpDescription(ourContent);
+ = JingleUtils.getRtpDescription(ourContent);
MediaType type = MediaType.parseString(description.getMedia());
//
StreamConnector connector
- = getTransportManager().getStreamConnector(type);
+ = transportManager.getStreamConnector(type);
//the device this stream would be reading from and writing to.
MediaDevice dev = getDefaultDevice(type);
@@ -382,7 +417,7 @@ protected List generateSessionAccept()
//stream direction
MediaDirection direction = JingleUtils.getDirection(
- ourContent, !getPeer().isInitiator());
+ ourContent, !peer.isInitiator());
//let's now see what was the format we announced as first and
//configure the stream with it.
@@ -425,15 +460,13 @@ protected List generateSessionAccept()
if(ourContent.getChildExtensionsOfType(
InputEvtPacketExtension.class) != null)
{
- OperationSetDesktopSharingClientJabberImpl client =
- (OperationSetDesktopSharingClientJabberImpl)
- this.getPeer().getProtocolProvider().getOperationSet(
- OperationSetDesktopSharingClient.class);
+ OperationSetDesktopSharingClientJabberImpl client
+ = (OperationSetDesktopSharingClientJabberImpl)
+ peer.getProtocolProvider().getOperationSet(
+ OperationSetDesktopSharingClient.class);
- if(client != null)
- {
+ if (client != null)
client.fireRemoteControlGranted();
- }
}
}
return sessAccept;
@@ -447,14 +480,14 @@ protected List generateSessionAccept()
* @return the {@link ContentPacketExtension}s of stream that this
* handler is prepared to initiate.
* @throws OperationFailedException if we fail to create the descriptions
- * for reasons like - problems with device interaction, allocating ports,
- * etc.
+ * for reasons like problems with device interaction, allocating ports, etc.
*/
private ContentPacketExtension createContent(MediaDevice dev)
+ throws OperationFailedException
{
- MediaDirection direction = dev.getDirection().and(
- getDirectionUserPreference(
- dev.getMediaType()));
+ MediaDirection direction
+ = dev.getDirection().and(
+ getDirectionUserPreference(dev.getMediaType()));
if(isLocallyOnHold())
direction = direction.and(MediaDirection.SENDONLY);
@@ -469,10 +502,11 @@ private ContentPacketExtension createContent(MediaDevice dev)
if(getPeer().getCall().isSipZrtpAttribute())
{
ZrtpControl control = getZrtpControls().get(dev.getMediaType());
+
if(control == null)
{
- control = JabberActivator.getMediaService()
- .createZrtpControl();
+ control
+ = JabberActivator.getMediaService().createZrtpControl();
getZrtpControls().put(dev.getMediaType(), control);
}
@@ -482,6 +516,7 @@ private ContentPacketExtension createContent(MediaDevice dev)
{
ZrtpHashPacketExtension hash
= new ZrtpHashPacketExtension();
+
hash.setVersion(helloHash[0]);
hash.setValue(helloHash[1]);
@@ -534,10 +569,15 @@ public List createContentList(MediaType mediaType)
}
//now add the transport elements
- getTransportManager().startCandidateHarvest(mediaDescs);
+ TransportManagerJabberImpl transportManager = getTransportManager();
+
+ transportManager.startCandidateHarvest(mediaDescs);
- //XXX ideally we wouldn't wrapup that quickly. we need to revisit this
- return getTransportManager().wrapupHarvest();
+ /*
+ * XXX Ideally, we wouldn't wrap up that quickly. We need to revisit
+ * this.
+ */
+ return transportManager.wrapupHarvest();
}
/**
@@ -550,15 +590,14 @@ public List createContentList(MediaType mediaType)
* streams that this handler is prepared to initiate.
*
* @throws OperationFailedException if we fail to create the descriptions
- * for reasons like - problems with device interaction, allocating ports,
- * etc.
+ * for reasons like problems with device interaction, allocating ports, etc.
*/
public List createContentList()
throws OperationFailedException
{
//Audio Media Description
List mediaDescs
- = new ArrayList();
+ = new ArrayList();
for (MediaType mediaType : MediaType.values())
{
@@ -574,9 +613,11 @@ public List createContentList()
if(direction != MediaDirection.INACTIVE)
{
- ContentPacketExtension content = createContentForOffer(
- dev.getSupportedFormats(), direction,
- dev.getSupportedExtensions());
+ ContentPacketExtension content
+ = createContentForOffer(
+ dev.getSupportedFormats(),
+ direction,
+ dev.getSupportedExtensions());
//ZRTP
if(getPeer().getCall().isSipZrtpAttribute())
@@ -607,8 +648,8 @@ public List createContentList()
*/
RtpDescriptionPacketExtension description
= JingleUtils.getRtpDescription(content);
- if(description.getMedia().equals(
- MediaType.VIDEO.toString()) && localInputEvtAware)
+ if(description.getMedia().equals(MediaType.VIDEO.toString())
+ && localInputEvtAware)
{
content.addChildExtension(
new InputEvtPacketExtension());
@@ -622,18 +663,24 @@ public List createContentList()
//fail if all devices were inactive
if(mediaDescs.isEmpty())
{
- ProtocolProviderServiceJabberImpl
- .throwOperationFailedException(
- "We couldn't find any active Audio/Video devices and "
- + "couldn't create a call",
- OperationFailedException.GENERAL_ERROR, null, logger);
+ ProtocolProviderServiceJabberImpl.throwOperationFailedException(
+ "We couldn't find any active Audio/Video devices"
+ + " and couldn't create a call",
+ OperationFailedException.GENERAL_ERROR,
+ null,
+ logger);
}
//now add the transport elements
- getTransportManager().startCandidateHarvest(mediaDescs);
+ TransportManagerJabberImpl transportManager = getTransportManager();
+
+ transportManager.startCandidateHarvest(mediaDescs);
- //XXX ideally we wouldn't wrapup that quickly. we need to revisit this
- return getTransportManager().wrapupHarvest();
+ /*
+ * XXX Ideally, we wouldn't wrap up that quickly. We need to revisit
+ * this.
+ */
+ return transportManager.wrapupHarvest();
}
/**
@@ -656,14 +703,15 @@ private ContentPacketExtension createContentForOffer(
MediaDirection direction,
List supportedExtensions)
{
- ContentPacketExtension content = JingleUtils.createDescription(
- CreatorEnum.initiator,
- supportedFormats.get(0).getMediaType().toString(),
- JingleUtils.getSenders(direction, !getPeer().isInitiator()),
- supportedFormats,
- supportedExtensions,
- getDynamicPayloadTypes(),
- getRtpExtensionsRegistry());
+ ContentPacketExtension content
+ = JingleUtils.createDescription(
+ CreatorEnum.initiator,
+ supportedFormats.get(0).getMediaType().toString(),
+ JingleUtils.getSenders(direction, !getPeer().isInitiator()),
+ supportedFormats,
+ supportedExtensions,
+ getDynamicPayloadTypes(),
+ getRtpExtensionsRegistry());
this.localContentMap.put(content.getName(), content);
return content;
@@ -708,10 +756,11 @@ public void reinitAllContents()
* in this operation can synchronize to the mediaHandler instance to wait
* processing to stop (method setState in CallPeer).
*/
- public void reinitContent(String name,
+ public void reinitContent(
+ String name,
ContentPacketExtension.SendersEnum senders)
- throws OperationFailedException,
- IllegalArgumentException
+ throws OperationFailedException,
+ IllegalArgumentException
{
ContentPacketExtension ext = remoteContentMap.get(name);
@@ -790,13 +839,13 @@ public void removeRemoteContent(String name)
*/
private void processContent(ContentPacketExtension content)
throws OperationFailedException,
- IllegalArgumentException
+ IllegalArgumentException
{
RtpDescriptionPacketExtension description
- = JingleUtils.getRtpDescription(content);
+ = JingleUtils.getRtpDescription(content);
MediaType mediaType
- = MediaType.parseString( description.getMedia() );
+ = MediaType.parseString( description.getMedia() );
//stream target
MediaStreamTarget target
@@ -882,24 +931,130 @@ public void processAnswer(List answer)
throws OperationFailedException,
IllegalArgumentException
{
- for ( ContentPacketExtension content : answer)
+ for (ContentPacketExtension content : answer)
{
remoteContentMap.put(content.getName(), content);
processContent(content);
}
+
+ /*
+ * Since we've received (the) remote candidates from the peer, we can
+ * start checking them for connectivity.
+ */
+ startConnectivityEstablishment(answer);
}
/**
- * Returns the transport manager that is handling our address management.
+ * Gets the TransportManager implementation handling our address
+ * management.
*
- * @return the transport manager that is handling our address management.
+ * @return the TransportManager implementation handling our address
+ * management
+ * @see CallPeerMediaHandler#getTransportManager()
*/
public TransportManagerJabberImpl getTransportManager()
{
+ if (transportManager == null)
+ {
+ CallPeerJabberImpl peer = getPeer();
+
+ if (peer.isInitiator())
+ {
+ throw new IllegalStateException(
+ "The initiator is expected to specify the transport"
+ + " in their offer.");
+ }
+ else
+ {
+ ScServiceDiscoveryManager discoveryManager
+ = peer.getProtocolProvider().getDiscoveryManager();
+ DiscoverInfo peerDiscoverInfo = peer.getDiscoverInfo();
+
+ if (discoveryManager.includesFeature(
+ ProtocolProviderServiceJabberImpl
+ .URN_XMPP_JINGLE_ICE_UDP_1)
+ && ((peerDiscoverInfo == null)
+ || peerDiscoverInfo.containsFeature(
+ ProtocolProviderServiceJabberImpl
+ .URN_XMPP_JINGLE_ICE_UDP_1)))
+ {
+ transportManager = new IceUdpTransportManager(peer);
+ }
+ else if (discoveryManager.includesFeature(
+ ProtocolProviderServiceJabberImpl
+ .URN_XMPP_JINGLE_RAW_UDP_0)
+ && ((peerDiscoverInfo == null)
+ || peerDiscoverInfo.containsFeature(
+ ProtocolProviderServiceJabberImpl
+ .URN_XMPP_JINGLE_RAW_UDP_0)))
+ {
+ transportManager = new RawUdpTransportManager(peer);
+ }
+ else if (logger.isDebugEnabled())
+ {
+ logger.debug(
+ "No known Jingle transport supported"
+ + " by Jabber call peer "
+ + peer);
+ }
+ }
+ }
return transportManager;
}
+ /**
+ * Sets the TransportManager implementation to handle our address
+ * management by Jingle transport XML namespace.
+ *
+ * @param xmlns the Jingle transport XML namespace specifying the
+ * TransportManager implementation type to be set on this instance
+ * to handle our address management
+ * @throws IllegalArgumentException if the specified xmlns does not
+ * specify a (supported) TransportManager implementation type
+ */
+ private void setTransportManager(String xmlns)
+ throws IllegalArgumentException
+ {
+ // Is this really going to be an actual change?
+ if ((transportManager != null)
+ && transportManager.getXmlNamespace().equals(xmlns))
+ {
+ return;
+ }
+
+ CallPeerJabberImpl peer = getPeer();
+
+ if (!peer
+ .getProtocolProvider()
+ .getDiscoveryManager().includesFeature(xmlns))
+ {
+ throw new IllegalArgumentException(
+ "Unsupported Jingle transport " + xmlns);
+ }
+
+ /*
+ * TODO The transportManager is going to be changed so it may need to be
+ * disposed prior to the change.
+ */
+
+ if (xmlns.equals(
+ ProtocolProviderServiceJabberImpl.URN_XMPP_JINGLE_ICE_UDP_1))
+ {
+ transportManager = new IceUdpTransportManager(peer);
+ }
+ else if (xmlns.equals(
+ ProtocolProviderServiceJabberImpl.URN_XMPP_JINGLE_RAW_UDP_0))
+ {
+ transportManager = new RawUdpTransportManager(peer);
+ }
+ else
+ {
+ throw new IllegalArgumentException(
+ "Unsupported Jingle transport " + xmlns);
+ }
+ }
+
/**
* Acts upon a notification received from the remote party indicating that
* they've put us on/off hold.
@@ -910,6 +1065,7 @@ public TransportManagerJabberImpl getTransportManager()
public void setRemotelyOnHold(boolean onHold)
{
this.remotelyOnHold = onHold;
+
MediaStream audioStream = getStream(MediaType.AUDIO);
MediaStream videoStream = getStream(MediaType.VIDEO);
@@ -969,8 +1125,9 @@ private MediaDirection calculatePostHoldDirection(MediaStream stream)
//2. check the user preference.
MediaDevice device = stream.getDevice();
- postHoldDir = postHoldDir
- .and(getDirectionUserPreference(device.getMediaType()));
+ postHoldDir
+ = postHoldDir.and(
+ getDirectionUserPreference(device.getMediaType()));
//3. check our local hold status.
if(isLocallyOnHold())
@@ -983,4 +1140,69 @@ private MediaDirection calculatePostHoldDirection(MediaStream stream)
return postHoldDir;
}
+
+ /**
+ * Overrides {@link CallPeerMediaHandler#start()}. Prior to starting this
+ * CallPeerMediaHandler, makes sure connectivity establishment
+ * through the associated TransportManager has been started in
+ * order to determine the StreamConnectors and the
+ * MediaStreamTargets of the MediaStreams managed by this
+ * instance.
+ *
+ * @throws IllegalStateException if this CallPeerMediaHandler has
+ * not first seen a media description or has not generated an offer
+ * @see CallPeerMediaHandler#start()
+ */
+ @Override
+ public void start()
+ throws IllegalStateException
+ {
+ if (getPeer().isInitiator())
+ {
+ try
+ {
+ startConnectivityEstablishment(remoteContentMap.values());
+ }
+ catch (OperationFailedException ofe)
+ {
+ throw new UndeclaredThrowableException(ofe);
+ }
+ }
+
+ super.start();
+ }
+
+ /**
+ * Starts the connectivity establishment of the associated
+ * TransportManagerJabberImpl i.e. checks the connectivity between
+ * the local and the remote peers given the remote counterpart of the
+ * negotiation between them and sets the respective connectors and
+ * targets of the associated MediaStreams.
+ *
+ * @param remote the collection of ContentPacketExtensions which
+ * represents the remote counterpart of the negotiation between the local
+ * and the remote peers
+ * @throws OperationFailedException if anything goes wrong while starting
+ * the connectivity establishment or setting the connectors or
+ * targets of the associated MediaStreams
+ */
+ private void startConnectivityEstablishment(
+ Collection remote)
+ throws OperationFailedException
+ {
+ TransportManagerJabberImpl transportManager = getTransportManager();
+
+ transportManager.startConnectivityEstablishment(remote);
+ for (MediaType mediaType : MediaType.values())
+ {
+ MediaStream stream = getStream(mediaType);
+
+ if (stream != null)
+ {
+ stream.setConnector(
+ transportManager.getStreamConnector(mediaType));
+ stream.setTarget(transportManager.getStreamTarget(mediaType));
+ }
+ }
+ }
}
diff --git a/src/net/java/sip/communicator/impl/protocol/jabber/IceUdpTransportManager.java b/src/net/java/sip/communicator/impl/protocol/jabber/IceUdpTransportManager.java
index e8b357c19..04ca8cebb 100644
--- a/src/net/java/sip/communicator/impl/protocol/jabber/IceUdpTransportManager.java
+++ b/src/net/java/sip/communicator/impl/protocol/jabber/IceUdpTransportManager.java
@@ -6,10 +6,13 @@
*/
package net.java.sip.communicator.impl.protocol.jabber;
+import java.beans.*;
+import java.net.*;
import java.util.*;
import net.java.sip.communicator.impl.protocol.jabber.extensions.jingle.*;
import net.java.sip.communicator.impl.protocol.jabber.jinglesdp.*;
+import net.java.sip.communicator.service.neomedia.*;
import net.java.sip.communicator.service.netaddr.*;
import net.java.sip.communicator.service.protocol.*;
import net.java.sip.communicator.util.*;
@@ -24,6 +27,7 @@
* candidate management.
*
* @author Emil Ivov
+ * @author Lyubomir Marinov
*/
public class IceUdpTransportManager
extends TransportManagerJabberImpl
@@ -32,12 +36,19 @@ public class IceUdpTransportManager
* The Logger used by the IceUdpTransportManager
* class and its instances for logging output.
*/
- private static final Logger logger = Logger
- .getLogger(IceUdpTransportManager.class.getName());
+ private static final Logger logger
+ = Logger.getLogger(IceUdpTransportManager.class);
+
+ /**
+ * The ICE Component IDs in their common order used, for example,
+ * by DefaultStreamConnector, MediaStreamTarget.
+ */
+ private static final int[] COMPONENT_IDS
+ = new int[] { Component.RTP, Component.RTCP };
/**
* This is where we keep our answer between the time we get the offer and
- * are ready with the answer;
+ * are ready with the answer.
*/
private List cpeList;
@@ -54,7 +65,7 @@ public class IceUdpTransportManager
* @param callPeer the {@link CallPeer} whose traffic we will be taking
* care of.
*/
- protected IceUdpTransportManager(CallPeerJabberImpl callPeer)
+ public IceUdpTransportManager(CallPeerJabberImpl callPeer)
{
super(callPeer);
@@ -70,12 +81,18 @@ protected IceUdpTransportManager(CallPeerJabberImpl callPeer)
*/
private Agent createIceAgent()
{
- ProtocolProviderServiceJabberImpl provider
- = getCallPeer().getProtocolProvider();
+ CallPeerJabberImpl peer = getCallPeer();
+ ProtocolProviderServiceJabberImpl provider = peer.getProtocolProvider();
NetworkAddressManagerService namSer = getNetAddrMgr();
Agent agent = namSer.createIceAgent();
+ /*
+ * XEP-0176: the initiator MUST include the ICE-CONTROLLING attribute,
+ * the responder MUST include the ICE-CONTROLLED attribute.
+ */
+ agent.setControlling(!peer.isInitiator());
+
//we will now create the harvesters
JabberAccountID accID = (JabberAccountID)provider.getAccountID();
@@ -84,15 +101,18 @@ private Agent createIceAgent()
//the default server is supposed to use the same user name and
//password as the account itself.
String username = provider.getOurJID();
- String password = JabberActivator
- .getProtocolProviderFactory().loadPassword(accID);
+ String password
+ = JabberActivator.getProtocolProviderFactory().loadPassword(
+ accID);
- StunCandidateHarvester autoHarvester = namSer.discoverStunServer(
- accID.getService(),
- StringUtils.getUTF8Bytes(username),
- StringUtils.getUTF8Bytes(password) );
+ StunCandidateHarvester autoHarvester
+ = namSer.discoverStunServer(
+ accID.getService(),
+ StringUtils.getUTF8Bytes(username),
+ StringUtils.getUTF8Bytes(password));
- logger.info("Auto discovered harvester is " + autoHarvester);
+ if (logger.isInfoEnabled())
+ logger.info("Auto discovered harvester is " + autoHarvester);
if (autoHarvester != null)
agent.addCandidateHarvester(autoHarvester);
@@ -110,9 +130,12 @@ private Agent createIceAgent()
if(desc.isTurnSupported())
{
//Yay! a TURN server
- harvester = new TurnCandidateHarvester(
- addr, new LongTermCredential(
- desc.getUsername(), desc.getPassword()));
+ harvester
+ = new TurnCandidateHarvester(
+ addr,
+ new LongTermCredential(
+ desc.getUsername(),
+ desc.getPassword()));
}
else
{
@@ -120,7 +143,8 @@ addr, new LongTermCredential(
harvester = new StunCandidateHarvester(addr);
}
- logger.info("Adding pre-conficugred harvester " + harvester);
+ if (logger.isInfoEnabled())
+ logger.info("Adding pre-configured harvester " + harvester);
agent.addCandidateHarvester(harvester);
}
@@ -128,6 +152,206 @@ addr, new LongTermCredential(
return agent;
}
+ /**
+ * Initializes a new StreamConnector to be used as the
+ * connector of the MediaStream with a specific
+ * MediaType.
+ *
+ * @param mediaType the MediaType of the MediaStream which
+ * is to have its connector set to the returned
+ * StreamConnector
+ * @return a new StreamConnector to be used as the
+ * connector of the MediaStream with the specified
+ * MediaType
+ * @throws OperationFailedException if anything goes wrong while
+ * initializing the new StreamConnector
+ */
+ @Override
+ protected StreamConnector createStreamConnector(MediaType mediaType)
+ throws OperationFailedException
+ {
+ DatagramSocket[] streamConnectorSockets
+ = getStreamConnectorSockets(mediaType);
+
+ /*
+ * XXX If the iceAgent has not completed (yet), go with a default
+ * StreamConnector (until it completes).
+ */
+ return
+ (streamConnectorSockets == null)
+ ? super.createStreamConnector(mediaType)
+ : new DefaultStreamConnector(
+ streamConnectorSockets[0 /* RTP */],
+ streamConnectorSockets[1 /* RTCP */]);
+ }
+
+ /**
+ * Gets the StreamConnector to be used as the connector of
+ * the MediaStream with a specific MediaType.
+ *
+ * @param mediaType the MediaType of the MediaStream which
+ * is to have its connector set to the returned
+ * StreamConnector
+ * @return the StreamConnector to be used as the connector
+ * of the MediaStream with the specified MediaType
+ * @throws OperationFailedException if anything goes wrong while
+ * initializing the requested StreamConnector
+ * @see net.java.sip.communicator.service.protocol.media.TransportManager#getStreamConnector(MediaType)
+ */
+ @Override
+ public StreamConnector getStreamConnector(MediaType mediaType)
+ throws OperationFailedException
+ {
+ StreamConnector streamConnector = super.getStreamConnector(mediaType);
+
+ /*
+ * Since the super caches the StreamConnectors, make sure that the
+ * returned one is up-to-date with the iceAgent.
+ */
+ if (streamConnector != null)
+ {
+ DatagramSocket[] streamConnectorSockets
+ = getStreamConnectorSockets(mediaType);
+
+ /*
+ * XXX If the iceAgent has not completed (yet), go with the default
+ * StreamConnector (until it completes).
+ */
+ if ((streamConnectorSockets != null)
+ && ((streamConnector.getDataSocket()
+ != streamConnectorSockets[0 /* RTP */])
+ || (streamConnector.getControlSocket()
+ != streamConnectorSockets[1 /* RTCP */])))
+ {
+ // Recreate the StreamConnector for the specified mediaType.
+ closeStreamConnector(mediaType);
+ streamConnector = super.getStreamConnector(mediaType);
+ }
+ }
+ return streamConnector;
+ }
+
+ /**
+ * Gets an array of DatagramSockets which represents the sockets to
+ * be used by the StreamConnector with the specified
+ * MediaType in the order of {@link #COMPONENT_IDS} if
+ * {@link #iceAgent} has completed.
+ *
+ * @param mediaType the MediaType of the StreamConnector
+ * for which the DatagramSockets are to be returned
+ * @return an array of DatagramSockets which represents the sockets
+ * to be used by the StreamConnector which the specified
+ * MediaType in the order of {@link #COMPONENT_IDS} if
+ * {@link #iceAgent} has completed; otherwise, null
+ */
+ private DatagramSocket[] getStreamConnectorSockets(MediaType mediaType)
+ {
+ IceMediaStream stream = iceAgent.getStream(mediaType.toString());
+
+ if (stream != null)
+ {
+ DatagramSocket[] streamConnectorSockets
+ = new DatagramSocket[COMPONENT_IDS.length];
+ int streamConnectorSocketCount = 0;
+
+ for (int i = 0; i < COMPONENT_IDS.length; i++)
+ {
+ Component component = stream.getComponent(COMPONENT_IDS[i]);
+
+ if (component != null)
+ {
+ CandidatePair selectedPair = component.getSelectedPair();
+
+ if (selectedPair != null)
+ {
+ DatagramSocket streamConnectorSocket
+ = selectedPair.getLocalCandidate().getSocket();
+
+ if (streamConnectorSocket != null)
+ {
+ streamConnectorSockets[i] = streamConnectorSocket;
+ streamConnectorSocketCount++;
+ }
+ }
+ }
+ }
+ if (streamConnectorSocketCount > 0)
+ return streamConnectorSockets;
+ }
+ return null;
+ }
+
+ /**
+ * Implements {@link TransportManagerJabberImpl#getStreamTarget(MediaType)}.
+ * Gets the MediaStreamTarget to be used as the target of
+ * the MediaStream with a specific MediaType.
+ *
+ * @param mediaType the MediaType of the MediaStream which
+ * is to have its target set to the returned
+ * MediaStreamTarget
+ * @return the MediaStreamTarget to be used as the target
+ * of the MediaStream with the specified MediaType
+ * @see TransportManagerJabberImpl#getStreamTarget(MediaType)
+ */
+ public MediaStreamTarget getStreamTarget(MediaType mediaType)
+ {
+ IceMediaStream stream = iceAgent.getStream(mediaType.toString());
+ MediaStreamTarget streamTarget = null;
+
+ if (stream != null)
+ {
+ InetSocketAddress[] streamTargetAddresses
+ = new InetSocketAddress[COMPONENT_IDS.length];
+ int streamTargetAddressCount = 0;
+
+ for (int i = 0; i < COMPONENT_IDS.length; i++)
+ {
+ Component component = stream.getComponent(COMPONENT_IDS[i]);
+
+ if (component != null)
+ {
+ CandidatePair selectedPair = component.getSelectedPair();
+
+ if (selectedPair != null)
+ {
+ InetSocketAddress streamTargetAddress
+ = selectedPair
+ .getRemoteCandidate()
+ .getTransportAddress();
+
+ if (streamTargetAddress != null)
+ {
+ streamTargetAddresses[i] = streamTargetAddress;
+ streamTargetAddressCount++;
+ }
+ }
+ }
+ }
+ if (streamTargetAddressCount > 0)
+ {
+ streamTarget
+ = new MediaStreamTarget(
+ streamTargetAddresses[0 /* RTP */],
+ streamTargetAddresses[1 /* RTCP */]);
+ }
+ }
+ return streamTarget;
+ }
+
+ /**
+ * Implements {@link TransportManagerJabberImpl#getXmlNamespace()}. Gets the
+ * XML namespace of the Jingle transport implemented by this
+ * TransportManagerJabberImpl.
+ *
+ * @return the XML namespace of the Jingle transport implemented by this
+ * TransportManagerJabberImpl
+ * @see TransportManagerJabberImpl#getXmlNamespace()
+ */
+ public String getXmlNamespace()
+ {
+ return ProtocolProviderServiceJabberImpl.URN_XMPP_JINGLE_ICE_UDP_1;
+ }
+
/**
* Starts transport candidate harvest. This method should complete rapidly
* and, in case of lengthy procedures like STUN/TURN/UPnP candidate harvests
@@ -158,15 +382,13 @@ public void startCandidateHarvest(List theirOffer,
continue;
RtpDescriptionPacketExtension rtpDesc
- = (RtpDescriptionPacketExtension)ourContent
- .getFirstChildOfType(RtpDescriptionPacketExtension.class);
+ = ourContent.getFirstChildOfType(
+ RtpDescriptionPacketExtension.class);
IceMediaStream stream = createIceStream(rtpDesc.getMedia());
//we now generate the XMPP code containing the candidates.
ourContent.addChildExtension(JingleUtils.createTransport(stream));
-
-
}
this.cpeList = ourAnswer;
@@ -191,12 +413,11 @@ public void startCandidateHarvest(
for(ContentPacketExtension ourContent : ourOffer)
{
RtpDescriptionPacketExtension rtpDesc
- = (RtpDescriptionPacketExtension)ourContent
- .getFirstChildOfType(RtpDescriptionPacketExtension.class);
+ = ourContent.getFirstChildOfType(
+ RtpDescriptionPacketExtension.class);
IceMediaStream stream = createIceStream(rtpDesc.getMedia());
-
//we now generate the XMPP code containing the candidates.
ourContent.addChildExtension(JingleUtils.createTransport(stream));
}
@@ -225,11 +446,12 @@ private IceMediaStream createIceStream(String media)
stream = getNetAddrMgr().createIceStream(
nextMediaPortToTry, media, iceAgent);
}
- catch (Exception exc)
+ catch (Exception ex)
{
throw new OperationFailedException(
"Failed to initialize stream " + media,
- OperationFailedException.INTERNAL_ERROR);
+ OperationFailedException.INTERNAL_ERROR,
+ ex);
}
//let's now update the next port var as best we can: we would assume
@@ -252,8 +474,6 @@ private IceMediaStream createIceStream(String media)
return stream;
}
-
-
/**
* Simply returns the list of local candidates that we gathered during the
* harvest. This is a raw udp transport manager so there's no real wrapping
@@ -267,29 +487,6 @@ public List wrapupHarvest()
return cpeList;
}
- /**
- * Looks through the cpExtList and returns the {@link
- * ContentPacketExtension} with the specified name.
- *
- * @param cpExtList the list that we will be searching for a specific
- * content.
- * @param name the name of the content element we are looking for.
- * @return the {@link ContentPacketExtension} with the specified name or
- * null if no such content element exists.
- */
- private ContentPacketExtension findContentByName(
- List cpExtList,
- String name)
- {
- for(ContentPacketExtension cpExt : cpExtList)
- {
- if(cpExt.getName().equals(name))
- return cpExt;
- }
-
- return null;
- }
-
/**
* Returns a reference to the {@link NetworkAddressManagerService}. The only
* reason this method exists is that {@link JabberActivator
@@ -302,4 +499,127 @@ private static NetworkAddressManagerService getNetAddrMgr()
{
return JabberActivator.getNetworkAddressManagerService();
}
+
+ /**
+ * Implements
+ * {@link TransportManagerJabberImpl#startConnectivityEstablishment(Collection)}.
+ * Starts the connectivity establishment of the associated ICE
+ * Agent and waits for it to complete.
+ *
+ * @param remote the collection of ContentPacketExtensions which
+ * represents the remote counterpart of the negotiation between the local
+ * and the remote peers
+ * @see TransportManagerJabberImpl#startConnectivityEstablishment(Collection)
+ */
+ public void startConnectivityEstablishment(
+ Collection remote)
+ {
+ int generation = iceAgent.getGeneration();
+
+ for (ContentPacketExtension content : remote)
+ {
+ IceUdpTransportPacketExtension transport
+ = content.getFirstChildOfType(
+ IceUdpTransportPacketExtension.class);
+
+ String ufrag = transport.getUfrag();
+
+ if (ufrag != null)
+ iceAgent.setRemoteUfrag(ufrag);
+
+ String password = transport.getPassword();
+
+ if (password != null)
+ iceAgent.setRemotePassword(password);
+
+ List candidates
+ = transport.getChildExtensionsOfType(
+ CandidatePacketExtension.class);
+
+ RtpDescriptionPacketExtension description
+ = content.getFirstChildOfType(
+ RtpDescriptionPacketExtension.class);
+ IceMediaStream stream = iceAgent.getStream(description.getMedia());
+
+ for (CandidatePacketExtension candidate : candidates)
+ {
+ /*
+ * Is the remote candidate from the current generation of the
+ * iceAgent?
+ */
+ if (candidate.getGeneration() != generation)
+ continue;
+
+ Component component
+ = stream.getComponent(candidate.getComponent());
+
+ component.addRemoteCandidate(
+ new RemoteCandidate(
+ new TransportAddress(
+ candidate.getIP(),
+ candidate.getPort(),
+ Transport.parse(
+ candidate.getProtocol())),
+ component,
+ org.ice4j.ice.CandidateType.parse(
+ candidate.getType().toString()),
+ Integer.toString(candidate.getFoundation()),
+ candidate.getPriority()));
+ }
+ }
+
+ final Object[] iceProcessingState = new Object[1];
+ PropertyChangeListener stateChangeListener
+ = new PropertyChangeListener()
+ {
+ public void propertyChange(PropertyChangeEvent evt)
+ {
+ Object newValue = evt.getNewValue();
+
+ if (IceProcessingState.COMPLETED.equals(newValue)
+ || IceProcessingState.FAILED.equals(newValue)
+ || IceProcessingState.TERMINATED.equals(newValue))
+ {
+ if (logger.isTraceEnabled())
+ logger.trace("ICE " + newValue);
+
+ Agent iceAgent = (Agent) evt.getSource();
+
+ iceAgent.removeStateChangeListener(this);
+
+ if (iceAgent == IceUdpTransportManager.this.iceAgent)
+ {
+ synchronized (iceProcessingState)
+ {
+ iceProcessingState[0] = newValue;
+ iceProcessingState.notify();
+ }
+ }
+ }
+ }
+ };
+
+ iceAgent.addStateChangeListener(stateChangeListener);
+ iceAgent.startConnectivityEstablishment();
+
+ // Wait for the connectivity checks to finish.
+ boolean interrupted = false;
+
+ synchronized (iceProcessingState)
+ {
+ while (iceProcessingState[0] == null)
+ {
+ try
+ {
+ iceProcessingState.wait();
+ }
+ catch (InterruptedException ie)
+ {
+ interrupted = true;
+ }
+ }
+ }
+ if (interrupted)
+ Thread.currentThread().interrupt();
+ }
}
diff --git a/src/net/java/sip/communicator/impl/protocol/jabber/RawUdpTransportManager.java b/src/net/java/sip/communicator/impl/protocol/jabber/RawUdpTransportManager.java
index 1e889f103..a91fc7b74 100644
--- a/src/net/java/sip/communicator/impl/protocol/jabber/RawUdpTransportManager.java
+++ b/src/net/java/sip/communicator/impl/protocol/jabber/RawUdpTransportManager.java
@@ -9,6 +9,7 @@
import java.util.*;
import net.java.sip.communicator.impl.protocol.jabber.extensions.jingle.*;
+import net.java.sip.communicator.impl.protocol.jabber.jinglesdp.*;
import net.java.sip.communicator.service.neomedia.*;
import net.java.sip.communicator.service.protocol.*;
@@ -17,15 +18,23 @@
* single candidate pair (i.e. RTP and RTCP).
*
* @author Emil Ivov
+ * @author Lyubomir Marinov
*/
public class RawUdpTransportManager
extends TransportManagerJabberImpl
{
/**
- * This is where we keep our answer between the time we get the offer and
- * are ready with the answer;
+ * The list of ContentPacketExtensions which represents the local
+ * counterpart of the negotiation between the local and the remote peers.
*/
- private List cpeList;
+ private List local;
+
+ /**
+ * The collection of ContentPacketExtensions which represents the
+ * remote counterpart of the negotiation between the local and the remote
+ * peers.
+ */
+ private Collection remote;
/**
* Creates a new instance of this transport manager, binding it to the
@@ -34,11 +43,61 @@ public class RawUdpTransportManager
* @param callPeer the {@link CallPeer} whose traffic we will be taking
* care of.
*/
- protected RawUdpTransportManager(CallPeerJabberImpl callPeer)
+ public RawUdpTransportManager(CallPeerJabberImpl callPeer)
{
super(callPeer);
}
+ /**
+ * Implements {@link TransportManagerJabberImpl#getStreamTarget(MediaType)}.
+ * Gets the MediaStreamTarget to be used as the target of
+ * the MediaStream with a specific MediaType.
+ *
+ * @param mediaType the MediaType of the MediaStream which
+ * is to have its target set to the returned
+ * MediaStreamTarget
+ * @return the MediaStreamTarget to be used as the target
+ * of the MediaStream with the specified MediaType
+ * @see TransportManagerJabberImpl#getStreamTarget(MediaType)
+ */
+ public MediaStreamTarget getStreamTarget(MediaType mediaType)
+ {
+ MediaStreamTarget streamTarget = null;
+
+ if (remote != null)
+ {
+ for (ContentPacketExtension content : remote)
+ {
+ RtpDescriptionPacketExtension rtpDescription
+ = content.getFirstChildOfType(
+ RtpDescriptionPacketExtension.class);
+ MediaType contentMediaType
+ = MediaType.parseString(rtpDescription.getMedia());
+
+ if (mediaType.equals(contentMediaType))
+ {
+ streamTarget = JingleUtils.extractDefaultTarget(content);
+ break;
+ }
+ }
+ }
+ return streamTarget;
+ }
+
+ /**
+ * Implements {@link TransportManagerJabberImpl#getXmlNamespace()}. Gets the
+ * XML namespace of the Jingle transport implemented by this
+ * TransportManagerJabberImpl.
+ *
+ * @return the XML namespace of the Jingle transport implemented by this
+ * TransportManagerJabberImpl
+ * @see TransportManagerJabberImpl#getXmlNamespace()
+ */
+ public String getXmlNamespace()
+ {
+ return ProtocolProviderServiceJabberImpl.URN_XMPP_JINGLE_RAW_UDP_0;
+ }
+
/**
* Starts transport candidate harvest. This method should complete rapidly
* and, in case of lengthy procedures like STUN/TURN/UPnP candidate harvests
@@ -61,8 +120,8 @@ public void startCandidateHarvest(List theirOffer,
for(ContentPacketExtension content : theirOffer)
{
RtpDescriptionPacketExtension rtpDesc
- = (RtpDescriptionPacketExtension)content
- .getFirstChildOfType(RtpDescriptionPacketExtension.class);
+ = content.getFirstChildOfType(
+ RtpDescriptionPacketExtension.class);
StreamConnector connector = getStreamConnector(
MediaType.parseString( rtpDesc.getMedia()));
@@ -81,7 +140,7 @@ public void startCandidateHarvest(List theirOffer,
cpExt.addChildExtension(ourTransport);
}
- this.cpeList = ourAnswer;
+ this.local = ourAnswer;
}
/**
@@ -91,39 +150,40 @@ public void startCandidateHarvest(List theirOffer,
* harvest would then need to be concluded in the {@link #wrapupHarvest()}
* method which would be called once we absolutely need the candidates.
*
- * @param ourAnswer the content list that should tell us how many stream
+ * @param ourOffer the content list that should tell us how many stream
* connectors we actually need.
*
* @throws OperationFailedException in case we fail allocating ports
*/
- public void startCandidateHarvest(
- List ourAnswer)
+ public void startCandidateHarvest(List ourOffer)
throws OperationFailedException
{
- for(ContentPacketExtension content : ourAnswer)
+ for(ContentPacketExtension content : ourOffer)
{
RtpDescriptionPacketExtension rtpDesc
- = (RtpDescriptionPacketExtension)content
- .getFirstChildOfType(RtpDescriptionPacketExtension.class);
+ = content.getFirstChildOfType(
+ RtpDescriptionPacketExtension.class);
- StreamConnector connector = getStreamConnector(
- MediaType.parseString( rtpDesc.getMedia()));
+ StreamConnector connector
+ = getStreamConnector(
+ MediaType.parseString( rtpDesc.getMedia()));
RawUdpTransportPacketExtension ourTransport
- = createTransport(connector);
+ = createTransport(connector);
- //now add our transport to our answer
+ //now add our transport to our offer
ContentPacketExtension cpExt
- = findContentByName(ourAnswer, content.getName());
+ = findContentByName(ourOffer, content.getName());
cpExt.addChildExtension(ourTransport);
}
- this.cpeList = ourAnswer;
+
+ this.local = ourOffer;
}
/**
- * Creates a raw udp transport element according to the specified stream
- * connector
+ * Creates a raw UDP transport element according to the specified stream
+ * connector.
*
* @param connector the connector that we'd like to describe within the
* transport element.
@@ -138,7 +198,7 @@ private RawUdpTransportPacketExtension createTransport(
= new RawUdpTransportPacketExtension();
// create and add candidates that correspond to the stream connector
- // rtp
+ // RTP
CandidatePacketExtension rtpCand = new CandidatePacketExtension();
rtpCand.setComponent(CandidatePacketExtension.RTP_COMPONENT_ID);
rtpCand.setGeneration(getCurrentGeneration());
@@ -150,7 +210,7 @@ private RawUdpTransportPacketExtension createTransport(
ourTransport.addCandidate(rtpCand);
- // rtcp
+ // RTCP
CandidatePacketExtension rtcpCand = new CandidatePacketExtension();
rtcpCand.setComponent(CandidatePacketExtension.RTCP_COMPONENT_ID);
rtcpCand.setGeneration(getCurrentGeneration());
@@ -167,7 +227,7 @@ private RawUdpTransportPacketExtension createTransport(
/**
* Simply returns the list of local candidates that we gathered during the
- * harvest. This is a raw udp transport manager so there's no real wraping
+ * harvest. This is a raw UDP transport manager so there's no real wrapping
* up to do.
*
* @return the list of local candidates that we gathered during the
@@ -175,29 +235,25 @@ private RawUdpTransportPacketExtension createTransport(
*/
public List wrapupHarvest()
{
- return cpeList;
+ return local;
}
/**
- * Looks through the cpExtList and returns the {@link
- * ContentPacketExtension} with the specified name.
+ * Implements
+ * {@link TransportManagerJabberImpl#startConnectivityEstablishment(Collection)}.
+ * Since this represents a raw UDP transport, performs no connectivity
+ * checks and just remembers the remote counterpart of the negotiation
+ * between the local and the remote peers in order to be able to report the
+ * MediaStreamTargets upon request.
*
- * @param cpExtList the list that we will be searching for a specific
- * content.
- * @param name the name of the content element we are looking for.
- * @return the {@link ContentPacketExtension} with the specified name or
- * null if no such content element exists.
+ * @param remote the collection of ContentPacketExtensions which
+ * represent the remote counterpart of the negotiation between the local and
+ * the remote peers
+ * @see TransportManagerJabberImpl#startConnectivityEstablishment(Collection)
*/
- private ContentPacketExtension findContentByName(
- List cpExtList,
- String name)
+ public void startConnectivityEstablishment(
+ Collection remote)
{
- for(ContentPacketExtension cpExt : cpExtList)
- {
- if(cpExt.getName().equals(name))
- return cpExt;
- }
-
- return null;
+ this.remote = remote;
}
}
diff --git a/src/net/java/sip/communicator/impl/protocol/jabber/TransportManagerJabberImpl.java b/src/net/java/sip/communicator/impl/protocol/jabber/TransportManagerJabberImpl.java
index 1fd8f5179..5d7e5c33f 100644
--- a/src/net/java/sip/communicator/impl/protocol/jabber/TransportManagerJabberImpl.java
+++ b/src/net/java/sip/communicator/impl/protocol/jabber/TransportManagerJabberImpl.java
@@ -10,6 +10,7 @@
import java.util.*;
import net.java.sip.communicator.impl.protocol.jabber.extensions.jingle.*;
+import net.java.sip.communicator.service.neomedia.*;
import net.java.sip.communicator.service.protocol.*;
import net.java.sip.communicator.service.protocol.media.*;
@@ -21,6 +22,7 @@
* it has not yet completed.
*
* @author Emil Ivov
+ * @author Lyubomir Marinov
*/
public abstract class TransportManagerJabberImpl
extends TransportManager
@@ -82,6 +84,27 @@ protected String getNextID()
return Integer.toString(nextID++);
}
+ /**
+ * Gets the MediaStreamTarget to be used as the target of
+ * the MediaStream with a specific MediaType.
+ *
+ * @param mediaType the MediaType of the MediaStream which
+ * is to have its target set to the returned
+ * MediaStreamTarget
+ * @return the MediaStreamTarget to be used as the target
+ * of the MediaStream with the specified MediaType
+ */
+ public abstract MediaStreamTarget getStreamTarget(MediaType mediaType);
+
+ /**
+ * Gets the XML namespace of the Jingle transport implemented by this
+ * TransportManagerJabberImpl.
+ *
+ * @return the XML namespace of the Jingle transport implemented by this
+ * TransportManagerJabberImpl
+ */
+ public abstract String getXmlNamespace();
+
/**
* Returns the generation that our current candidates belong to.
*
@@ -134,7 +157,7 @@ public abstract void startCandidateHarvest(
* @throws OperationFailedException if we fail to allocate a port number.
*/
public abstract void startCandidateHarvest(
- List ourOffer)
+ List ourOffer)
throws OperationFailedException;
/**
@@ -146,4 +169,39 @@ public abstract void startCandidateHarvest(
* a new instance) and that we have updated with transport lists.
*/
public abstract List wrapupHarvest();
+
+ /**
+ * Looks through the cpExtList and returns the {@link
+ * ContentPacketExtension} with the specified name.
+ *
+ * @param cpExtList the list that we will be searching for a specific
+ * content.
+ * @param name the name of the content element we are looking for.
+ * @return the {@link ContentPacketExtension} with the specified name or
+ * null if no such content element exists.
+ */
+ protected ContentPacketExtension findContentByName(
+ List cpExtList,
+ String name)
+ {
+ for(ContentPacketExtension cpExt : cpExtList)
+ {
+ if(cpExt.getName().equals(name))
+ return cpExt;
+ }
+ return null;
+ }
+
+ /**
+ * Starts the connectivity establishment of this
+ * TransportManagerJabberImpl i.e. checks the connectivity between
+ * the local and the remote peers given the remote counterpart of the
+ * negotiation between them.
+ *
+ * @param remote the collection of ContentPacketExtensions which
+ * represents the remote counterpart of the negotiation between the local
+ * and the remote peer
+ */
+ public abstract void startConnectivityEstablishment(
+ Collection remote);
}
diff --git a/src/net/java/sip/communicator/service/protocol/media/CallPeerMediaHandler.java b/src/net/java/sip/communicator/service/protocol/media/CallPeerMediaHandler.java
index b7578309c..8c16603d5 100644
--- a/src/net/java/sip/communicator/service/protocol/media/CallPeerMediaHandler.java
+++ b/src/net/java/sip/communicator/service/protocol/media/CallPeerMediaHandler.java
@@ -173,7 +173,7 @@ public abstract class CallPeerMediaHandler<
* Indicates whether this handler has already started at least one of its
* streams, at least once.
*/
- private boolean isStarted = false;
+ private boolean started = false;
/**
* Contains all dynamic payload type mappings that have been made for this
@@ -387,19 +387,15 @@ public synchronized void close()
protected void closeStream(MediaType type)
{
if( type == MediaType.AUDIO)
- {
setAudioStream(null);
-
- }
else
- {
setVideoStream(null);
- }
- this.getTransportManager().closeStreamConnector(type);
+ getTransportManager().closeStreamConnector(type);
- // clears the zrtp controls used for current call.
+ // Clear the ZRTP controls used for the associated Call.
ZrtpControl zrtpCtrl = zrtpControls.get(type);
+
if (zrtpCtrl != null)
{
zrtpCtrl.cleanup();
@@ -1126,34 +1122,35 @@ protected MediaStream initStream(StreamConnector connector,
List rtpExtensions)
throws OperationFailedException
{
- MediaStream stream = null;
-
- if (device.getMediaType() == MediaType.AUDIO)
- stream = this.audioStream;
- else
- {
- stream = this.videoStream;
- }
+ MediaType mediaType = device.getMediaType();
+ MediaStream stream = getStream(mediaType);
if (stream == null)
{
+ if (logger.isTraceEnabled() && (mediaType != format.getMediaType()))
+ logger.trace("The media types of device and format differ.");
+
// check whether a control already exists
- ZrtpControl control = zrtpControls.get(format.getMediaType());
+ ZrtpControl control = zrtpControls.get(mediaType);
MediaService mediaService
- = ProtocolMediaActivator.getMediaService();
+ = ProtocolMediaActivator.getMediaService();
if(control == null)
stream = mediaService.createMediaStream(connector, device);
else
- stream = mediaService.createMediaStream(
- connector, device, control);
+ {
+ stream
+ = mediaService.createMediaStream(
+ connector, device, control);
+ }
}
else
{
//this is a reinit
}
- return configureStream(
+ return
+ configureStream(
device, format, target, direction, rtpExtensions, stream);
}
@@ -1209,7 +1206,7 @@ protected MediaStream configureStream( MediaDevice device,
if(peer.getCall().isDefaultEncrypted())
{
// we use the audio stream for master stream
- // when using zrtp multistreams
+ // when using ZRTP multistreams.
ZrtpControl zrtpControl = stream.getZrtpControl();
zrtpControl.setZrtpListener(zrtpController);
@@ -1220,9 +1217,9 @@ protected MediaStream configureStream( MediaDevice device,
}
/**
- * Send empty UDP packet to target destination data/control ports
- * in order to open port on NAT or RTP proxy if any. In order to be really
- * efficient, this method should be called after we send our offer or answer
+ * Sends empty UDP packets to target destination data/control ports in order
+ * to open port on NAT or RTP proxy if any. In order to be really efficient,
+ * this method should be called after we send our offer or answer.
*
* @param target MediaStreamTarget
*/
@@ -1536,16 +1533,15 @@ protected DynamicRTPExtensionsRegistry getRtpExtensionsRegistry()
*/
public boolean isStarted()
{
- return isStarted;
+ return started;
}
/**
- * Returns true if this handler has already started at least one
- * of its streams, at least once, and false otherwise. If the
- * handler is already started, this method has no effect.
+ * Starts this CallPeerMediaHandler. If it has already been
+ * started, does nothing.
*
* @throws IllegalStateException if this method is called without this
- * handler having first seen a media description or having generate an
+ * handler having first seen a media description or having generated an
* offer.
*/
public void start()
@@ -1555,21 +1551,22 @@ public void start()
return;
MediaStream stream = getStream(MediaType.AUDIO);
- if ( stream != null && !stream.isStarted()
- && isLocalAudioTransmissionEnabled())
+ if ((stream != null)
+ && !stream.isStarted()
+ && isLocalAudioTransmissionEnabled())
{
stream.start();
}
stream = getStream(MediaType.VIDEO);
- if ( stream != null && !stream.isStarted())
+ if ((stream != null) && !stream.isStarted())
{
stream.start();
// send empty packet to deblock some kind of RTP proxy to let just
// one user sends its video
- if(stream instanceof VideoMediaStream
- && !isLocalVideoTransmissionEnabled())
+ if ((stream instanceof VideoMediaStream)
+ && !isLocalVideoTransmissionEnabled())
{
sendHolePunchPacket(stream.getTarget());
}
@@ -1606,9 +1603,11 @@ protected abstract void throwOperationFailedException( String message,
throws OperationFailedException;
/**
- * Returns the transport manager that is handling our address management.
+ * Gets the TransportManager implementation handling our address
+ * management.
*
- * @return the transport manager that is handling our address management.
+ * @return the TransportManager implementation handling our address
+ * management
*/
public abstract TransportManager getTransportManager();
}
diff --git a/src/net/java/sip/communicator/service/protocol/media/TransportManager.java b/src/net/java/sip/communicator/service/protocol/media/TransportManager.java
index c6986a34a..ede43c69b 100644
--- a/src/net/java/sip/communicator/service/protocol/media/TransportManager.java
+++ b/src/net/java/sip/communicator/service/protocol/media/TransportManager.java
@@ -8,6 +8,7 @@
import java.net.*;
+import net.java.sip.communicator.service.configuration.*;
import net.java.sip.communicator.service.neomedia.*;
import net.java.sip.communicator.service.netaddr.*;
import net.java.sip.communicator.service.protocol.*;
@@ -21,6 +22,7 @@
* or CallPeerJabberImpl
*
* @author Emil Ivov
+ * @author Lyubomir Marinov
*/
public abstract class TransportManager>
{
@@ -28,8 +30,8 @@ public abstract class TransportManager>
* The Logger used by the TransportManager
* class and its instances for logging output.
*/
- private static final Logger logger = Logger
- .getLogger(TransportManager.class.getName());
+ private static final Logger logger
+ = Logger.getLogger(TransportManager.class);
/**
* The minimum port number that we'd like our RTP sockets to bind upon.
@@ -48,21 +50,17 @@ public abstract class TransportManager>
protected static int nextMediaPortToTry = minMediaPort;
/**
- * The RTP/RTCP socket couple that this media handler should use to send
- * and receive audio flows through.
- */
- private StreamConnector audioStreamConnector = null;
-
- /**
- * The RTP/RTCP socket couple that this media handler should use to send
- * and receive video flows through.
+ * The {@link MediaAwareCallPeer} whose traffic we will be taking care of.
*/
- private StreamConnector videoStreamConnector = null;
+ private U callPeer;
/**
- * The {@link MediaAwareCallPeer} whose traffic we will be taking care of.
+ * The RTP/RTCP socket couples that this TransportManager uses to
+ * send and receive media flows through indexed by MediaType
+ * (ordinal).
*/
- private U callPeer;
+ private final StreamConnector[] streamConnectors
+ = new StreamConnector[MediaType.values().length];
/**
* Creates a new instance of this transport manager, binding it to the
@@ -83,8 +81,8 @@ protected TransportManager(U callPeer)
* been initialized for this mediaType yet or in case one
* of its underlying sockets has been closed.
*
- * @param mediaType the MediaType that we'd like to create a connector for.
- *
+ * @param mediaType the MediaType that we'd like to create a
+ * connector for.
* @return this media handler's StreamConnector for the specified
* mediaType.
*
@@ -94,28 +92,18 @@ protected TransportManager(U callPeer)
public StreamConnector getStreamConnector(MediaType mediaType)
throws OperationFailedException
{
- if (mediaType == MediaType.AUDIO)
- {
- if ( audioStreamConnector == null
- || audioStreamConnector.getDataSocket().isClosed()
- || audioStreamConnector.getControlSocket().isClosed())
- {
- audioStreamConnector = createStreamConnector();
- }
+ StreamConnector streamConnector = streamConnectors[mediaType.ordinal()];
- return audioStreamConnector;
- }
- else
+ if ((streamConnector == null)
+ || streamConnector.getDataSocket().isClosed()
+ || streamConnector.getControlSocket().isClosed())
{
- if ( videoStreamConnector == null
- || videoStreamConnector.getDataSocket().isClosed()
- || videoStreamConnector.getControlSocket().isClosed())
- {
- videoStreamConnector = createStreamConnector();
- }
-
- return videoStreamConnector;
+ streamConnectors[mediaType.ordinal()]
+ = streamConnector
+ = createStreamConnector(mediaType);
}
+
+ return streamConnector;
}
/**
@@ -127,31 +115,30 @@ public StreamConnector getStreamConnector(MediaType mediaType)
public void closeStreamConnector(MediaType mediaType)
{
StreamConnector connector
- = (mediaType == MediaType.VIDEO)
- ? videoStreamConnector
- : audioStreamConnector;
-
- if(connector == null)
- return;
+ = streamConnectors[mediaType.ordinal()];
- synchronized(connector)
+ if(connector != null)
{
- connector.getDataSocket().close();
- connector.getControlSocket().close();
- connector = null;
+ synchronized(connector)
+ {
+ connector.getDataSocket().close();
+ connector.getControlSocket().close();
+ streamConnectors[mediaType.ordinal()] = null;
+ }
}
-
}
/**
* Creates a media StreamConnector. The method takes into account
* the minimum and maximum media port boundaries.
*
+ * @param mediaType the MediaType of the stream for which a new
+ * StreamConnector is to be created
* @return a new StreamConnector.
*
* @throws OperationFailedException if we fail binding the the sockets.
*/
- protected StreamConnector createStreamConnector()
+ protected StreamConnector createStreamConnector(MediaType mediaType)
throws OperationFailedException
{
NetworkAddressManagerService nam
@@ -192,7 +179,8 @@ protected StreamConnector createStreamConnector()
{
throw new OperationFailedException(
"Failed to allocate the network ports necessary for the call.",
- OperationFailedException.INTERNAL_ERROR, exc);
+ OperationFailedException.INTERNAL_ERROR,
+ exc);
}
//make sure that next time we don't try to bind on occupied ports
@@ -201,11 +189,7 @@ protected StreamConnector createStreamConnector()
if (nextMediaPortToTry > maxMediaPort -1)// take RTCP into account.
nextMediaPortToTry = minMediaPort;
- //create the RTCP socket
- DefaultStreamConnector connector = new DefaultStreamConnector(
- rtpSocket, rtcpSocket);
-
- return connector;
+ return new DefaultStreamConnector(rtpSocket, rtcpSocket);
}
/**
@@ -219,10 +203,12 @@ protected void initializePortNumbers()
maxMediaPort = 6000;
//then set to anything the user might have specified.
+ ConfigurationService configuration
+ = ProtocolMediaActivator.getConfigurationService();
String minPortNumberStr
- = ProtocolMediaActivator.getConfigurationService()
- .getString(OperationSetBasicTelephony
- .MIN_MEDIA_PORT_NUMBER_PROPERTY_NAME);
+ = configuration.getString(
+ OperationSetBasicTelephony
+ .MIN_MEDIA_PORT_NUMBER_PROPERTY_NAME);
if (minPortNumberStr != null)
{
@@ -239,8 +225,8 @@ protected void initializePortNumbers()
}
String maxPortNumberStr
- = ProtocolMediaActivator.getConfigurationService()
- .getString(OperationSetBasicTelephony
+ = configuration.getString(
+ OperationSetBasicTelephony
.MAX_MEDIA_PORT_NUMBER_PROPERTY_NAME);
if (maxPortNumberStr != null)
@@ -270,7 +256,7 @@ protected void initializePortNumbers()
* descriptions so we already have a specific local address assigned to them
* at the time we get ready to create the c= and o= fields. It is therefore
* better to try and return one of these addresses before trying the net
- * address manager again ang running the slight risk of getting a different
+ * address manager again and running the slight risk of getting a different
* address.
*
* @return an InetAddress that we use in one of the
@@ -278,14 +264,17 @@ protected void initializePortNumbers()
*/
public InetAddress getLastUsedLocalHost()
{
- if (audioStreamConnector != null)
- return audioStreamConnector.getDataSocket().getLocalAddress();
+ for (MediaType mediaType : MediaType.values())
+ {
+ StreamConnector streamConnector
+ = streamConnectors[mediaType.ordinal()];
- if (videoStreamConnector != null)
- return videoStreamConnector.getDataSocket().getLocalAddress();
+ if (streamConnector != null)
+ return streamConnector.getDataSocket().getLocalAddress();
+ }
NetworkAddressManagerService nam
- = ProtocolMediaActivator.getNetworkAddressManagerService();
+ = ProtocolMediaActivator.getNetworkAddressManagerService();
InetAddress intendedDestination = getIntendedDestination(getCallPeer());
return nam.getLocalHost(intendedDestination);