diff options
author | Lyubomir Marinov <lyubomir.marinov@jitsi.org> | 2010-10-19 09:51:19 +0000 |
---|---|---|
committer | Lyubomir Marinov <lyubomir.marinov@jitsi.org> | 2010-10-19 09:51:19 +0000 |
commit | 0bfadb48948260b88bc252695b3c84e5ff6af9f4 (patch) | |
tree | 34d0f2cd003453def98e308b660a162d51a79dea /src/net | |
parent | a496b37ac740dddebf9d4f2efd809b7a252c7def (diff) | |
download | jitsi-0bfadb48948260b88bc252695b3c84e5ff6af9f4.zip jitsi-0bfadb48948260b88bc252695b3c84e5ff6af9f4.tar.gz jitsi-0bfadb48948260b88bc252695b3c84e5ff6af9f4.tar.bz2 |
Commits work in progress on enabling ICE support in Jingle calls:
- Sends transport-info without content child extensions other than transport.
- Does not send candidates in session-accept if they have already been sent in transport-info.
- Does not wait for connectivity establishment to conclude before sending session-accept because the ICE controlling agent determines when the connectivity establishment concludes.
Diffstat (limited to 'src/net')
13 files changed, 653 insertions, 306 deletions
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 01b3def..84949a6 100644 --- a/src/net/java/sip/communicator/impl/protocol/jabber/CallPeerJabberImpl.java +++ b/src/net/java/sip/communicator/impl/protocol/jabber/CallPeerJabberImpl.java @@ -8,6 +8,7 @@ package net.java.sip.communicator.impl.protocol.jabber; import java.util.*; +import org.jivesoftware.smack.packet.*; import org.jivesoftware.smackx.packet.*; import net.java.sip.communicator.impl.protocol.jabber.extensions.jingle.*; @@ -68,7 +69,7 @@ public class CallPeerJabberImpl super(owningCall); this.peerJID = peerAddress; - super.setMediaHandler( new CallPeerMediaHandlerJabberImpl(this) ); + setMediaHandler( new CallPeerMediaHandlerJabberImpl(this) ); } /** @@ -375,15 +376,17 @@ public class CallPeerJabberImpl { this.sessionInitIQ = sessionInitIQ; + CallPeerMediaHandlerJabberImpl mediaHandler = getMediaHandler(); List<ContentPacketExtension> answer = sessionInitIQ.getContentList(); try { - getMediaHandler().processAnswer(answer); + mediaHandler.processAnswer(answer); } catch(Exception exc) { - logger.info("Failed to process a session-accept", exc); + if (logger.isInfoEnabled()) + logger.info("Failed to process a session-accept", exc); //send an error response; JingleIQ errResp = JinglePacketFactory.createSessionTerminate( @@ -400,7 +403,7 @@ public class CallPeerJabberImpl //stop setState(CallPeerState.CONNECTED); - getMediaHandler().start(); + mediaHandler.start(); } /** @@ -533,23 +536,27 @@ public class CallPeerJabberImpl */ private void sendRemoveVideoContent() { + CallPeerMediaHandlerJabberImpl mediaHandler = getMediaHandler(); + ContentPacketExtension content = new ContentPacketExtension(); - ContentPacketExtension remoteContent = getMediaHandler(). - getRemoteContent(MediaType.VIDEO.toString()); - List<ContentPacketExtension> contents = - new ArrayList<ContentPacketExtension>(); + ContentPacketExtension remoteContent + = mediaHandler.getRemoteContent(MediaType.VIDEO.toString()); content.setName(remoteContent.getName()); content.setCreator(remoteContent.getCreator()); content.setSenders(remoteContent.getSenders()); - contents.add(content); - JingleIQ contentIQ = JinglePacketFactory - .createContentRemove(getProtocolProvider().getOurJID(), - this.peerJID, getJingleSID(), contents); + ProtocolProviderServiceJabberImpl protocolProvider + = getProtocolProvider(); + JingleIQ contentIQ + = JinglePacketFactory.createContentRemove( + protocolProvider.getOurJID(), + this.peerJID, + getJingleSID(), + Arrays.asList(content)); - getProtocolProvider().getConnection().sendPacket(contentIQ); - getMediaHandler().removeRemoteContent(remoteContent.getName()); + protocolProvider.getConnection().sendPacket(contentIQ); + mediaHandler.removeContent(remoteContent.getName()); } /** @@ -643,14 +650,16 @@ public class CallPeerJabberImpl */ public void processContentAdd(JingleIQ content) { + CallPeerMediaHandlerJabberImpl mediaHandler = getMediaHandler(); List<ContentPacketExtension> contents = content.getContentList(); - JingleIQ contentIQ = null; Iterable<ContentPacketExtension> answerContents; + JingleIQ contentIQ; try { - getMediaHandler().processOffer(contents); - answerContents = getMediaHandler().generateSessionAccept(); + mediaHandler.processOffer(contents); + answerContents = mediaHandler.generateSessionAccept(); + contentIQ = null; } catch(Exception e) { @@ -677,7 +686,7 @@ public class CallPeerJabberImpl } getProtocolProvider().getConnection().sendPacket(contentIQ); - getMediaHandler().start(); + mediaHandler.start(); } /** @@ -696,7 +705,7 @@ public class CallPeerJabberImpl } catch(Exception exc) { - logger.warn("Exception occurred", exc); + logger.warn("Failed to process a content-accept", exc); //send an error response; JingleIQ errResp = JinglePacketFactory.createSessionTerminate( sessionInitIQ.getTo(), sessionInitIQ.getFrom(), @@ -752,8 +761,21 @@ public class CallPeerJabberImpl { List<ContentPacketExtension> contents = content.getContentList(); - for(ContentPacketExtension ext : contents) - getMediaHandler().removeRemoteContent(ext.getName()); + if (!contents.isEmpty()) + { + CallPeerMediaHandlerJabberImpl mediaHandler = getMediaHandler(); + + for(ContentPacketExtension c : contents) + mediaHandler.removeContent(c.getName()); + + /* + * TODO XEP-0166: Jingle says: If the content-remove results in zero + * content definitions for the session, the entity that receives the + * content-remove SHOULD send a session-terminate action to the + * other party (since a session with no content definitions is + * void). + */ + } } /** @@ -797,4 +819,31 @@ public class CallPeerJabberImpl logger.error("Failed to process an incoming transport-info", ofe); } } + + /** + * Sends local candidate addresses from the local peer to the remote peer + * using the <tt>transport-info</tt> {@link JingleIQ}. + * + * @param contents the local candidate addresses to be sent from the local + * peer to the remote peer using the <tt>transport-info</tt> + * {@link JingleIQ} + */ + void sendTransportInfo(Iterable<ContentPacketExtension> contents) + { + JingleIQ transportInfo = new JingleIQ(); + + for (ContentPacketExtension content : contents) + transportInfo.addContent(content); + + ProtocolProviderServiceJabberImpl protocolProvider + = getProtocolProvider(); + + transportInfo.setAction(JingleAction.TRANSPORT_INFO); + transportInfo.setFrom(protocolProvider.getOurJID()); + transportInfo.setSID(getJingleSID()); + transportInfo.setTo(getAddress()); + transportInfo.setType(IQ.Type.SET); + + protocolProvider.getConnection().sendPacket(transportInfo); + } } 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 05664ba..d5a2ff3 100644 --- a/src/net/java/sip/communicator/impl/protocol/jabber/CallPeerMediaHandlerJabberImpl.java +++ b/src/net/java/sip/communicator/impl/protocol/jabber/CallPeerMediaHandlerJabberImpl.java @@ -6,9 +6,9 @@ */ package net.java.sip.communicator.impl.protocol.jabber; +import java.lang.reflect.*; import java.util.*; -import org.jivesoftware.smack.packet.*; import org.jivesoftware.smackx.packet.*; import net.java.sip.communicator.impl.protocol.jabber.extensions.jingle.*; @@ -376,14 +376,32 @@ public class CallPeerMediaHandlerJabberImpl } /* - * In order to minimize post-pickup delay, establish the connectivity - * prior to ringing. + * In order to minimize post-pickup delay, start establishing the + * connectivity prior to ringing. */ - List<ContentPacketExtension> candidates - = harvestCandidates(offer, answer); - - sendTransportInfo(candidates); - establishConnectivity(offer); + harvestCandidates( + offer, + answer, + new TransportInfoSender() + { + public void sendTransportInfo( + Iterable<ContentPacketExtension> contents) + { + getPeer().sendTransportInfo(contents); + } + }); + /* + * While it may sound like we can completely eliminate the post-pickup + * delay by waiting for the connectivity establishment to finish, it may + * not be possible in all cases. We are the Jingle session responder so, + * in the case of the ICE UDP transport, we are not the controlling ICE + * Agent and we cannot be sure when the controlling ICE Agent will + * perform the nomination. It could, for example, choose to wait for our + * session-accept to perform the nomination which will deadlock us if we + * have chosen to wait for the connectivity establishment to finish + * before we begin ringing and send session-accept. + */ + getTransportManager().startConnectivityEstablishment(offer); } /** @@ -401,7 +419,7 @@ public class CallPeerMediaHandlerJabberImpl { TransportManagerJabberImpl transportManager = getTransportManager(); Iterable<ContentPacketExtension> sessAccept - = transportManager.wrapupConnectivityEstablishment(); + = transportManager.wrapupCandidateHarvest(); CallPeerJabberImpl peer = getPeer(); //user answered an incoming call so we go through whatever content @@ -412,7 +430,7 @@ public class CallPeerMediaHandlerJabberImpl = JingleUtils.getRtpDescription(ourContent); MediaType type = MediaType.parseString(description.getMedia()); - // + // stream connector StreamConnector connector = transportManager.getStreamConnector(type); @@ -420,24 +438,22 @@ public class CallPeerMediaHandlerJabberImpl MediaDevice dev = getDefaultDevice(type); // stream target - ContentPacketExtension theirContent - = this.remoteContentMap.get(ourContent.getName()); - MediaStreamTarget target - = JingleUtils.extractDefaultTarget(theirContent); - RtpDescriptionPacketExtension theirDescription - = JingleUtils.getRtpDescription(theirContent); + MediaStreamTarget target = transportManager.getStreamTarget(type); //stream direction - MediaDirection direction = JingleUtils.getDirection( - ourContent, !peer.isInitiator()); + MediaDirection direction + = JingleUtils.getDirection(ourContent, !peer.isInitiator()); //let's now see what was the format we announced as first and //configure the stream with it. + ContentPacketExtension theirContent + = this.remoteContentMap.get(ourContent.getName()); + RtpDescriptionPacketExtension theirDescription + = JingleUtils.getRtpDescription(theirContent); MediaFormat format = null; - List<PayloadTypePacketExtension> payloadTypes = - theirDescription.getPayloadTypes(); - for(PayloadTypePacketExtension payload : payloadTypes) + for(PayloadTypePacketExtension payload + : theirDescription.getPayloadTypes()) { format = JingleUtils.payloadTypeToMediaFormat( @@ -583,7 +599,7 @@ public class CallPeerMediaHandlerJabberImpl } //now add the transport elements - return harvestCandidates(null, mediaDescs); + return harvestCandidates(null, mediaDescs, null); } /** @@ -678,7 +694,7 @@ public class CallPeerMediaHandlerJabberImpl } //now add the transport elements - return harvestCandidates(null, mediaDescs); + return harvestCandidates(null, mediaDescs, null); } /** @@ -771,52 +787,42 @@ public class CallPeerMediaHandlerJabberImpl } /** - * Remove a media content and stop the corresponding stream. + * Removes a media content with a specific name from the session represented + * by this <tt>CallPeerMediaHandlerJabberImpl</tt> and closes its associated + * media stream. * - * @param name of the Jingle content + * @param name the name of the media content to be removed from this session */ - public void removeLocalContent(String name) + public void removeContent(String name) { - ContentPacketExtension content = localContentMap.remove(name); - - if(content == null) - return; - - RtpDescriptionPacketExtension description - = JingleUtils.getRtpDescription(content); - - String media = description.getMedia(); - - if(media != null ) - { - MediaStream stream = getStream(MediaType.parseString(media)); - stream.stop(); - stream = null; - } + removeContent(localContentMap, name); + removeContent(remoteContentMap, name); + getTransportManager().removeContent(name); } /** - * Remove a media content and stop the corresponding stream. + * Removes a media content with a specific name from the session represented + * by this <tt>CallPeerMediaHandlerJabberImpl</tt> and closes its associated + * media stream. * - * @param name of the Jingle content + * @param contentMap the <tt>Map</tt> in which the specified <tt>name</tt> + * has an association with the media content to be removed + * @param name the name of the media content to be removed from this session */ - public void removeRemoteContent(String name) + private void removeContent( + Map<String, ContentPacketExtension> contentMap, + String name) { - ContentPacketExtension content = remoteContentMap.remove(name); - - if(content == null) - return; - - RtpDescriptionPacketExtension description - = JingleUtils.getRtpDescription(content); - - String media = description.getMedia(); + ContentPacketExtension content = contentMap.remove(name); - if(media != null ) + if (content != null) { - MediaStream stream = getStream(MediaType.parseString(media)); - stream.stop(); - stream = null; + RtpDescriptionPacketExtension description + = JingleUtils.getRtpDescription(content); + String media = description.getMedia(); + + if (media != null) + closeStream(MediaType.parseString(media)); } } @@ -841,16 +847,18 @@ public class CallPeerMediaHandlerJabberImpl { RtpDescriptionPacketExtension description = JingleUtils.getRtpDescription(content); - MediaType mediaType = MediaType.parseString( description.getMedia() ); //stream target - MediaStreamTarget target - = JingleUtils.extractDefaultTarget(content); + TransportManagerJabberImpl transportManager = getTransportManager(); + MediaStreamTarget target = transportManager.getStreamTarget(mediaType); + + if (target == null) + target = JingleUtils.extractDefaultTarget(content); // no target port - try next media description - if(target.getDataAddress().getPort() == 0) + if((target == null) || (target.getDataAddress().getPort() == 0)) { closeStream(mediaType); return; @@ -885,7 +893,7 @@ public class CallPeerMediaHandlerJabberImpl } StreamConnector connector - = getTransportManager().getStreamConnector(mediaType); + = transportManager.getStreamConnector(mediaType); //determine the direction that we need to announce. MediaDirection remoteDirection @@ -929,18 +937,19 @@ public class CallPeerMediaHandlerJabberImpl throws OperationFailedException, IllegalArgumentException { - for (ContentPacketExtension content : answer) - { - remoteContentMap.put(content.getName(), content); - - processContent(content); - } /* * The answer given in session-accept may contain transport-related * information compatible with that carried in transport-info. */ processTransportInfo(answer); + + for (ContentPacketExtension content : answer) + { + remoteContentMap.put(content.getName(), content); + + processContent(content); + } } /** @@ -1149,6 +1158,7 @@ public class CallPeerMediaHandlerJabberImpl * peer to the remote peer. If <tt>remote</tt> is <tt>null</tt>, * <tt>local</tt> represents an offer from the local peer to be sent to the * remote peer + * @param transportInfoSender * @return the media descriptions of the local peer after the local * candidate addresses have been gathered as returned by * {@link TransportManagerJabberImpl#wrapupCandidateHarvest()} @@ -1157,15 +1167,30 @@ public class CallPeerMediaHandlerJabberImpl */ private List<ContentPacketExtension> harvestCandidates( List<ContentPacketExtension> remote, - List<ContentPacketExtension> local) + List<ContentPacketExtension> local, + TransportInfoSender transportInfoSender) throws OperationFailedException { TransportManagerJabberImpl transportManager = getTransportManager(); if (remote == null) + { + /* + * We'll be harvesting candidates in order to make an offer so it + * doesn't make sense to send them in transport-info. + */ + if (transportInfoSender != null) + throw new IllegalArgumentException("transportInfoSender"); + transportManager.startCandidateHarvest(local); + } else - transportManager.startCandidateHarvest(remote, local); + { + transportManager.startCandidateHarvest( + remote, + local, + transportInfoSender); + } /* * XXX Ideally, we wouldn't wrap up that quickly. We need to revisit @@ -1175,104 +1200,73 @@ public class CallPeerMediaHandlerJabberImpl } /** - * Establishes connectivity between the candidate addresses of the local and - * the remote peers. + * Processes the transport-related information provided by the remote + * <tt>peer</tt> in a specific set of <tt>ContentPacketExtension</tt>s. * - * @param remote the media descriptions received from the remote peer which - * contain the remote candidate addresses to establish connectivity with - * @throws OperationFailedException if anything goes wrong while starting or - * wrapping up the establishment of connectivity between the candidate - * addresses of the local and the remote peers + * @param contents the <tt>ContentPacketExtenion</tt>s provided by the + * remote <tt>peer</tt> and containing the transport-related information to + * be processed + * @throws OperationFailedException if anything goes wrong while processing + * the transport-related information provided by the remote <tt>peer</tt> in + * the specified set of <tt>ContentPacketExtension</tt>s */ - private void establishConnectivity(Iterable<ContentPacketExtension> remote) + public void processTransportInfo(Iterable<ContentPacketExtension> contents) throws OperationFailedException { - TransportManagerJabberImpl transportManager = getTransportManager(); - - transportManager.startConnectivityEstablishment(remote); - transportManager.wrapupConnectivityEstablishment(); - for (MediaType mediaType : MediaType.values()) - { - MediaStream stream = getStream(mediaType); - - if (stream != null) - { - stream.setConnector( - transportManager.getStreamConnector(mediaType)); - stream.setTarget(transportManager.getStreamTarget(mediaType)); - } - } + if (getTransportManager().startConnectivityEstablishment(contents)) + wrapupConnectivityEstablishment(); } /** - * Sends local candidate addresses from the local peer to the remote peer - * using the <tt>transport-info</tt> {@link JingleIQ}. Since only ICE UDP - * among the supported Jingle transports is documented to utilize - * <tt>transport-info</tt>, the <tt>sendTransportInfo</tt> method does not - * send <tt>ContentPacketExtension</tt>s with transport other than ICE UDP - * and silently ignores them (i.e. no <tt>transport-info</tt> - * <tt>JingleIQ</tt> is sent in the case of all <tt>candidates</tt> not - * being from the ICE UDP transport). + * Waits for the associated <tt>TransportManagerJabberImpl</tt> to conclude + * any started connectivity establishment and then starts this + * <tt>CallPeerMediaHandler</tt>. * - * @param candidates the local candidate addresses to be sent from the local - * peer to the remote peer using the <tt>transport-info</tt> - * {@link JingleIQ} + * @throws IllegalStateException if no offer or answer has been provided or + * generated earlier */ - private void sendTransportInfo(Iterable<ContentPacketExtension> candidates) + @Override + public void start() + throws IllegalStateException { - JingleIQ transportInfo = new JingleIQ(); - boolean sendTransportInfo = false; - - for (ContentPacketExtension content : candidates) + try { - IceUdpTransportPacketExtension transport - = content.getFirstChildOfType( - IceUdpTransportPacketExtension.class); - - if ((transport != null) - && IceUdpTransportPacketExtension.NAMESPACE.equals( - transport.getNamespace())) - { - List<CandidatePacketExtension> candidateList - = transport.getCandidateList(); - - if ((candidateList != null) && !candidateList.isEmpty()) - { - transportInfo.addContent(content); - sendTransportInfo = true; - } - } + wrapupConnectivityEstablishment(); } - if (sendTransportInfo) + catch (OperationFailedException ofe) { - CallPeerJabberImpl peer = getPeer(); - ProtocolProviderServiceJabberImpl protocolProvider - = peer.getProtocolProvider(); - - transportInfo.setAction(JingleAction.TRANSPORT_INFO); - transportInfo.setFrom(protocolProvider.getOurJID()); - transportInfo.setSID(peer.getJingleSID()); - transportInfo.setTo(peer.getAddress()); - transportInfo.setType(IQ.Type.SET); - - protocolProvider.getConnection().sendPacket(transportInfo); + throw new UndeclaredThrowableException(ofe); } + + super.start(); } /** - * Processes the transport-related information provided by the remote - * <tt>peer</tt> in a specific set of <tt>ContentPacketExtension</tt>s. + * Notifies the associated <tt>TransportManagerJabberImpl</tt> that it + * should conclude any connectivity establishment, waits for it to actually + * do so and sets the <tt>connector</tt>s and <tt>target</tt>s of the + * <tt>MediaStream</tt>s managed by this <tt>CallPeerMediaHandler</tt>. * - * @param contents the <tt>ContentPacketExtenion</tt>s provided by the - * remote <tt>peer</tt> and containing the transport-related information to - * be processed - * @throws OperationFailedException if anything goes wrong while processing - * the transport-related information provided by the remote <tt>peer</tt> in - * the specified set of <tt>ContentPacketExtension</tt>s + * @throws OperationFailedException if anything goes wrong while setting the + * <tt>connector</tt>s and/or <tt>target</tt>s of the <tt>MediaStream</tt>s + * managed by this <tt>CallPeerMediaHandler</tt> */ - public void processTransportInfo(Iterable<ContentPacketExtension> contents) + private void wrapupConnectivityEstablishment() throws OperationFailedException { - establishConnectivity(contents); + TransportManagerJabberImpl transportManager = getTransportManager(); + + transportManager.wrapupConnectivityEstablishment(); + 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 56fc5ed..928aa24 100644 --- a/src/net/java/sip/communicator/impl/protocol/jabber/IceUdpTransportManager.java +++ b/src/net/java/sip/communicator/impl/protocol/jabber/IceUdpTransportManager.java @@ -364,13 +364,30 @@ public class IceUdpTransportManager * transports our peer is using. * @param ourAnswer the content descriptions that we should be adding our * transport lists to (although not necessarily in this very instance). + * @param transportInfoSender the <tt>TransportInfoSender</tt> to be used by + * this <tt>TransportManagerJabberImpl</tt> to send <tt>transport-info</tt> + * <tt>JingleIQ</tt>s from the local peer to the remote peer if this + * <tt>TransportManagerJabberImpl</tt> wishes to utilize + * <tt>transport-info</tt>. Local candidate addresses sent by this + * <tt>TransportManagerJabberImpl</tt> in <tt>transport-info</tt> are + * expected to not be included in the result of + * {@link #wrapupCandidateHarvest()}. * * @throws OperationFailedException if we fail to allocate a port number. + * @see TransportManagerJabberImpl#startCandidateHarvest(List, List, + * TransportInfoSender) */ - public void startCandidateHarvest(List<ContentPacketExtension> theirOffer, - List<ContentPacketExtension> ourAnswer) + public void startCandidateHarvest( + List<ContentPacketExtension> theirOffer, + List<ContentPacketExtension> ourAnswer, + TransportInfoSender transportInfoSender) throws OperationFailedException { + Collection<ContentPacketExtension> transportInfoContents + = (transportInfoSender ==null) + ? null + : new LinkedList<ContentPacketExtension>(); + for(ContentPacketExtension theirContent : theirOffer) { //now add our transport to our answer @@ -386,10 +403,47 @@ public class IceUdpTransportManager RtpDescriptionPacketExtension.class); IceMediaStream stream = createIceStream(rtpDesc.getMedia()); - //we now generate the XMPP code containing the candidates. - ourContent.addChildExtension(JingleUtils.createTransport(stream)); + // Report the gathered candidate addresses. + if (transportInfoSender == null) + { + ourContent.addChildExtension( + JingleUtils.createTransport(stream)); + } + else + { + /* + * The candidates will be sent in transport-info so the + * transport of session-accept just has to be present, not + * populated with candidates. + */ + ourContent.addChildExtension( + new IceUdpTransportPacketExtension()); + + /* + * Create the content to be sent in a transport-info. The + * transport is the only extension to be sent in transport-info + * so the content has the same attributes as in our answer and + * none of its non-transport extensions. + */ + ContentPacketExtension transportInfoContent + = new ContentPacketExtension(); + + for (String name : ourContent.getAttributeNames()) + { + Object value = ourContent.getAttribute(name); + + if (value != null) + transportInfoContent.setAttribute(name, value); + } + transportInfoContent.addChildExtension( + JingleUtils.createTransport(stream)); + transportInfoContents.add(transportInfoContent); + } } + if (transportInfoSender != null) + transportInfoSender.sendTransportInfo(transportInfoContents); + this.cpeList = ourAnswer; } @@ -499,17 +553,18 @@ public class IceUdpTransportManager } /** - * Implements - * {@link TransportManagerJabberImpl#startConnectivityEstablishment(Collection)}. * Starts the connectivity establishment of the associated ICE * <tt>Agent</tt>. * * @param remote the collection of <tt>ContentPacketExtension</tt>s which * represents the remote counterpart of the negotiation between the local * and the remote peers + * @return <tt>true</tt> if connectivity establishment has been started in + * response to the call; otherwise, <tt>false</tt> * @see TransportManagerJabberImpl#startConnectivityEstablishment(Iterable) */ - public void startConnectivityEstablishment( + @Override + public boolean startConnectivityEstablishment( Iterable<ContentPacketExtension> remote) { /* @@ -518,7 +573,7 @@ public class IceUdpTransportManager * has been started. */ if (!IceProcessingState.WAITING.equals(iceAgent.getState())) - return; + return false; int generation = iceAgent.getGeneration(); boolean startConnectivityEstablishment = false; @@ -543,9 +598,29 @@ public class IceUdpTransportManager = transport.getChildExtensionsOfType( CandidatePacketExtension.class); + /* + * If we cannot associate an IceMediaStream with the remote content, + * we will not have anything to add the remote candidates to. + */ RtpDescriptionPacketExtension description = content.getFirstChildOfType( RtpDescriptionPacketExtension.class); + + if ((description == null) && (cpeList != null)) + { + ContentPacketExtension localContent + = findContentByName(cpeList, content.getName()); + + if (localContent != null) + { + description + = localContent.getFirstChildOfType( + RtpDescriptionPacketExtension.class); + } + } + if (description == null) + continue; + IceMediaStream stream = iceAgent.getStream(description.getMedia()); for (CandidatePacketExtension candidate : candidates) @@ -576,22 +651,46 @@ public class IceUdpTransportManager } } if (startConnectivityEstablishment) - iceAgent.startConnectivityEstablishment(); + { + /* + * Once again because the ICE Agent does not support adding + * candidates after the connectivity establishment has been started + * and because multiple transport-info JingleIQs may be used to send + * the whole set of transport candidates from the remote peer to the + * local peer, do not really start the connectivity establishment + * until we have at least one remote candidate per ICE Component. + */ + for (IceMediaStream stream : iceAgent.getStreams()) + { + for (Component component : stream.getComponents()) + { + if (component.getRemoteCandidateCount() < 1) + { + startConnectivityEstablishment = false; + break; + } + } + if (!startConnectivityEstablishment) + break; + } + + if (startConnectivityEstablishment) + { + iceAgent.startConnectivityEstablishment(); + return true; + } + } + return false; } /** - * Implements - * {@link TransportManagerJabberImpl#wrapupConnectivityEstablishment()}. * Waits for the associated ICE <tt>Agent</tt> to finish any started - * connectivity checks and returns the collection of - * <tt>ContentPacketExtension</tt>s which represents the local counterpart - * of the negotiation between the local and the remote peers. + * connectivity checks. * - * @return the collection of <tt>ContentPacketExtension</tt>s which - * represents the local counterpart of the negotiation between the local and - * the remote peer after the end of any started connectivity establishment + * @see TransportManagerJabberImpl#wrapupConnectivityEstablishment() */ - public Iterable<ContentPacketExtension> wrapupConnectivityEstablishment() + @Override + public void wrapupConnectivityEstablishment() { final Object iceProcessingStateSyncRoot = new Object(); PropertyChangeListener stateChangeListener @@ -651,6 +750,71 @@ public class IceUdpTransportManager */ iceAgent.removeStateChangeListener(stateChangeListener); - return cpeList; + /* + * Once we're done establishing connectivity, we shouldn't be sending + * any more candidates because we will not be able to perform + * connectivity checks for them. Besides, they must have been sent in + * transport-info already. + */ + if (cpeList != null) + { + for (ContentPacketExtension content : cpeList) + { + IceUdpTransportPacketExtension transport + = content.getFirstChildOfType( + IceUdpTransportPacketExtension.class); + + if (transport != null) + { + for (CandidatePacketExtension candidate + : transport.getCandidateList()) + transport.removeCandidate(candidate); + + Collection<?> childExtensions + = transport.getChildExtensions(); + + if ((childExtensions == null) || childExtensions.isEmpty()) + { + transport.removeAttribute( + IceUdpTransportPacketExtension.UFRAG_ATTR_NAME); + transport.removeAttribute( + IceUdpTransportPacketExtension.PWD_ATTR_NAME); + } + } + } + } + } + + /** + * Removes a content with a specific name from the transport-related part of + * the session represented by this <tt>TransportManagerJabberImpl</tt> which + * may have been reported through previous calls to the + * <tt>startCandidateHarvest</tt> and + * <tt>startConnectivityEstablishment</tt> methods. + * + * @param name the name of the content to be removed from the + * transport-related part of the session represented by this + * <tt>TransportManagerJabberImpl</tt> + * @see TransportManagerJabberImpl#removeContent(String) + */ + public void removeContent(String name) + { + ContentPacketExtension content = removeContent(cpeList, name); + + if (content != null) + { + RtpDescriptionPacketExtension rtpDescription + = content.getFirstChildOfType( + RtpDescriptionPacketExtension.class); + + if (rtpDescription != null) + { + IceMediaStream stream + = iceAgent.getStream(rtpDescription.getMedia()); + + if (stream != null) + iceAgent.removeStream(stream); + } + } } } 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 f177aaf..24f1b4c 100644 --- a/src/net/java/sip/communicator/impl/protocol/jabber/RawUdpTransportManager.java +++ b/src/net/java/sip/communicator/impl/protocol/jabber/RawUdpTransportManager.java @@ -110,11 +110,23 @@ public class RawUdpTransportManager * transports our peer is using. * @param ourAnswer the content descriptions that we should be adding our * transport lists to (although not necessarily in this very instance). + * @param transportInfoSender the <tt>TransportInfoSender</tt> to be used by + * this <tt>TransportManagerJabberImpl</tt> to send <tt>transport-info</tt> + * <tt>JingleIQ</tt>s from the local peer to the remote peer if this + * <tt>TransportManagerJabberImpl</tt> wishes to utilize + * <tt>transport-info</tt>. Local candidate addresses sent by this + * <tt>TransportManagerJabberImpl</tt> in <tt>transport-info</tt> are + * expected to not be included in the result of + * {@link #wrapupCandidateHarvest()}. * * @throws OperationFailedException if we fail to allocate a port number. + * @see TransportManagerJabberImpl#startCandidateHarvest(List, List, + * TransportInfoSender) */ - public void startCandidateHarvest(List<ContentPacketExtension> theirOffer, - List<ContentPacketExtension> ourAnswer) + public void startCandidateHarvest( + List<ContentPacketExtension> theirOffer, + List<ContentPacketExtension> ourAnswer, + TransportInfoSender transportInfoSender) throws OperationFailedException { for(ContentPacketExtension content : theirOffer) @@ -239,37 +251,22 @@ public class RawUdpTransportManager } /** - * Implements - * {@link TransportManagerJabberImpl#startConnectivityEstablishment(Iterable)}. - * 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 - * <tt>MediaStreamTarget</tt>s upon request. + * Removes a content with a specific name from the transport-related part of + * the session represented by this <tt>TransportManagerJabberImpl</tt> which + * may have been reported through previous calls to the + * <tt>startCandidateHarvest</tt> and + * <tt>startConnectivityEstablishment</tt> methods. * - * @param remote the collection of <tt>ContentPacketExtension</tt>s which - * represent the remote counterpart of the negotiation between the local and - * the remote peers - * @see TransportManagerJabberImpl#startConnectivityEstablishment(Iterable) - */ - public void startConnectivityEstablishment( - Iterable<ContentPacketExtension> remote) - { - this.remote = remote; - } - - /** - * Implements - * {@link TransportManagerJabberImpl#wrapupConnectivityEstablishment()}. - * Since this represents a raw UDP transport i.e. no connectivity checks are - * performed, just returns the local counterpart of the negotiation between - * the local and the remote peers. - * - * @return the local counterpart of the negotiation between the local and - * the remote peers - * @see TransportManagerJabberImpl#wrapupConnectivityEstablishment() + * @param name the name of the content to be removed from the + * transport-related part of the session represented by this + * <tt>TransportManagerJabberImpl</tt> + * @see TransportManagerJabberImpl#removeContent(String) */ - public Iterable<ContentPacketExtension> wrapupConnectivityEstablishment() + public void removeContent(String name) { - return local; + if (local != null) + removeContent(local, name); + if (remote != null) + removeContent(remote, name); } } diff --git a/src/net/java/sip/communicator/impl/protocol/jabber/TransportInfoSender.java b/src/net/java/sip/communicator/impl/protocol/jabber/TransportInfoSender.java new file mode 100644 index 0000000..e40cbc7 --- /dev/null +++ b/src/net/java/sip/communicator/impl/protocol/jabber/TransportInfoSender.java @@ -0,0 +1,30 @@ +/* + * SIP Communicator, the OpenSource Java VoIP and Instant Messaging client. + * + * Distributable under LGPL license. + * See terms of license at gnu.org. + */ +package net.java.sip.communicator.impl.protocol.jabber; + +import net.java.sip.communicator.impl.protocol.jabber.extensions.jingle.*; + +/** + * Represents functionality which allows a <tt>TransportManagerJabberImpl</tt> + * implementation to send <tt>transport-info</tt> {@link JingleIQ}s for the + * purposes of expediting candidate negotiation. + * + * @author Lyubomir Marinov + */ +public interface TransportInfoSender +{ + /** + * Sends specific {@link ContentPacketExtension}s in a + * <tt>transport-info</tt> {@link JingleIQ} from the local peer to the + * remote peer. + * + * @param contents the <tt>ContentPacketExtension</tt>s to be sent in a + * <tt>transport-info</tt> <tt>JingleIQ</tt> from the local peer to the + * remote peer + */ + public void sendTransportInfo(Iterable<ContentPacketExtension> contents); +} 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 a872760..f680bbe 100644 --- a/src/net/java/sip/communicator/impl/protocol/jabber/TransportManagerJabberImpl.java +++ b/src/net/java/sip/communicator/impl/protocol/jabber/TransportManagerJabberImpl.java @@ -18,8 +18,8 @@ import net.java.sip.communicator.service.protocol.media.*; * <tt>TransportManager</tt>s gather local candidates for incoming and outgoing * calls. Their work starts by calling a start method which, using the remote * peer's session description, would start the harvest. Calling a second wrapup - * method would deliver the candidate harvest, possibly after blocking if - * it has not yet completed. + * method would deliver the candidate harvest, possibly after blocking if it has + * not yet completed. * * @author Emil Ivov * @author Lyubomir Marinov @@ -136,12 +136,21 @@ public abstract class TransportManagerJabberImpl * transports our peer is using. * @param ourAnswer the content descriptions that we should be adding our * transport lists to (although not necessarily in this very instance). + * @param transportInfoSender the <tt>TransportInfoSender</tt> to be used by + * this <tt>TransportManagerJabberImpl</tt> to send <tt>transport-info</tt> + * <tt>JingleIQ</tt>s from the local peer to the remote peer if this + * <tt>TransportManagerJabberImpl</tt> wishes to utilize + * <tt>transport-info</tt>. Local candidate addresses sent by this + * <tt>TransportManagerJabberImpl</tt> in <tt>transport-info</tt> are + * expected to not be included in the result of + * {@link #wrapupCandidateHarvest()}. * * @throws OperationFailedException if we fail to allocate a port number. */ public abstract void startCandidateHarvest( - List<ContentPacketExtension> theirOffer, - List<ContentPacketExtension> ourAnswer) + List<ContentPacketExtension> theirOffer, + List<ContentPacketExtension> ourAnswer, + TransportInfoSender transportInfoSender) throws OperationFailedException; /** @@ -180,9 +189,9 @@ public abstract class TransportManagerJabberImpl * @return the {@link ContentPacketExtension} with the specified name or * <tt>null</tt> if no such content element exists. */ - protected ContentPacketExtension findContentByName( - List<ContentPacketExtension> cpExtList, - String name) + protected static ContentPacketExtension findContentByName( + Iterable<ContentPacketExtension> cpExtList, + String name) { for(ContentPacketExtension cpExt : cpExtList) { @@ -201,18 +210,85 @@ public abstract class TransportManagerJabberImpl * @param remote the collection of <tt>ContentPacketExtension</tt>s which * represents the remote counterpart of the negotiation between the local * and the remote peer + * @return <tt>true</tt> if connectivity establishment has been started in + * response to the call; otherwise, <tt>false</tt>. + * <tt>TransportManagerJabberImpl</tt> implementations which do not perform + * connectivity checks (e.g. raw UDP) should return <tt>true</tt>. The + * default implementation does not perform connectivity checks and always + * returns <tt>true</tt>. */ - public abstract void startConnectivityEstablishment( - Iterable<ContentPacketExtension> remote); + public boolean startConnectivityEstablishment( + Iterable<ContentPacketExtension> remote) + { + return true; + } /** * Notifies this <tt>TransportManagerJabberImpl</tt> that it should conclude - * any started connectivity establishment and return (at least) the - * transport-related media descriptions of the local peer. + * any started connectivity establishment. + */ + public void wrapupConnectivityEstablishment() + { + } + + /** + * Removes a content with a specific name from the transport-related part of + * the session represented by this <tt>TransportManagerJabberImpl</tt> which + * may have been reported through previous calls to the + * <tt>startCandidateHarvest</tt> and + * <tt>startConnectivityEstablishment</tt> methods. + * <p> + * <b>Note</b>: Because <tt>TransportManager</tt> deals with + * <tt>MediaType</tt>s, not content names and + * <tt>TransportManagerJabberImpl</tt> does not implement translating from + * content name to <tt>MediaType</tt>, implementers are expected to call + * {@link TransportManager#closeStreamConnector(MediaType)}. + * </p> + * + * @param name the name of the content to be removed from the + * transport-related part of the session represented by this + * <tt>TransportManagerJabberImpl</tt> + */ + public abstract void removeContent(String name); + + /** + * Removes a content with a specific name from a specific collection of + * contents and closes any associated <tt>StreamConnector</tt>. * - * @return the transport-related media descriptions of the local peer after - * the end of the connectivity establishment + * @param contents the collection of contents to remove the content with the + * specified name from + * @param name the name of the content to remove + * @return the removed <tt>ContentPacketExtension</tt> if any; otherwise, + * <tt>null</tt> */ - public abstract Iterable<ContentPacketExtension> - wrapupConnectivityEstablishment(); + protected ContentPacketExtension removeContent( + Iterable<ContentPacketExtension> contents, + String name) + { + Iterator<ContentPacketExtension> contentIter = contents.iterator(); + + while (contentIter.hasNext()) + { + ContentPacketExtension content = contentIter.next(); + + if (name.equals(content.getName())) + { + contentIter.remove(); + + // closeStreamConnector + RtpDescriptionPacketExtension rtpDescription + = content.getFirstChildOfType( + RtpDescriptionPacketExtension.class); + + if (rtpDescription != null) + { + closeStreamConnector( + MediaType.parseString(rtpDescription.getMedia())); + } + + return content; + } + } + return null; + } } diff --git a/src/net/java/sip/communicator/impl/protocol/jabber/extensions/AbstractPacketExtension.java b/src/net/java/sip/communicator/impl/protocol/jabber/extensions/AbstractPacketExtension.java index 32271ff..4bb1521 100644 --- a/src/net/java/sip/communicator/impl/protocol/jabber/extensions/AbstractPacketExtension.java +++ b/src/net/java/sip/communicator/impl/protocol/jabber/extensions/AbstractPacketExtension.java @@ -20,6 +20,7 @@ import org.jivesoftware.smack.packet.*; * handling instead. * * @author Emil Ivov + * @author Lyubomir Marinov */ public abstract class AbstractPacketExtension implements PacketExtension @@ -95,42 +96,61 @@ public abstract class AbstractPacketExtension */ public String toXML() { - StringBuilder bldr = new StringBuilder("<" + getElementName() + " "); + StringBuilder bldr = new StringBuilder(); + + bldr.append("<").append(getElementName()).append(" "); if(getNamespace() != null) - bldr.append("xmlns='" + getNamespace() + "'"); + bldr.append("xmlns='").append(getNamespace()).append("'"); //add the rest of the attributes if any for(Map.Entry<String, String> entry : attributes.entrySet()) { - bldr.append(" " + entry.getKey() + "='" + entry.getValue() + "'"); + bldr.append(" ") + .append(entry.getKey()) + .append("='") + .append(entry.getValue()) + .append("'"); } //add child elements if any List<? extends PacketExtension> childElements = getChildExtensions(); - synchronized(childElements) + String text = getText(); + + if (childElements == null) { - if( (childElements == null || childElements.size() == 0) - && (getText() == null || getText().length() == 0)) + if ((text == null) || (text.length() == 0)) { bldr.append("/>"); return bldr.toString(); } else + bldr.append('>'); + } + else + { + synchronized(childElements) { - bldr.append(">"); - for(PacketExtension packExt : childElements) + if (childElements.isEmpty() + && ((text == null) || (text.length() == 0))) + { + bldr.append("/>"); + return bldr.toString(); + } + else { - bldr.append(packExt.toXML()); + bldr.append(">"); + for(PacketExtension packExt : childElements) + bldr.append(packExt.toXML()); } } } //text content if any - if(getText() != null && getText().trim().length() > 0) - bldr.append(getText()); + if((text != null) && (text.trim().length() > 0)) + bldr.append(text); - bldr.append("</"+getElementName()+">"); + bldr.append("</").append(getElementName()).append(">"); return bldr.toString(); } @@ -246,13 +266,28 @@ public abstract class AbstractPacketExtension */ public int getAttributeAsInt(String attribute) { + return getAttributeAsInt(attribute, -1); + } + + /** + * Returns the <tt>int</tt> value of the attribute with the specified + * <tt>name</tt>. + * + * @param attribute the name of the attribute that we'd like to retrieve + * @param defaultValue the <tt>int</tt> to be returned as the value of the + * specified attribute if no such attribute is currently registered with + * this extension + * @return the <tt>int</tt> value of the specified <tt>attribute</tt> or + * <tt>defaultValue</tt> if no such attribute is currently registered with + * this extension + */ + public int getAttributeAsInt(String attribute, int defaultValue) + { synchronized(attributes) { - String attributeVal = getAttributeAsString(attribute); + String value = getAttributeAsString(attribute); - return attributeVal == null - ? -1 - : Integer.parseInt(attributeVal); + return (value == null) ? defaultValue : Integer.parseInt(value); } } @@ -292,6 +327,21 @@ public abstract class AbstractPacketExtension } /** + * Gets the names of the attributes which currently have associated values + * in this extension. + * + * @return the names of the attributes which currently have associated + * values in this extension + */ + public List<String> getAttributeNames() + { + synchronized (attributes) + { + return new ArrayList<String>(attributes.keySet()); + } + } + + /** * Specifies the text content of this extension. * * @param text the text content of this extension. diff --git a/src/net/java/sip/communicator/impl/protocol/jabber/extensions/jingle/ExtmapPacketExtension.java b/src/net/java/sip/communicator/impl/protocol/jabber/extensions/jingle/ExtmapPacketExtension.java index 5b3e568..2a728a7 100644 --- a/src/net/java/sip/communicator/impl/protocol/jabber/extensions/jingle/ExtmapPacketExtension.java +++ b/src/net/java/sip/communicator/impl/protocol/jabber/extensions/jingle/ExtmapPacketExtension.java @@ -133,5 +133,4 @@ public class ExtmapPacketExtension { return super.getAttributeAsString(ATTRIBUTES_ATTR_NAME); } - } diff --git a/src/net/java/sip/communicator/impl/protocol/jabber/extensions/jingle/IceUdpTransportPacketExtension.java b/src/net/java/sip/communicator/impl/protocol/jabber/extensions/jingle/IceUdpTransportPacketExtension.java index 9c9f663..b98960c 100644 --- a/src/net/java/sip/communicator/impl/protocol/jabber/extensions/jingle/IceUdpTransportPacketExtension.java +++ b/src/net/java/sip/communicator/impl/protocol/jabber/extensions/jingle/IceUdpTransportPacketExtension.java @@ -16,6 +16,7 @@ import net.java.sip.communicator.impl.protocol.jabber.extensions.*; * An {@link AbstractPacketExtension} implementation for transport elements. * * @author Emil Ivov + * @author Lyubomir Marinov */ public class IceUdpTransportPacketExtension extends AbstractPacketExtension { @@ -158,7 +159,24 @@ public class IceUdpTransportPacketExtension extends AbstractPacketExtension { synchronized(candidateList) { - this.candidateList.add(candidate); + candidateList.add(candidate); + } + } + + /** + * Removes <tt>candidate</tt> from the list of + * {@link CandidatePacketExtension}s registered with this transport. + * + * @param candidate the <tt>CandidatePacketExtension</tt> to remove from + * this transport element + * @return <tt>true</tt> if the list of <tt>CandidatePacketExtension</tt>s + * registered with this transport contained the specified <tt>candidate</tt> + */ + public boolean removeCandidate(CandidatePacketExtension candidate) + { + synchronized (candidateList) + { + return candidateList.remove(candidate); } } @@ -215,7 +233,4 @@ public class IceUdpTransportPacketExtension extends AbstractPacketExtension else if(childExtension instanceof CandidatePacketExtension) addCandidate((CandidatePacketExtension) childExtension); } - - - } diff --git a/src/net/java/sip/communicator/impl/protocol/jabber/extensions/jingle/JinglePacketFactory.java b/src/net/java/sip/communicator/impl/protocol/jabber/extensions/jingle/JinglePacketFactory.java index a728030..b3eb0a3 100644 --- a/src/net/java/sip/communicator/impl/protocol/jabber/extensions/jingle/JinglePacketFactory.java +++ b/src/net/java/sip/communicator/impl/protocol/jabber/extensions/jingle/JinglePacketFactory.java @@ -394,10 +394,10 @@ public class JinglePacketFactory * packet. */ public static JingleIQ createContentRemove( - String from, - String to, - String sid, - List<ContentPacketExtension> contentList) + String from, + String to, + String sid, + Iterable<ContentPacketExtension> contentList) { JingleIQ contentRemove = new JingleIQ(); @@ -410,9 +410,7 @@ public class JinglePacketFactory contentRemove.setAction(JingleAction.CONTENT_REMOVE); for(ContentPacketExtension content : contentList) - { contentRemove.addContent(content); - } return contentRemove; } diff --git a/src/net/java/sip/communicator/impl/protocol/jabber/extensions/jingle/PayloadTypePacketExtension.java b/src/net/java/sip/communicator/impl/protocol/jabber/extensions/jingle/PayloadTypePacketExtension.java index 4612eb1..e76060c 100644 --- a/src/net/java/sip/communicator/impl/protocol/jabber/extensions/jingle/PayloadTypePacketExtension.java +++ b/src/net/java/sip/communicator/impl/protocol/jabber/extensions/jingle/PayloadTypePacketExtension.java @@ -79,7 +79,11 @@ public class PayloadTypePacketExtension extends AbstractPacketExtension */ public int getChannels() { - return getAttributeAsInt(CHANNELS_ATTR_NAME); + /* + * XEP-0167: Jingle RTP Sessions says: if omitted, it MUST be assumed + * to contain one channel. + */ + return getAttributeAsInt(CHANNELS_ATTR_NAME, 1); } /** diff --git a/src/net/java/sip/communicator/impl/protocol/jabber/extensions/jingle/RawUdpTransportPacketExtension.java b/src/net/java/sip/communicator/impl/protocol/jabber/extensions/jingle/RawUdpTransportPacketExtension.java index 9ffd35b..a81c0b7 100644 --- a/src/net/java/sip/communicator/impl/protocol/jabber/extensions/jingle/RawUdpTransportPacketExtension.java +++ b/src/net/java/sip/communicator/impl/protocol/jabber/extensions/jingle/RawUdpTransportPacketExtension.java @@ -16,6 +16,7 @@ import net.java.sip.communicator.impl.protocol.jabber.extensions.*; * An {@link AbstractPacketExtension} implementation for transport elements. * * @author Emil Ivov + * @author Lyubomir Marinov */ public class RawUdpTransportPacketExtension extends IceUdpTransportPacketExtension @@ -31,14 +32,6 @@ public class RawUdpTransportPacketExtension public static final String ELEMENT_NAME = "transport"; /** - * A list of one or more candidates representing each of the initiator's - * higher-priority transport candidates as determined in accordance with - * the ICE methodology. - */ - private final List<CandidatePacketExtension> candidateList - = new ArrayList<CandidatePacketExtension>(); - - /** * Creates a new {@link RawUdpTransportPacketExtension} instance. */ public RawUdpTransportPacketExtension() @@ -54,33 +47,6 @@ public class RawUdpTransportPacketExtension @Override public List<? extends PacketExtension> getChildExtensions() { - return candidateList; - } - - /** - * Adds <tt>candidate</tt> to the list of {@link CandidatePacketExtension}s - * registered with this transport. - * - * @param candidate the new {@link CandidatePacketExtension} to add to this - * transport element. - */ - public void addCandidate(CandidatePacketExtension candidate) - { - this.candidateList.add(candidate); - } - - /** - * Returns the list of {@link CandidatePacketExtension}s currently - * registered with this transport. - * - * @return the list of {@link CandidatePacketExtension}s currently - * registered with this transport. - */ - public List<CandidatePacketExtension> getCandidateList() - { - synchronized(candidateList) - { - return new ArrayList<CandidatePacketExtension>(this.candidateList); - } + return getCandidateList(); } } diff --git a/src/net/java/sip/communicator/impl/protocol/jabber/jinglesdp/JingleUtils.java b/src/net/java/sip/communicator/impl/protocol/jabber/jinglesdp/JingleUtils.java index bef4beb..bbb21b0 100644 --- a/src/net/java/sip/communicator/impl/protocol/jabber/jinglesdp/JingleUtils.java +++ b/src/net/java/sip/communicator/impl/protocol/jabber/jinglesdp/JingleUtils.java @@ -116,19 +116,24 @@ public class JingleUtils DynamicPayloadTypeRegistry ptRegistry) { byte pt = (byte)payloadType.getID(); - List<ParameterPacketExtension> params = payloadType.getParameters(); //convert params to a name:value map + List<ParameterPacketExtension> params = payloadType.getParameters(); Map<String, String> paramsMap = new HashMap<String, String>(); for(ParameterPacketExtension param : params) paramsMap.put(param.getName(), param.getValue()); //now create the format. - MediaFormat format = JabberActivator.getMediaService() - .getFormatFactory().createMediaFormat( - pt, payloadType.getName(), (double)payloadType.getClockrate(), - payloadType.getChannels(), paramsMap, null); + MediaFormat format + = JabberActivator.getMediaService().getFormatFactory() + .createMediaFormat( + pt, + payloadType.getName(), + (double)payloadType.getClockrate(), + payloadType.getChannels(), + paramsMap, + null); //we don't seem to know anything about this format if(format == null) @@ -527,8 +532,8 @@ public class JingleUtils for(Component component : stream.getComponents()) { - for(Candidate cand : component.getLocalCandidates()) - trans.addCandidate(createCandidate(cand)); + for(Candidate candidate : component.getLocalCandidates()) + trans.addCandidate(createCandidate(candidate)); } return trans; |