diff options
Diffstat (limited to 'src/net/java')
25 files changed, 1008 insertions, 407 deletions
diff --git a/src/net/java/sip/communicator/impl/gui/main/call/CallPanel.java b/src/net/java/sip/communicator/impl/gui/main/call/CallPanel.java index f1d3466..e79b01b 100644 --- a/src/net/java/sip/communicator/impl/gui/main/call/CallPanel.java +++ b/src/net/java/sip/communicator/impl/gui/main/call/CallPanel.java @@ -320,7 +320,7 @@ public class CallPanel this.callConference = callConference; this.callWindow = callWindow; - uiVideoHandler = new UIVideoHandler2(callConference); + uiVideoHandler = new UIVideoHandler2(this.callConference); callDurationTimer = new Timer( @@ -345,9 +345,10 @@ public class CallPanel * Adds the listeners which will observe the model and will trigger the * updates of this view from it. */ - callConference.addCallChangeListener(callConferenceListener); - callConference.addCallPeerConferenceListener(callConferenceListener); - callConference.addPropertyChangeListener(callConferenceListener); + this.callConference.addCallChangeListener(callConferenceListener); + this.callConference.addCallPeerConferenceListener( + callConferenceListener); + this.callConference.addPropertyChangeListener(callConferenceListener); uiVideoHandler.addObserver(uiVideoHandlerObserver); updateViewFromModel(); @@ -400,12 +401,16 @@ public class CallPanel else if (buttonName.equals(CONFERENCE_BUTTON)) { ConferenceInviteDialog inviteDialog; + if (callConference.isJitsiVideoBridge()) - inviteDialog = new ConferenceInviteDialog( - callConference, - callConference.getCalls() - .get(0).getProtocolProvider(), - true); + { + inviteDialog + = new ConferenceInviteDialog( + callConference, + callConference.getCalls().get(0) + .getProtocolProvider(), + true); + } else inviteDialog = new ConferenceInviteDialog(callConference); @@ -437,18 +442,11 @@ public class CallPanel { if (callInfoFrame == null) { - this.callInfoFrame = new CallInfoFrame(callConference); - this.addCallTitleListener(callInfoFrame); - } - - if (callInfoFrame.hasCallInfo()) - { - callInfoFrame.setVisible(!callInfoFrame.isVisible()); - } - else - { - callInfoFrame.setVisible(false); + callInfoFrame = new CallInfoFrame(callConference); + addCallTitleListener(callInfoFrame); } + callInfoFrame.setVisible( + callInfoFrame.hasCallInfo() && !callInfoFrame.isVisible()); } } diff --git a/src/net/java/sip/communicator/impl/gui/main/call/OneToOneCallPeerPanel.java b/src/net/java/sip/communicator/impl/gui/main/call/OneToOneCallPeerPanel.java index d04411b..4897908 100644 --- a/src/net/java/sip/communicator/impl/gui/main/call/OneToOneCallPeerPanel.java +++ b/src/net/java/sip/communicator/impl/gui/main/call/OneToOneCallPeerPanel.java @@ -292,14 +292,17 @@ public class OneToOneCallPeerPanel = new TransparentPanel(new BorderLayout(5, 0)); TransparentPanel remoteLevelPanel = new TransparentPanel(new BorderLayout(5, 0)); - - localLevel = new InputVolumeControlButton( - callPeer.getCall(), - ImageLoader.MICROPHONE, - ImageLoader.MUTE_BUTTON, - false, false, false); - remoteLevel = new OutputVolumeControlButton( - ImageLoader.HEADPHONE, false, false).getComponent(); + Call call = callPeer.getCall(); + + localLevel + = new InputVolumeControlButton( + call, + ImageLoader.MICROPHONE, + ImageLoader.MUTE_BUTTON, + false, false, false); + remoteLevel + = new OutputVolumeControlButton(ImageLoader.HEADPHONE, false, false) + .getComponent(); final SoundLevelIndicator localLevelIndicator = new SoundLevelIndicator( @@ -339,7 +342,7 @@ public class OneToOneCallPeerPanel + "DISABLE_SOUND_LEVEL_INDICATORS", false)) { - this.callPeer.addStreamSoundLevelListener( + callPeer.addStreamSoundLevelListener( new SoundLevelListener() { public void soundLevelChanged(Object source, int level) @@ -347,15 +350,26 @@ public class OneToOneCallPeerPanel remoteLevelIndicator.updateSoundLevel(level); } }); - - this.callPeer.getCall().addLocalUserSoundLevelListener( - new SoundLevelListener() - { - public void soundLevelChanged(Object source, int level) + /* + * By the time the UI gets to be initialized, the callPeer may have + * been removed from its Call. As far as the UI is concerned, the + * callPeer will never have a Call again and there will be no audio + * levels to display anyway so there is no point in throwing a + * NullPointerException here. + */ + if (call != null) + { + call.addLocalUserSoundLevelListener( + new SoundLevelListener() { - localLevelIndicator.updateSoundLevel(level); - } - }); + public void soundLevelChanged( + Object source, + int level) + { + localLevelIndicator.updateSoundLevel(level); + } + }); + } } } @@ -502,11 +516,8 @@ public class OneToOneCallPeerPanel CallPeerSecurityStatusEvent securityEvent = callPeer.getCurrentSecuritySettings(); - if (securityEvent != null - && securityEvent instanceof CallPeerSecurityOnEvent) - { + if (securityEvent instanceof CallPeerSecurityOnEvent) securityOn((CallPeerSecurityOnEvent) securityEvent); - } } /** @@ -733,8 +744,10 @@ public class OneToOneCallPeerPanel SrtpControl srtpControl = evt.getSecurityController(); if ((srtpControl.requiresSecureSignalingTransport() - && callPeer.getProtocolProvider().isSignalingTransportSecure()) - || !srtpControl.requiresSecureSignalingTransport()) + && callPeer + .getProtocolProvider() + .isSignalingTransportSecure()) + || !srtpControl.requiresSecureSignalingTransport()) { if (srtpControl instanceof ZrtpControl) { diff --git a/src/net/java/sip/communicator/impl/protocol/jabber/AbstractCallPeerMediaHandlerJabberGTalkImpl.java b/src/net/java/sip/communicator/impl/protocol/jabber/AbstractCallPeerMediaHandlerJabberGTalkImpl.java index 8dfee62..0e535b0 100644 --- a/src/net/java/sip/communicator/impl/protocol/jabber/AbstractCallPeerMediaHandlerJabberGTalkImpl.java +++ b/src/net/java/sip/communicator/impl/protocol/jabber/AbstractCallPeerMediaHandlerJabberGTalkImpl.java @@ -245,26 +245,23 @@ public abstract class AbstractCallPeerMediaHandlerJabberGTalkImpl { List<CryptoPacketExtension> cryptoPacketExtensions = encryptionPacketExtension.getCryptoList(); - Vector<SrtpCryptoAttribute> peerAttributes - = new Vector<SrtpCryptoAttribute>(cryptoPacketExtensions.size()); + List<SrtpCryptoAttribute> peerAttributes + = new ArrayList<SrtpCryptoAttribute>(cryptoPacketExtensions.size()); for (CryptoPacketExtension cpe : cryptoPacketExtensions) peerAttributes.add(cpe.toSrtpCryptoAttribute()); - if (peerAttributes == null) - return null; - - if (isInitiator) - return sDesControl.initiatorSelectAttribute(peerAttributes); - else - return sDesControl.responderSelectAttribute(peerAttributes); + return + isInitiator + ? sDesControl.initiatorSelectAttribute(peerAttributes) + : sDesControl.responderSelectAttribute(peerAttributes); } /** * Returns if the remote peer supports ZRTP. * * @param encryptionPacketExtension The ENCRYPTION element received from - * the remote peer. This may contain the ZRTP acket element for the remote + * the remote peer. This may contain the ZRTP packet element for the remote * peer. * * @return True if the remote peer supports ZRTP. False, otherwise. @@ -513,15 +510,16 @@ public abstract class AbstractCallPeerMediaHandlerJabberGTalkImpl RtpDescriptionPacketExtension remoteDescription) { // Sets ZRTP or SDES, depending on the preferences for this account. - List<String> preferredEncryptionProtocols = getPeer() - .getProtocolProvider() - .getAccountID() - .getSortedEnabledEncryptionProtocolList(); + List<String> preferredEncryptionProtocols + = getPeer() + .getProtocolProvider() + .getAccountID() + .getSortedEnabledEncryptionProtocolList(); - for(int i = 0; i < preferredEncryptionProtocols.size(); ++i) + for(String preferredEncryptionProtocol : preferredEncryptionProtocols) { // ZRTP - if(preferredEncryptionProtocols.get(i).equals( + if(preferredEncryptionProtocol.equals( ProtocolProviderFactory.ENCRYPTION_PROTOCOL + ".ZRTP")) { boolean isZRTPAddedToDescription @@ -529,18 +527,19 @@ public abstract class AbstractCallPeerMediaHandlerJabberGTalkImpl mediaType, localDescription, remoteDescription); + if(isZRTPAddedToDescription) { addZRTPAdvertisedEncryptions( false, remoteDescription, mediaType); - // Stops once an encryption advertisement has been choosen. + // Stops once an encryption advertisement has been chosen. return; } } // SDES - else if(preferredEncryptionProtocols.get(i).equals( + else if(preferredEncryptionProtocol.equals( ProtocolProviderFactory.ENCRYPTION_PROTOCOL + ".SDES")) { addSDESAdvertisedEncryptions( @@ -552,7 +551,7 @@ public abstract class AbstractCallPeerMediaHandlerJabberGTalkImpl localDescription, remoteDescription)) { - // Stops once an encryption advertisement has been choosen. + // Stops once an encryption advertisement has been chosen. return; } } 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 213bf29..a7995f5 100644 --- a/src/net/java/sip/communicator/impl/protocol/jabber/CallJabberImpl.java +++ b/src/net/java/sip/communicator/impl/protocol/jabber/CallJabberImpl.java @@ -605,6 +605,88 @@ public class CallJabberImpl } /** + * Notifies this instance that a specific <tt>CobriConferenceIQ</tt> has + * been received. + * + * @param conferenceIQ the <tt>CobriConferenceIQ</tt> which has been + * received + * @return <tt>true</tt> if the specified <tt>conferenceIQ</tt> was + * processed by this instance and no further processing is to be performed + * by other possible processors of <tt>CobriConferenceIQ</tt>s; otherwise, + * <tt>false</tt>. Because a <tt>CobriConferenceIQ</tt> request sent from + * the Jitsi VideoBridge server to the application as its client concerns a + * specific <tt>CallJabberImpl</tt> implementation, no further processing by + * other <tt>CallJabberImpl</tt> instances is necessary once the + * <tt>CobriConferenceIQ</tt> is processed by the associated + * <tt>CallJabberImpl</tt> instance. + */ + boolean processCobriConferenceIQ(CobriConferenceIQ conferenceIQ) + { + if (cobri == null) + { + /* + * This instance has not set up any conference using the Jitsi + * VideoBridge server-side technology yet so it cannot be bothered + * with related requests. + */ + return false; + } + else if (conferenceIQ.getID().equals(cobri.getID())) + { + /* + * Remove the local Channels (from the specified conferenceIQ) i.e. + * the Channels on which the local peer/user is sending to the Jitsi + * VideoBridge server because they concern this Call only and not + * its CallPeers. + */ + for (MediaType mediaType : MediaType.values()) + { + String contentName = mediaType.toString(); + CobriConferenceIQ.Content content + = conferenceIQ.getContent(contentName); + + if (content != null) + { + CobriConferenceIQ.Content thisContent + = cobri.getContent(contentName); + + if ((thisContent != null) + && (thisContent.getChannelCount() > 0)) + { + CobriConferenceIQ.Channel thisChannel + = thisContent.getChannel(0); + CobriConferenceIQ.Channel channel + = content.getChannel(thisChannel.getID()); + + if (channel != null) + content.removeChannel(channel); + } + } + } + + for (CallPeerJabberImpl callPeer : getCallPeerList()) + callPeer.processCobriConferenceIQ(conferenceIQ); + + /* + * We have removed the local Channels from the specified + * conferenceIQ. Consequently, it is no longer the same and fit for + * processing by other CallJabberImpl instances. + */ + return true; + } + else + { + /* + * This instance has set up a conference using the Jitsi VideoBridge + * server-side technology but it is not the one referred to by the + * specified conferenceIQ i.e. the specified conferenceIQ does not + * concern this instance. + */ + return false; + } + } + + /** * Creates a new call peer and sends a RINGING response. * * @param jingleIQ the {@link JingleIQ} that created the session. 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 4ec4dd0..b2632fc 100644 --- a/src/net/java/sip/communicator/impl/protocol/jabber/CallPeerJabberImpl.java +++ b/src/net/java/sip/communicator/impl/protocol/jabber/CallPeerJabberImpl.java @@ -9,6 +9,7 @@ package net.java.sip.communicator.impl.protocol.jabber; import java.lang.reflect.*; import java.util.*; +import net.java.sip.communicator.impl.protocol.jabber.extensions.cobri.*; import net.java.sip.communicator.impl.protocol.jabber.extensions.jingle.*; import net.java.sip.communicator.impl.protocol.jabber.extensions.jingle.ContentPacketExtension.SendersEnum; import net.java.sip.communicator.impl.protocol.jabber.jinglesdp.*; @@ -114,9 +115,11 @@ public class CallPeerJabberImpl try { - getMediaHandler().getTransportManager(). - wrapupConnectivityEstablishment(); - answer = getMediaHandler().generateSessionAccept(); + CallPeerMediaHandlerJabberImpl mediaHandler = getMediaHandler(); + + mediaHandler + .getTransportManager().wrapupConnectivityEstablishment(); + answer = mediaHandler.generateSessionAccept(); } catch(Exception exc) { @@ -362,6 +365,26 @@ public class CallPeerJabberImpl } /** + * Notifies this instance that a specific <tt>CobriConferenceIQ</tt> has + * been received. This <tt>CallPeerJabberImpl</tt> uses the part of the + * information provided in the specified <tt>conferenceIQ</tt> which + * concerns it only. + * + * @param conferenceIQ the <tt>CobriConferenceIQ</tt> which has been + * received + */ + void processCobriConferenceIQ(CobriConferenceIQ conferenceIQ) + { + /* + * CallPeerJabberImpl does not itself/directly know the specifics + * related to the channels allocated on the Jitsi VideoBridge server. + * The channels contain transport and media-related information so + * forward the notification to CallPeerMediaHandlerJabberImpl. + */ + getMediaHandler().processCobriConferenceIQ(conferenceIQ); + } + + /** * Processes the content-accept {@link JingleIQ}. * * @param content The {@link JingleIQ} that contains content that remote @@ -373,20 +396,27 @@ public class CallPeerJabberImpl try { - getMediaHandler().getTransportManager(). - wrapupConnectivityEstablishment(); - getMediaHandler().processAnswer(contents); + CallPeerMediaHandlerJabberImpl mediaHandler = getMediaHandler(); + + mediaHandler + .getTransportManager().wrapupConnectivityEstablishment(); + mediaHandler.processAnswer(contents); } - catch(Exception exc) + catch (Exception e) { - logger.warn("Failed to process a content-accept", exc); - //send an error response; - JingleIQ errResp = JinglePacketFactory.createSessionTerminate( - sessionInitIQ.getTo(), sessionInitIQ.getFrom(), - sessionInitIQ.getSID(), Reason.INCOMPATIBLE_PARAMETERS, - "Error: " + exc.getMessage()); + logger.warn("Failed to process a content-accept", e); - setState(CallPeerState.FAILED, "Error: " + exc.getMessage()); + // Send an error response. + String reason = "Error: " + e.getMessage(); + JingleIQ errResp + = JinglePacketFactory.createSessionTerminate( + sessionInitIQ.getTo(), + sessionInitIQ.getFrom(), + sessionInitIQ.getSID(), + Reason.INCOMPATIBLE_PARAMETERS, + reason); + + setState(CallPeerState.FAILED, reason); getProtocolProvider().getConnection().sendPacket(errResp); return; } @@ -446,6 +476,7 @@ public class CallPeerJabberImpl { new Thread() { + @Override public void run() { try @@ -537,25 +568,27 @@ public class CallPeerJabberImpl try { - boolean modify = false; - if(ext.getFirstChildOfType(RtpDescriptionPacketExtension.class) - != null) - { - modify = true; - } + boolean modify + = (ext.getFirstChildOfType(RtpDescriptionPacketExtension.class) + != null); + getMediaHandler().reinitContent(ext.getName(), ext, modify); } - catch(Exception exc) + catch(Exception e) { - logger.info("Failed to process an incoming content-modify", exc); + logger.info("Failed to process an incoming content-modify", e); - //send an error response; - JingleIQ errResp = JinglePacketFactory.createSessionTerminate( - sessionInitIQ.getTo(), sessionInitIQ.getFrom(), - sessionInitIQ.getSID(), Reason.INCOMPATIBLE_PARAMETERS, - "Error: " + exc.getMessage()); + // Send an error response. + String reason = "Error: " + e.getMessage(); + JingleIQ errResp + = JinglePacketFactory.createSessionTerminate( + sessionInitIQ.getTo(), + sessionInitIQ.getFrom(), + sessionInitIQ.getSID(), + Reason.INCOMPATIBLE_PARAMETERS, + reason); - setState(CallPeerState.FAILED, "Error: " + exc.getMessage()); + setState(CallPeerState.FAILED, reason); getProtocolProvider().getConnection().sendPacket(errResp); return; } @@ -626,8 +659,8 @@ public class CallPeerJabberImpl try { - mediaHandler.getTransportManager(). - wrapupConnectivityEstablishment(); + mediaHandler + .getTransportManager().wrapupConnectivityEstablishment(); mediaHandler.processAnswer(answer); } catch(Exception exc) 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 6af49cb..eaa5563 100644 --- a/src/net/java/sip/communicator/impl/protocol/jabber/CallPeerMediaHandlerJabberImpl.java +++ b/src/net/java/sip/communicator/impl/protocol/jabber/CallPeerMediaHandlerJabberImpl.java @@ -9,6 +9,7 @@ package net.java.sip.communicator.impl.protocol.jabber; import java.lang.reflect.*; import java.util.*; +import net.java.sip.communicator.impl.protocol.jabber.extensions.cobri.*; 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.protocol.*; @@ -18,7 +19,7 @@ import net.java.sip.communicator.util.*; import org.jitsi.service.neomedia.*; import org.jitsi.service.neomedia.device.*; import org.jitsi.service.neomedia.format.*; -import org.jivesoftware.smack.util.StringUtils; +import org.jivesoftware.smack.util.*; import org.jivesoftware.smackx.packet.*; /** @@ -143,6 +144,61 @@ public class CallPeerMediaHandlerJabberImpl } /** + * {@inheritDoc} + * + * In the case of a telephony conference organized by the local peer/user + * via the Jitsi VideoBridge server-side technology, returns an SSRC + * reported by the server as received on the channel allocated by the local + * peer/user for the purposes of communicating with the <tt>CallPeer</tt> + * associated with this instance. + */ + @Override + public long getRemoteSSRC(MediaType mediaType) + { + /* + * If the Jitsi VideoBridge server-side technology is utilized, a single + * MediaStream (per MediaType) is shared among the participating + * CallPeers and, consequently, the remote SSRCs cannot be associated + * with the CallPeers from which they are actually being sent. That's + * why the server will report them to the conference focus. + */ + TransportManagerJabberImpl transportManager = this.transportManager; + + if (transportManager instanceof RawUdpTransportManager) + { + RawUdpTransportManager rawUdpTransportManager + = (RawUdpTransportManager) transportManager; + CobriConferenceIQ.Channel channel + = rawUdpTransportManager.getCobriChannel( + mediaType, + false /* remote */); + + if (channel != null) + { + long[] ssrcs = channel.getSSRCs(); + + /* + * A peer (regardless of whether it is local or remote) may send + * multiple RTP streams at any time. In such a case, it is not + * clear which one of their SSRCs is to be returned. Anyway, the + * super says that the returned is the last known and we will + * presume that the last known in the list reported by the Jitsi + * VideoBridge server is the last. + */ + for (int i = ssrcs.length - 1; i >= 0; i--) + { + long remoteSSRC = ssrcs[i]; + + if (remoteSSRC != -1) + return remoteSSRC; + } + } + } + + return super.getRemoteSSRC(mediaType); + } + + /** * Get the local content of a specific content type (like audio or video). * * @param contentType content type name @@ -977,6 +1033,86 @@ public class CallPeerMediaHandlerJabberImpl } /** + * Notifies this instance that a specific <tt>CobriConferenceIQ</tt> has + * been received. This <tt>CallPeerMediaHandler</tt> uses the part of the + * information provided in the specified <tt>conferenceIQ</tt> which + * concerns it only. + * + * @param conferenceIQ the <tt>CobriConferenceIQ</tt> which has been + * received + */ + void processCobriConferenceIQ(CobriConferenceIQ conferenceIQ) + { + /* + * This CallPeerMediaHandler stores the media information but it does + * not store the cobri Channels (which contain both media and transport + * information). The TransportManager associated with this instance + * stores the cobri Channels but does not store media information (such + * as the remote SSRCs). An design/implementation choice has to be made + * though and the present one is to have this CallPeerMediaHandler + * transparently (with respect to the TransportManager) store the media + * information inside the TransportManager. + */ + TransportManagerJabberImpl transportManager = this.transportManager; + + if (transportManager instanceof RawUdpTransportManager) + { + RawUdpTransportManager rawUdpTransportManager + = (RawUdpTransportManager) transportManager; + long oldAudioRemoteSSRC = getRemoteSSRC(MediaType.AUDIO); + long oldVideoRemoteSSRC = getRemoteSSRC(MediaType.VIDEO); + + for (MediaType mediaType : MediaType.values()) + { + CobriConferenceIQ.Channel dst + = rawUdpTransportManager.getCobriChannel( + mediaType, + false /* remote */); + + if (dst != null) + { + CobriConferenceIQ.Content content + = conferenceIQ.getContent(mediaType.toString()); + + if (content != null) + { + CobriConferenceIQ.Channel src + = content.getChannel(dst.getID()); + + if (src != null) + { + long[] ssrcs = src.getSSRCs(); + + if (!Arrays.equals(dst.getSSRCs(), ssrcs)) + dst.setSSRCs(src.getSSRCs()); + } + } + } + } + + /* + * Do fire new PropertyChangeEvents for the properties + * AUDIO_REMOTE_SSRC and VIDEO_REMOTE_SSRC if necessary. + */ + long newAudioRemoteSSRC = getRemoteSSRC(MediaType.AUDIO); + long newVideoRemoteSSRC = getRemoteSSRC(MediaType.VIDEO); + + if (oldAudioRemoteSSRC != newAudioRemoteSSRC) + { + firePropertyChange( + AUDIO_REMOTE_SSRC, + oldAudioRemoteSSRC, newAudioRemoteSSRC); + } + if (oldVideoRemoteSSRC != newVideoRemoteSSRC) + { + firePropertyChange( + VIDEO_REMOTE_SSRC, + oldVideoRemoteSSRC, newVideoRemoteSSRC); + } + } + } + + /** * Process a <tt>ContentPacketExtension</tt> and initialize its * corresponding <tt>MediaStream</tt>. * @@ -986,7 +1122,7 @@ public class CallPeerMediaHandlerJabberImpl * @throws OperationFailedException if we fail to handle <tt>content</tt> * for reasons like failing to initialize media devices or streams. * @throws IllegalArgumentException if there's a problem with the syntax or - * the semantics of <tt>content</tt>. Method is synchronized in order to + * the semantics of <tt>content</tt>. The method is synchronized in order to * avoid closing mediaHandler when we are currently in process of * initializing, configuring and starting streams and anybody interested * in this operation can synchronize to the mediaHandler instance to wait @@ -1676,6 +1812,7 @@ public class CallPeerMediaHandlerJabberImpl /** * Returns the quality control for video calls if any. + * * @return the implemented quality control. */ public QualityControl getQualityControl() @@ -1695,6 +1832,7 @@ public class CallPeerMediaHandlerJabberImpl /** * Sometimes as initing a call with custom preset can set and we force * that quality controls is supported. + * * @param value whether quality controls is supported.. */ public void setSupportQualityControls(boolean value) @@ -1705,6 +1843,7 @@ public class CallPeerMediaHandlerJabberImpl /** * Closes the <tt>CallPeerMediaHandler</tt>. */ + @Override public synchronized void close() { super.close(); @@ -1721,16 +1860,17 @@ public class CallPeerMediaHandlerJabberImpl /** * Overrides to give access to the transport manager to send events * about ICE state changes. + * * @param property the name of the property of this * <tt>PropertyChangeNotifier</tt> which had its value changed * @param oldValue the value of the property with the specified name before * the change * @param newValue the value of the property with the specified name after */ + @Override protected void firePropertyChange( String property, - Object oldValue, - Object newValue) + Object oldValue, Object newValue) { super.firePropertyChange(property, oldValue, newValue); } 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 b2c9c46..8501831 100644 --- a/src/net/java/sip/communicator/impl/protocol/jabber/IceUdpTransportManager.java +++ b/src/net/java/sip/communicator/impl/protocol/jabber/IceUdpTransportManager.java @@ -668,7 +668,7 @@ public class IceUdpTransportManager for(Component component : stream.getComponents()) { - for(Candidate candidate : component.getLocalCandidates()) + for(Candidate<?> candidate : component.getLocalCandidates()) trans.addCandidate(createCandidate(candidate)); } @@ -685,7 +685,7 @@ public class IceUdpTransportManager * @return a new {@link CandidatePacketExtension} corresponding to the state * of the <tt>candidate</tt> candidate. */ - private CandidatePacketExtension createCandidate(Candidate candidate) + private CandidatePacketExtension createCandidate(Candidate<?> candidate) { CandidatePacketExtension packet = new CandidatePacketExtension(); diff --git a/src/net/java/sip/communicator/impl/protocol/jabber/OperationSetBasicTelephonyJabberImpl.java b/src/net/java/sip/communicator/impl/protocol/jabber/OperationSetBasicTelephonyJabberImpl.java index 053e51e..0e5ae0d 100644 --- a/src/net/java/sip/communicator/impl/protocol/jabber/OperationSetBasicTelephonyJabberImpl.java +++ b/src/net/java/sip/communicator/impl/protocol/jabber/OperationSetBasicTelephonyJabberImpl.java @@ -117,7 +117,6 @@ public class OperationSetBasicTelephonyJabberImpl } else if (registrationState == RegistrationState.UNREGISTERED) { - // plug jingle unregistration unsubscribeForJinglePackets(); if (logger.isInfoEnabled()) @@ -751,14 +750,14 @@ public class OperationSetBasicTelephonyJabberImpl } /** - * Unsubscribes us to notifications about incoming jingle packets. + * Unsubscribes us from notifications about incoming jingle packets. */ private void unsubscribeForJinglePackets() { - if(protocolProvider.getConnection() != null) - { - protocolProvider.getConnection().removePacketListener(this); - } + XMPPConnection connection = protocolProvider.getConnection(); + + if(connection != null) + connection.removePacketListener(this); } /** @@ -773,19 +772,19 @@ public class OperationSetBasicTelephonyJabberImpl */ public boolean accept(Packet packet) { - String sid = null; - - //we only handle JingleIQ-s - if( ! (packet instanceof JingleIQ) && !(packet instanceof SessionIQ)) + // We handle JingleIQ and SessionIQ. + if(!(packet instanceof JingleIQ) && !(packet instanceof SessionIQ)) { - AbstractCallPeer<?, ?> callPeer = - activeCallsRepository.findCallPeerBySessInitPacketID( - packet.getPacketID()); + String packetID = packet.getPacketID(); + AbstractCallPeer<?, ?> callPeer + = activeCallsRepository.findCallPeerBySessInitPacketID( + packetID); if(callPeer == null) { - callPeer = activeGTalkCallsRepository. - findCallPeerBySessInitPacketID(packet.getPacketID()); + callPeer + = activeGTalkCallsRepository.findCallPeerBySessInitPacketID( + packetID); } if(callPeer != null) @@ -798,20 +797,30 @@ public class OperationSetBasicTelephonyJabberImpl if (error != null) { - logger.error("Received an error: code=" + error.getCode() - + " message=" + error.getMessage()); - String message = "Service unavailable"; - Roster roster = getProtocolProvider().getConnection(). - getRoster(); + String errorMessage = error.getMessage(); - if(!roster.contains(packet.getFrom())) + logger.error( + "Received an error: code=" + error.getCode() + + " message=" + errorMessage); + + String message; + + if (errorMessage == null) { - message += ": try adding the contact to your contact " + - "list first."; - } + Roster roster + = getProtocolProvider().getConnection().getRoster(); + String packetFrom = packet.getFrom(); - if (error.getMessage() != null) - message = error.getMessage(); + message = "Service unavailable"; + if(!roster.contains(packetFrom)) + { + message + += ": try adding the contact " + packetFrom + + " to your contact list first."; + } + } + else + message = errorMessage; callPeer.setState(CallPeerState.FAILED, message); } @@ -831,7 +840,7 @@ public class OperationSetBasicTelephonyJabberImpl RtpDescriptionPacketExtension.class); } - sid = jingleIQ.getSID(); + String sid = jingleIQ.getSID(); //if this is not a session-initiate we'll only take it if we've //already seen its session ID. @@ -845,12 +854,14 @@ public class OperationSetBasicTelephonyJabberImpl { return true; } + else + { + String sid = sessionIQ.getID(); - sid = sessionIQ.getID(); - - //if this is not a session's initiate we'll only take it if we've - //already seen its session ID. - return (activeGTalkCallsRepository.findSID(sid) != null); + // If this is not a session's initiate, we'll take it only if + // we've seen its session ID already. + return (activeGTalkCallsRepository.findSID(sid) != null); + } } return false; } @@ -863,66 +874,56 @@ public class OperationSetBasicTelephonyJabberImpl */ public void processPacket(Packet packet) { - if(packet instanceof JingleIQ) - { - JingleIQ jingleIQ = (JingleIQ)packet; + IQ iq = (IQ) packet; - //to prevent hijacking sessions from other jingle based features - //like file transfer for example, we should only send the - //ack if this is a session-initiate with rtp content or if we are - //the owners of this packet's sid + /* + * To prevent hijacking sessions from other Jingle-based features such + * as file transfer, we should send the ack only if this is a + * session-initiate with RTP content or if we are the owners of the + * packet's SID. + */ - //first ack all "set" requests. - if(jingleIQ.getType() == IQ.Type.SET) - { - IQ ack = IQ.createResultIQ(jingleIQ); - protocolProvider.getConnection().sendPacket(ack); - } + //first ack all "set" requests. + if(iq.getType() == IQ.Type.SET) + { + IQ ack = IQ.createResultIQ(iq); - try - { - processJingleIQ(jingleIQ); - } - catch(Throwable t) - { - logger.info("Error while handling incoming Jingle packet: ", t); + protocolProvider.getConnection().sendPacket(ack); + } - /* - * The Javadoc on ThreadDeath says: If ThreadDeath is caught by - * a method, it is important that it be rethrown so that the - * thread actually dies. - */ - if (t instanceof ThreadDeath) - throw (ThreadDeath) t; - } + try + { + if (iq instanceof JingleIQ) + processJingleIQ((JingleIQ) iq); + else if (iq instanceof SessionIQ) + processSessionIQ((SessionIQ) iq); } - else if(packet instanceof SessionIQ) + catch(Throwable t) { - SessionIQ sessionIQ = (SessionIQ)packet; - - //first ack all "set" requests. - if(sessionIQ.getType() == IQ.Type.SET) + if (logger.isInfoEnabled()) { - IQ ack = IQ.createResultIQ(sessionIQ); - protocolProvider.getConnection().sendPacket(ack); - } + String packetClass; - try - { - processSessionIQ(sessionIQ); - } - catch(Throwable t) - { - logger.info("Error while handling incoming GTalk packet: ", t); + if (iq instanceof JingleIQ) + packetClass = "Jingle"; + else if (iq instanceof SessionIQ) + packetClass = "Gtalk"; + else + packetClass = packet.getClass().getSimpleName(); - /* - * The Javadoc on ThreadDeath says: If ThreadDeath is caught by - * a method, it is important that it be rethrown so that the - * thread actually dies. - */ - if (t instanceof ThreadDeath) - throw (ThreadDeath) t; + logger.info( + "Error while handling incoming " + packetClass + + " packet: ", + t); } + + /* + * The Javadoc on ThreadDeath says: If ThreadDeath is caught by + * a method, it is important that it be rethrown so that the + * thread actually dies. + */ + if (t instanceof ThreadDeath) + throw (ThreadDeath) t; } } @@ -948,10 +949,12 @@ public class OperationSetBasicTelephonyJabberImpl if(error != null) { - message += "\ncode=" + error.getCode() - + " message=" + error.getMessage(); - logger.error(" code=" + error.getCode() - + " message=" + error.getMessage()); + String errorStr + = "code=" + error.getCode() + + " message=" + error.getMessage(); + + message += "\n" + errorStr; + logger.error(" " + errorStr); } if (callPeer != null) @@ -964,13 +967,12 @@ public class OperationSetBasicTelephonyJabberImpl if(action == JingleAction.SESSION_INITIATE) { - CallJabberImpl call = null; - TransferPacketExtension transfer = (TransferPacketExtension) jingleIQ.getExtension( - TransferPacketExtension.ELEMENT_NAME, - TransferPacketExtension.NAMESPACE); + TransferPacketExtension.ELEMENT_NAME, + TransferPacketExtension.NAMESPACE); + CallJabberImpl call = null; if (transfer != null) { @@ -992,7 +994,7 @@ public class OperationSetBasicTelephonyJabberImpl && protocolProvider.getOurJID().equals( transfer.getTo())) { - // OK transfer correspond to us + // OK, we are legally involved in the transfer. call = attendantCall; } } @@ -1000,18 +1002,16 @@ public class OperationSetBasicTelephonyJabberImpl } if(call == null) - { call = new CallJabberImpl(this); - } - final CallJabberImpl callThread = call; + final CallJabberImpl finalCall = call; new Thread() { @Override public void run() { - callThread.processSessionInitiate(jingleIQ); + finalCall.processSessionInitiate(jingleIQ); } }.start(); @@ -1076,11 +1076,14 @@ public class OperationSetBasicTelephonyJabberImpl if (packetExtension instanceof CoinPacketExtension) { - CoinPacketExtension coinExt = - (CoinPacketExtension)packetExtension; + CoinPacketExtension coinExt + = (CoinPacketExtension)packetExtension; + callPeer.setConferenceFocus( - Boolean.parseBoolean(coinExt.getAttributeAsString( - CoinPacketExtension.ISFOCUS_ATTR_NAME))); + Boolean.parseBoolean( + coinExt.getAttributeAsString( + CoinPacketExtension + .ISFOCUS_ATTR_NAME))); } } } @@ -1164,6 +1167,7 @@ public class OperationSetBasicTelephonyJabberImpl // smack processor new Thread() { + @Override public void run() { try diff --git a/src/net/java/sip/communicator/impl/protocol/jabber/OperationSetTelephonyConferencingJabberImpl.java b/src/net/java/sip/communicator/impl/protocol/jabber/OperationSetTelephonyConferencingJabberImpl.java index 511cc43..3931c14 100644 --- a/src/net/java/sip/communicator/impl/protocol/jabber/OperationSetTelephonyConferencingJabberImpl.java +++ b/src/net/java/sip/communicator/impl/protocol/jabber/OperationSetTelephonyConferencingJabberImpl.java @@ -341,26 +341,23 @@ public class OperationSetTelephonyConferencingJabberImpl * * @param evt the event received */ + @Override public void registrationStateChanged(RegistrationStateChangeEvent evt) { super.registrationStateChanged(evt); RegistrationState registrationState = evt.getNewState(); - if (registrationState == RegistrationState.REGISTERED) + if (RegistrationState.REGISTERED.equals(registrationState)) { if(logger.isDebugEnabled()) - { logger.debug("Subscribes to Coin packets"); - } subscribeForCoinPackets(); } - else if (registrationState == RegistrationState.UNREGISTERED) + else if (RegistrationState.UNREGISTERED.equals(registrationState)) { if(logger.isDebugEnabled()) - { logger.debug("Unsubscribes to Coin packets"); - } unsubscribeForCoinPackets(); } } @@ -432,14 +429,14 @@ public class OperationSetTelephonyConferencingJabberImpl } /** - * Unsubscribes us to notifications about incoming Coin packets. + * Unsubscribes us from notifications about incoming Coin packets. */ private void unsubscribeForCoinPackets() { - if(parentProvider.getConnection() != null) - { - parentProvider.getConnection().removePacketListener(this); - } + XMPPConnection connection = parentProvider.getConnection(); + + if (connection != null) + connection.removePacketListener(this); } /** @@ -452,12 +449,7 @@ public class OperationSetTelephonyConferencingJabberImpl */ public boolean accept(Packet packet) { - if(!(packet instanceof CoinIQ)) - { - return false; - } - - return true; + return (packet instanceof CoinIQ); } /** @@ -487,17 +479,20 @@ public class OperationSetTelephonyConferencingJabberImpl sid); if (callPeer != null) - handleCoin(coinIQ, callPeer); + handleCoin(callPeer, coinIQ); } } /** - * Handle Coin IQ. + * Handles a specific <tt>CoinIQ</tt> sent from a specific + * <tt>CallPeer</tt>. * - * @param coinIQ Coin IQ - * @param callPeer a <tt>CallPeer</tt> + * @param callPeer the <tt>CallPeer</tt> from which the specified + * <tt>CoinIQ</tt> was sent + * @param coinIQ the <tt>CoinIQ</tt> which was sent from the specified + * <tt>callPeer</tt> */ - private void handleCoin(CoinIQ coinIQ, CallPeerJabberImpl callPeer) + private void handleCoin(CallPeerJabberImpl callPeer, CoinIQ coinIQ) { setConferenceInfoXML(callPeer, -1, coinIQ.getChildElementXML()); } diff --git a/src/net/java/sip/communicator/impl/protocol/jabber/OperationSetVideoBridgeImpl.java b/src/net/java/sip/communicator/impl/protocol/jabber/OperationSetVideoBridgeImpl.java index 2408cd7..f4ff56b 100644 --- a/src/net/java/sip/communicator/impl/protocol/jabber/OperationSetVideoBridgeImpl.java +++ b/src/net/java/sip/communicator/impl/protocol/jabber/OperationSetVideoBridgeImpl.java @@ -8,23 +8,38 @@ package net.java.sip.communicator.impl.protocol.jabber; import java.util.*; -import org.jivesoftware.smack.*; -import org.jivesoftware.smackx.packet.*; - import net.java.sip.communicator.impl.protocol.jabber.extensions.cobri.*; import net.java.sip.communicator.service.protocol.*; +import net.java.sip.communicator.service.protocol.event.*; import net.java.sip.communicator.service.protocol.media.*; +import net.java.sip.communicator.util.*; + +import org.jivesoftware.smack.*; +import org.jivesoftware.smack.filter.*; +import org.jivesoftware.smack.packet.*; /** * Implements <tt>OperationSetVideoBridge</tt> for Jabber. * * @author Yana Stamcheva + * @author Lyubomir Marinov */ public class OperationSetVideoBridgeImpl - implements OperationSetVideoBridge + implements OperationSetVideoBridge, + PacketFilter, + PacketListener, + RegistrationStateChangeListener { /** - * The parent protocol provider. + * The <tt>Logger</tt> used by the <tt>OperationSetVideoBridgeImpl</tt> + * class and its instances for logging output. + */ + private static final Logger logger + = Logger.getLogger(OperationSetVideoBridgeImpl.class); + + /** + * The <tt>ProtocolProviderService</tt> implementation which initialized + * this instance, owns it and is often referred to as its parent. */ private final ProtocolProviderServiceJabberImpl protocolProvider; @@ -35,10 +50,28 @@ public class OperationSetVideoBridgeImpl * * @param protocolProvider the parent Jabber protocol provider */ - public OperationSetVideoBridgeImpl(ProtocolProviderServiceJabberImpl - protocolProvider) + public OperationSetVideoBridgeImpl( + ProtocolProviderServiceJabberImpl protocolProvider) { this.protocolProvider = protocolProvider; + this.protocolProvider.addRegistrationStateChangeListener(this); + } + + /** + * Implements {@link PacketFilter}. Determines whether this instance is + * interested in a specific {@link Packet}. + * <tt>OperationSetVideoBridgeImpl</tt> returns <tt>true</tt> if the + * specified <tt>packet</tt> is a {@link CobriConferenceIQ}; otherwise, + * <tt>false</tt>. + * + * @param packet the <tt>Packet</tt> to be determined whether this instance + * is interested in it + * @return <tt>true</tt> if the specified <tt>packet</tt> is a + * <tt>CobriConferenceIQ</tt>; otherwise, <tt>false</tt> + */ + public boolean accept(Packet packet) + { + return (packet instanceof CobriConferenceIQ); } /** @@ -54,12 +87,14 @@ public class OperationSetVideoBridgeImpl */ public Call createConfCall(String[] callees) throws OperationFailedException, - OperationNotSupportedException + OperationNotSupportedException { - return protocolProvider + return + protocolProvider .getOperationSet(OperationSetTelephonyConferencing.class) - .createConfCall(callees, - new MediaAwareCallConference(true)); + .createConfCall( + callees, + new MediaAwareCallConference(true)); } /** @@ -82,10 +117,10 @@ public class OperationSetVideoBridgeImpl throws OperationFailedException, OperationNotSupportedException { - return protocolProvider.getOperationSet( - OperationSetTelephonyConferencing.class).inviteCalleeToCall( - uri, - call); + return + protocolProvider + .getOperationSet(OperationSetTelephonyConferencing.class) + .inviteCalleeToCall(uri, call); } /** @@ -100,7 +135,151 @@ public class OperationSetVideoBridgeImpl { String jitsiVideoBridge = protocolProvider.getJitsiVideoBridge(); - return (jitsiVideoBridge != null - && jitsiVideoBridge.length() > 0); + return ((jitsiVideoBridge != null) && (jitsiVideoBridge.length() > 0)); + } + + /** + * Notifies this instance that a specific <tt>CobriConferenceIQ</tt> has + * been received. + * + * @param conferenceIQ the <tt>CobriConferenceIQ</tt> which has been + * received + */ + private void processCobriConferenceIQ(CobriConferenceIQ conferenceIQ) + { + /* + * The application is not a Jitsi VideoBridge server, it is a client. + * Consequently, the specified CobriConferenceIQ is sent to it in + * relation to the part of the application's functionality which makes + * requests to a Jitsi VideoBridge server i.e. CallJabberImpl. + * + * Additionally, the method processCobriConferenceIQ is presently tasked + * with processing CobriConferenceIQ requests only. They are SET IQs + * sent by the Jitsi VideoBridge server to notify the application about + * updates in the states of (cobri) conferences organized by the + * application. + */ + if (IQ.Type.SET.equals(conferenceIQ.getType()) + && conferenceIQ.getID() != null) + { + OperationSetBasicTelephony<?> basicTelephony + = protocolProvider.getOperationSet( + OperationSetBasicTelephony.class); + + if (basicTelephony != null) + { + Iterator<? extends Call> i = basicTelephony.getActiveCalls(); + + while (i.hasNext()) + { + Call call = i.next(); + + if (call instanceof CallJabberImpl) + { + CallJabberImpl callJabberImpl = (CallJabberImpl) call; + MediaAwareCallConference conference + = callJabberImpl.getConference(); + + if ((conference != null) + && conference.isJitsiVideoBridge()) + { + /* + * TODO We may want to disallow rogue CallJabberImpl + * instances which may throw an exception to prevent + * the conferenceIQ from reaching the CallJabberImpl + * instance which it was meant for. + */ + callJabberImpl.processCobriConferenceIQ( + conferenceIQ); + break; + } + } + } + } + } + } + + /** + * Implements {@link PacketListener}. Notifies this instance that a specific + * {@link Packet} (which this instance has already expressed interest into + * by returning <tt>true</tt> from {@link #accept(Packet)}) has been + * received. + * + * @param packet the <tt>Packet</tt> which has been received and which this + * instance is given a chance to process + */ + public void processPacket(Packet packet) + { + /* + * As we do elsewhere, acknowledge the receipt of the Packet first and + * then go about our business with it. + */ + IQ iq = (IQ) packet; + + if (iq.getType() == IQ.Type.SET) + protocolProvider.getConnection().sendPacket(IQ.createResultIQ(iq)); + + /* + * Now that the acknowledging is out of the way, do go about our + * business with the Packet. + */ + CobriConferenceIQ conferenceIQ = (CobriConferenceIQ) iq; + boolean interrupted = false; + + try + { + processCobriConferenceIQ(conferenceIQ); + } + catch (Throwable t) + { + logger.error( + "An error occurred during the processing of a " + + packet.getClass().getName() + " packet", + t); + + if (t instanceof InterruptedException) + { + /* + * We cleared the interrupted state of the current Thread by + * catching the InterruptedException. However, we do not really + * care whether the current Thread has been interrupted - we + * caught the InterruptedException because we want to swallow + * any Throwable. Consequently, we should better restore the + * interrupted state. + */ + interrupted = true; + } + else if (t instanceof ThreadDeath) + throw (ThreadDeath) t; + } + if (interrupted) + Thread.currentThread().interrupt(); + } + + /** + * {@inheritDoc} + * + * Implements {@link RegistrationStateChangeListener}. Notifies this + * instance that there has been a change in the <tt>RegistrationState</tt> + * of {@link #protocolProvider}. Subscribes this instance to + * {@link CobriConferenceIQ}s as soon as <tt>protocolProvider</tt> is + * registered and unsubscribes it as soon as <tt>protocolProvider</tt> is + * unregistered. + */ + public void registrationStateChanged(RegistrationStateChangeEvent ev) + { + RegistrationState registrationState = ev.getNewState(); + + if (RegistrationState.REGISTERED.equals(registrationState)) + { + protocolProvider.getConnection().addPacketListener(this, this); + } + else if (RegistrationState.UNREGISTERED.equals(registrationState)) + { + XMPPConnection connection = protocolProvider.getConnection(); + + if (connection != null) + connection.removePacketListener(this); + } } } diff --git a/src/net/java/sip/communicator/impl/protocol/jabber/P2PTransportManager.java b/src/net/java/sip/communicator/impl/protocol/jabber/P2PTransportManager.java index d56660e..f8f0289 100644 --- a/src/net/java/sip/communicator/impl/protocol/jabber/P2PTransportManager.java +++ b/src/net/java/sip/communicator/impl/protocol/jabber/P2PTransportManager.java @@ -21,6 +21,7 @@ import org.jivesoftware.smack.packet.*; * Google P2P TransportManager. * * @author Sebastien Vincent + * @author Lyubomir Marinov */ public class P2PTransportManager extends IceUdpTransportManager @@ -61,13 +62,16 @@ public class P2PTransportManager * @return the ICE agent to use for all the ICE negotiation that this * transport manager would be going through */ + @Override protected Agent createIceAgent() { CallPeerJabberImpl peer = getCallPeer(); ProtocolProviderServiceJabberImpl provider = peer.getProtocolProvider(); - Agent iceAgent = TransportManagerGTalkImpl.createAgent(provider, - !peer.isInitiator()); + Agent iceAgent + = TransportManagerGTalkImpl.createAgent( + provider, + !peer.isInitiator()); /* We use a custom strategy that will wait a little bit before choosing * to go through a relay. In fact Empathy will begin to send first the @@ -76,7 +80,7 @@ public class P2PTransportManager * checks will start earlier for relay. */ iceAgent.setNominationStrategy( - NominationStrategy.NOMINATE_FIRST_HOST_OR_REFLEXIVE_VALID); + NominationStrategy.NOMINATE_FIRST_HOST_OR_REFLEXIVE_VALID); return iceAgent; } @@ -89,6 +93,7 @@ public class P2PTransportManager * <tt>TransportManagerJabberImpl</tt> * @see TransportManagerJabberImpl#getXmlNamespace() */ + @Override public String getXmlNamespace() { return "http://www.google.com/transport/p2p"; @@ -99,6 +104,7 @@ public class P2PTransportManager * * @return <tt>PacketExtension</tt> */ + @Override protected PacketExtension getTransportPacketExtension() { return new GTalkTransportPacketExtension(); @@ -113,37 +119,46 @@ public class P2PTransportManager * * @return the {@link GTalkTransportPacketExtension} */ + @Override public PacketExtension createTransport(IceMediaStream stream) { GTalkTransportPacketExtension trans = new GTalkTransportPacketExtension(); if(stream != null) + { for(Component component : stream.getComponents()) { - List<LocalCandidate> candToRemove = - new ArrayList<LocalCandidate>(); - List<LocalCandidate> candidates = - component.getLocalCandidates(); + /* Remove the bases of the UPNP candidates. */ + List<LocalCandidate> candidates + = component.getLocalCandidates(); + List<LocalCandidate> candidatesToRemove = null; - for(LocalCandidate candidate : component.getLocalCandidates()) + for(LocalCandidate candidate : candidates) { if(candidate instanceof UPNPCandidate) { LocalCandidate base = candidate.getBase(); - candToRemove.add(base); + + if (candidatesToRemove == null) + { + candidatesToRemove + = new ArrayList<LocalCandidate>( + candidates.size()); + } + candidatesToRemove.add(base); } } - - for(Candidate candidate : candToRemove) + if (candidatesToRemove != null) { - candidates.remove(candidate); + for(Candidate<?> candidateToRemove : candidatesToRemove) + candidates.remove(candidateToRemove); } - for(Candidate candidate : candidates) + for(Candidate<?> candidate : candidates) trans.addCandidate(createCandidate(candidate)); } - + } return trans; } @@ -157,19 +172,13 @@ public class P2PTransportManager * @return a new {@link CandidatePacketExtension} corresponding to the state * of the <tt>candidate</tt> candidate. */ - private GTalkCandidatePacketExtension createCandidate(Candidate candidate) + private GTalkCandidatePacketExtension createCandidate( + Candidate<?> candidate) { - String name = - candidate.getParentComponent().getParentStream().getName(); - - if(candidate.getParentComponent().getComponentID() == Component.RTP) - { - name = "rtp"; - } - else - { - name = "rtcp"; - } + String name + = (candidate.getParentComponent().getComponentID() == Component.RTP) + ? "rtp" + : "rtcp"; return GTalkPacketFactory.createCandidate(candidate, name); } @@ -194,9 +203,10 @@ public class P2PTransportManager * {@link #wrapupCandidateHarvest()}. * @throws OperationFailedException in case we fail allocating ports */ + @Override public void startCandidateHarvest( - List<ContentPacketExtension> ourOffer, - final TransportInfoSender transportInfoSender) + List<ContentPacketExtension> ourOffer, + final TransportInfoSender transportInfoSender) throws OperationFailedException { final List<ContentPacketExtension> offer = ourOffer; @@ -224,13 +234,11 @@ public class P2PTransportManager } for(ContentPacketExtension ourContent : offer) - { - ourContent.addChildExtension( - getTransportPacketExtension()); - } + ourContent.addChildExtension(getTransportPacketExtension()); new Thread() { + @Override public void run() { Collection<ContentPacketExtension> transportInfoContents @@ -246,7 +254,8 @@ public class P2PTransportManager = ourContent.getFirstChildOfType( RtpDescriptionPacketExtension.class); - ourContent.addChildExtension(getTransportPacketExtension()); + ourContent.addChildExtension( + getTransportPacketExtension()); IceMediaStream stream = null; try @@ -275,7 +284,7 @@ public class P2PTransportManager transportInfoContents.add(transportInfoContent); transportInfoSender.sendTransportInfo( - transportInfoContents); + transportInfoContents); } } } @@ -303,28 +312,23 @@ public class P2PTransportManager if (IceProcessingState.RUNNING.equals(iceAgent.getState())) { if(logger.isInfoEnabled()) - { logger.info("Update ICE remote candidates"); - } for (ContentPacketExtension content : remote) { GTalkTransportPacketExtension transport = content.getFirstChildOfType( GTalkTransportPacketExtension.class); - List<GTalkCandidatePacketExtension> candidates = transport.getChildExtensionsOfType( - GTalkCandidatePacketExtension.class); + GTalkCandidatePacketExtension.class); - if(candidates == null || candidates.size() == 0) - { + if((candidates == null) || (candidates.size() == 0)) return false; - } RtpDescriptionPacketExtension description = content.getFirstChildOfType( - RtpDescriptionPacketExtension.class); + RtpDescriptionPacketExtension.class); if (description == null) { @@ -371,7 +375,7 @@ public class P2PTransportManager candidate.getType().toString()), "0", (long)(candidate.getPreference() * 1000), - // Gingle does not send rel-addr/rel-port infromation. + // Gingle does not send rel-addr/rel-port information. null, ufrag); @@ -383,9 +387,7 @@ public class P2PTransportManager for(IceMediaStream stream : iceAgent.getStreams()) { for(Component component : stream.getComponents()) - { component.updateRemoteCandidate(); - } } return false; @@ -399,7 +401,6 @@ public class P2PTransportManager GTalkTransportPacketExtension transport = content.getFirstChildOfType( GTalkTransportPacketExtension.class); - List<GTalkCandidatePacketExtension> candidates = transport.getChildExtensionsOfType( GTalkCandidatePacketExtension.class); @@ -440,7 +441,6 @@ public class P2PTransportManager */ if (candidate.getGeneration() != generation) continue; - if(candidate.getProtocol().equalsIgnoreCase("ssltcp")) continue; @@ -462,7 +462,7 @@ public class P2PTransportManager candidate.getType().toString()), "0", (long)(candidate.getPreference() * 1000), - // Gingle does not send rel-addr/rel-port infromation. + // Gingle does not send rel-addr/rel-port information. null, ufrag); 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 dea5306..6af0f58 100644 --- a/src/net/java/sip/communicator/impl/protocol/jabber/RawUdpTransportManager.java +++ b/src/net/java/sip/communicator/impl/protocol/jabber/RawUdpTransportManager.java @@ -337,6 +337,11 @@ public class RawUdpTransportManager * Gets the {@link CobriConferenceIQ.Channel} which belongs to a content * associated with a specific <tt>MediaType</tt> and is to be either locally * or remotely used. + * <p> + * <b>Note</b>: Modifications to the <tt>CobriConferenceIQ.Channel</tt> + * instance returned by the method propagate to (the state of) this + * instance. + * </p> * * @param mediaType the <tt>MediaType</tt> associated with the content which * contains the <tt>CobriConferenceIQ.Channel</tt> to get @@ -348,7 +353,7 @@ public class RawUdpTransportManager * in accord with the specified <tt>local</tt> indicator if such a channel * exists; otherwise, <tt>null</tt> */ - private CobriConferenceIQ.Channel getCobriChannel( + CobriConferenceIQ.Channel getCobriChannel( MediaType mediaType, boolean local) { diff --git a/src/net/java/sip/communicator/impl/protocol/jabber/extensions/caps/EntityCapsManager.java b/src/net/java/sip/communicator/impl/protocol/jabber/extensions/caps/EntityCapsManager.java index b8e9bf0..301d4fd 100644 --- a/src/net/java/sip/communicator/impl/protocol/jabber/extensions/caps/EntityCapsManager.java +++ b/src/net/java/sip/communicator/impl/protocol/jabber/extensions/caps/EntityCapsManager.java @@ -27,7 +27,6 @@ import org.jivesoftware.smackx.*; import org.jivesoftware.smackx.packet.*; import org.xmlpull.mxp1.*; import org.xmlpull.v1.*; -// disambiguation /** * Keeps track of entity capabilities. @@ -35,7 +34,7 @@ import org.xmlpull.v1.*; * This work is based on Jonas Adahl's smack fork. * * @author Emil Ivov - * @author Lubomir Marinov + * @author Lyubomir Marinov */ public class EntityCapsManager { @@ -885,18 +884,16 @@ public class EntityCapsManager /* Google Talk web does not set hash but we need it to be cached */ if(hash == null) - { hash = ""; - } if (hash != null) { // Check it the packet indicates that the user is online. We // will use this information to decide if we're going to send // the discover info request. - boolean online = false; - if (packet instanceof Presence) - online = ((Presence) packet).isAvailable(); + boolean online + = (packet instanceof Presence) + && ((Presence) packet).isAvailable(); if(online) { @@ -917,7 +914,7 @@ public class EntityCapsManager * Implements an immutable value which stands for a specific node, a * specific hash (algorithm) and a specific ver. * - * @author Lubomir Marinov + * @author Lyubomir Marinov */ public static class Caps { diff --git a/src/net/java/sip/communicator/impl/protocol/jabber/extensions/cobri/CobriConferenceIQ.java b/src/net/java/sip/communicator/impl/protocol/jabber/extensions/cobri/CobriConferenceIQ.java index d44c6ca..db23b3a 100644 --- a/src/net/java/sip/communicator/impl/protocol/jabber/extensions/cobri/CobriConferenceIQ.java +++ b/src/net/java/sip/communicator/impl/protocol/jabber/extensions/cobri/CobriConferenceIQ.java @@ -39,6 +39,13 @@ public class CobriConferenceIQ = "http://jitsi.org/protocol/videobridge#conference"; /** + * An array of <tt>long</tt>s which represents the lack of any (RTP) SSRCs + * seen/received on a <tt>Channel</tt>. Explicitly defined to reduce + * unnecessary allocations. + */ + public static final long[] NO_SSRCS = new long[0]; + + /** * The list of {@link Content}s included into this <tt>conference</tt> IQ. */ private final List<Content> contents = new LinkedList<Content>(); @@ -234,6 +241,13 @@ public class CobriConferenceIQ public static final String RTP_PORT_ATTR_NAME = "rtpport"; /** + * The name of the XML element which is a child of the <channel> + * element and which identifies/specifies an (RTP) SSRC which has been + * seen/received on the respective <tt>Channel</tt>. + */ + public static final String SSRC_ELEMENT_NAME = "ssrc"; + + /** * The number of seconds of inactivity after which the <tt>channel</tt> * represented by this instance expires. */ @@ -267,6 +281,13 @@ public class CobriConferenceIQ private int rtpPort; /** + * The list of (RTP) SSRCs which have been seen/received on this + * <tt>Channel</tt> by now. These may exclude SSRCs which are no longer + * active. Set by the Jitsi VideoBridge server, not its clients. + */ + private long[] ssrcs = NO_SSRCS; + + /** * Adds a <tt>payload-type</tt> element defined by XEP-0167: Jingle RTP * Sessions to this <tt>channel</tt>. * @@ -290,6 +311,33 @@ public class CobriConferenceIQ } /** + * Adds a specific (RTP) SSRC to the list of SSRCs seen/received on this + * <tt>Channel</tt>. Invoked by the Jitsi VideoBridge server, not its + * clients. + * + * @param ssrc the (RTP) SSRC to be added to the list of SSRCs + * seen/received on this <tt>Channel</tt> + * @return <tt>true</tt> if the list of SSRCs seen/received on this + * <tt>Channel</tt> has been modified as part of the method call; + * otherwise, <tt>false</tt> + */ + public synchronized boolean addSSRC(long ssrc) + { + // contains + for (long element : ssrcs) + if (element == ssrc) + return false; + + // add + long[] newSSRCs = new long[ssrcs.length + 1]; + + System.arraycopy(ssrcs, 0, newSSRCs, 0, ssrcs.length); + newSSRCs[ssrcs.length] = ssrc; + ssrcs = newSSRCs; + return true; + } + + /** * Gets the number of seconds of inactivity after which the * <tt>channel</tt> represented by this instance expires. * @@ -332,6 +380,18 @@ public class CobriConferenceIQ } /** + * Gets (a copy of) the list of (RTP) SSRCs seen/received on this + * <tt>Channel</tt>. + * + * @return an array of <tt>long</tt>s which represents (a copy of) the + * list of (RTP) SSRCs seen/received on this <tt>Channel</tt> + */ + public synchronized long[] getSSRCs() + { + return (ssrcs.length == 0) ? NO_SSRCS : ssrcs.clone(); + } + + /** * Removes a <tt>payload-type</tt> element defined by XEP-0167: Jingle * RTP Sessions from this <tt>channel</tt>. * @@ -347,6 +407,54 @@ public class CobriConferenceIQ } /** + * Removes a specific (RTP) SSRC from the list of SSRCs seen/received on + * this <tt>Channel</tt>. Invoked by the Jitsi VideoBridge server, not + * its clients. + * + * @param ssrc the (RTP) SSRC to be removed from the list of SSRCs + * seen/received on this <tt>Channel</tt> + * @return <tt>true</tt> if the list of SSRCs seen/received on this + * <tt>Channel</tt> has been modified as part of the method call; + * otherwise, <tt>false</tt> + */ + public synchronized boolean removeSSRC(long ssrc) + { + if (ssrcs.length == 1) + { + if (ssrcs[0] == ssrc) + { + ssrcs = NO_SSRCS; + return true; + } + else + return false; + } + else + { + for (int i = 0; i < ssrcs.length; i++) + { + if (ssrcs[i] == ssrc) + { + long[] newSSRCs = new long[ssrcs.length - 1]; + + if (i != 0) + System.arraycopy(ssrcs, 0, newSSRCs, 0, i); + if (i != newSSRCs.length) + { + System.arraycopy( + ssrcs, i + 1, + newSSRCs, i, + newSSRCs.length - i); + } + ssrcs = newSSRCs; + return true; + } + } + return false; + } + } + + /** * Sets the number of seconds of inactivity after which the * <tt>channel</tt> represented by this instance expires. * @@ -389,6 +497,24 @@ public class CobriConferenceIQ this.rtpPort = rtpPort; } + /** + * Sets the list of (RTP) SSRCs seen/received on this <tt>Channel</tt>. + * + * @param ssrcs the list of (RTP) SSRCs to be set as seen/received on + * this <tt>Channel</tt> + */ + public void setSSRCs(long[] ssrcs) + { + /* + * TODO Make sure that the SSRCs set on this instance do not contain + * duplicates. + */ + this.ssrcs + = ((ssrcs == null) || (ssrcs.length == 0)) + ? NO_SSRCS + : ssrcs.clone(); + } + public void toXML(StringBuilder xml) { xml.append('<').append(ELEMENT_NAME); @@ -396,45 +522,70 @@ public class CobriConferenceIQ String id = getID(); if (id != null) + { xml.append(' ').append(ID_ATTR_NAME).append("='").append(id) .append('\''); + } String host = getHost(); if (host != null) + { xml.append(' ').append(HOST_ATTR_NAME).append("='").append(host) .append('\''); + } int rtpPort = getRTPPort(); if (rtpPort > 0) + { xml.append(' ').append(RTP_PORT_ATTR_NAME).append("='") .append(rtpPort).append('\''); + } int rtcpPort = getRTCPPort(); if (rtcpPort > 0) + { xml.append(' ').append(RTCP_PORT_ATTR_NAME).append("='") .append(rtcpPort).append('\''); + } int expire = getExpire(); if (expire >= 0) + { xml.append(' ').append(EXPIRE_ATTR_NAME).append("='") .append(expire).append('\''); + } List<PayloadTypePacketExtension> payloadTypes = getPayloadTypes(); + boolean hasPayloadTypes = (payloadTypes.size() != 0); + long[] ssrcs = getSSRCs(); + boolean hasSSRCs = (ssrcs.length != 0); - if (payloadTypes.size() == 0) + if (hasPayloadTypes || hasSSRCs) { - xml.append(" />"); + xml.append('>'); + if (hasPayloadTypes) + { + for (PayloadTypePacketExtension payloadType : payloadTypes) + xml.append(payloadType.toXML()); + } + if (hasSSRCs) + { + for (long ssrc : ssrcs) + { + xml.append('<').append(SSRC_ELEMENT_NAME).append('>') + .append(ssrc).append("</") + .append(SSRC_ELEMENT_NAME).append('>'); + } + } + xml.append("</").append(ELEMENT_NAME).append('>'); } else { - xml.append('>'); - for (PayloadTypePacketExtension payloadType : payloadTypes) - xml.append(payloadType.toXML()); - xml.append("</").append(ELEMENT_NAME).append('>'); + xml.append(" />"); } } } diff --git a/src/net/java/sip/communicator/impl/protocol/jabber/extensions/cobri/CobriIQProvider.java b/src/net/java/sip/communicator/impl/protocol/jabber/extensions/cobri/CobriIQProvider.java index aab8ad3..54d4ccf 100644 --- a/src/net/java/sip/communicator/impl/protocol/jabber/extensions/cobri/CobriIQProvider.java +++ b/src/net/java/sip/communicator/impl/protocol/jabber/extensions/cobri/CobriIQProvider.java @@ -51,6 +51,7 @@ public class CobriIQProvider CobriConferenceIQ.Channel channel = null; CobriConferenceIQ.Content content = null; PacketExtensionProvider payloadTypePacketExtensionProvider = null; + StringBuilder ssrc = null; while (!done) { @@ -64,15 +65,21 @@ public class CobriIQProvider { done = true; } - else if (CobriConferenceIQ.Channel.ELEMENT_NAME - .equals(name)) + else if (CobriConferenceIQ.Channel.ELEMENT_NAME.equals( + name)) { content.addChannel(channel); channel = null; } - else if (CobriConferenceIQ.Content.ELEMENT_NAME + else if (CobriConferenceIQ.Channel.SSRC_ELEMENT_NAME .equals(name)) { + channel.addSSRC(Long.parseLong(ssrc.toString().trim())); + ssrc = null; + } + else if (CobriConferenceIQ.Content.ELEMENT_NAME.equals( + name)) + { conference.addContent(content); content = null; } @@ -129,9 +136,14 @@ public class CobriIQProvider if ((expire != null) && (expire.length() != 0)) channel.setExpire(Integer.parseInt(expire)); } - else if (CobriConferenceIQ.Content.ELEMENT_NAME + else if (CobriConferenceIQ.Channel.SSRC_ELEMENT_NAME .equals(name)) { + ssrc = new StringBuilder(); + } + else if (CobriConferenceIQ.Content.ELEMENT_NAME.equals( + name)) + { content = new CobriConferenceIQ.Content(); String contentName @@ -181,6 +193,13 @@ public class CobriIQProvider } break; } + + case XmlPullParser.TEXT: + { + if (ssrc != null) + ssrc.append(parser.getText()); + break; + } } } diff --git a/src/net/java/sip/communicator/service/protocol/AbstractCallPeer.java b/src/net/java/sip/communicator/service/protocol/AbstractCallPeer.java index e490dd1..44f4a68 100644 --- a/src/net/java/sip/communicator/service/protocol/AbstractCallPeer.java +++ b/src/net/java/sip/communicator/service/protocol/AbstractCallPeer.java @@ -253,9 +253,8 @@ public abstract class AbstractCallPeer<T extends Call, protected ConferenceMember findConferenceMember(long ssrc) { List<ConferenceMember> members = getConferenceMembers(); - int memberCount = members.size(); - for (int i = 0; i < memberCount; i++) + for (int i = 0, memberCount = members.size(); i < memberCount; i++) { ConferenceMember member = members.get(i); diff --git a/src/net/java/sip/communicator/service/protocol/AccountID.java b/src/net/java/sip/communicator/service/protocol/AccountID.java index ba1cf86..c373120 100644 --- a/src/net/java/sip/communicator/service/protocol/AccountID.java +++ b/src/net/java/sip/communicator/service/protocol/AccountID.java @@ -463,14 +463,15 @@ public abstract class AccountID public List<String> getSortedEnabledEncryptionProtocolList() { Map<String, Integer> encryptionProtocols - = this.getIntegerPropertiesByPrefix( + = getIntegerPropertiesByPrefix( ProtocolProviderFactory.ENCRYPTION_PROTOCOL, true); Map<String, Boolean> encryptionProtocolStatus - = this.getBooleanPropertiesByPrefix( + = getBooleanPropertiesByPrefix( ProtocolProviderFactory.ENCRYPTION_PROTOCOL_STATUS, true, false); + // If the account is not yet configured, then ZRTP is activated by // default. if(encryptionProtocols.size() == 0) @@ -484,49 +485,45 @@ public abstract class AccountID true); } - List<String> sortedEncryptionProtocolList + List<String> sortedEncryptionProtocols = new ArrayList<String>(encryptionProtocols.size()); - Iterator<String> names = encryptionProtocols.keySet().iterator(); - String name; - int index; + // First: add all protocol in the right order. - while(names.hasNext()) + for (Map.Entry<String, Integer> e : encryptionProtocols.entrySet()) { - name = names.next(); - index = encryptionProtocols.get(name); + int index = e.getValue(); // If the key is set. - if(index != -1) + if (index != -1) { - if(index > sortedEncryptionProtocolList.size()) - { - index = sortedEncryptionProtocolList.size(); - } - sortedEncryptionProtocolList.add(index, name); + if (index > sortedEncryptionProtocols.size()) + index = sortedEncryptionProtocols.size(); + + String name = e.getKey(); + + sortedEncryptionProtocols.add(index, name); } } // Second: remove all disabled protocol. - String encryptionProtocolPropertyName; - int prefixeLength + int namePrefixLength = ProtocolProviderFactory.ENCRYPTION_PROTOCOL.length() + 1; - names = encryptionProtocols.keySet().iterator(); - while(names.hasNext()) + + for (Iterator<String> i = sortedEncryptionProtocols.iterator(); + i.hasNext();) { - encryptionProtocolPropertyName = names.next(); - index = encryptionProtocols.get(encryptionProtocolPropertyName); - name = encryptionProtocolPropertyName.substring(prefixeLength); - // If the key is set. - if(index != -1 && !encryptionProtocolStatus.get( - ProtocolProviderFactory.ENCRYPTION_PROTOCOL_STATUS + String name = i.next().substring(namePrefixLength); + + if (!encryptionProtocolStatus.get( + ProtocolProviderFactory.ENCRYPTION_PROTOCOL_STATUS + "." + name)) { - sortedEncryptionProtocolList.remove(index); + i.remove(); } } - return sortedEncryptionProtocolList; + return sortedEncryptionProtocols; } /** diff --git a/src/net/java/sip/communicator/service/protocol/ActiveCallsRepository.java b/src/net/java/sip/communicator/service/protocol/ActiveCallsRepository.java index e1ceeb4..ebe4008 100644 --- a/src/net/java/sip/communicator/service/protocol/ActiveCallsRepository.java +++ b/src/net/java/sip/communicator/service/protocol/ActiveCallsRepository.java @@ -100,7 +100,12 @@ public abstract class ActiveCallsRepository<T extends Call, { synchronized(activeCalls) { - return new LinkedList<T>(activeCalls.values()).iterator(); + /* + * Given that we know the elements that will go into the new List, + * it is more optimal in terms of memory and execution time to use + * ArrayList rather than LinkedList. + */ + return new ArrayList<T>(activeCalls.values()).iterator(); } } diff --git a/src/net/java/sip/communicator/service/protocol/event/RegistrationStateChangeListener.java b/src/net/java/sip/communicator/service/protocol/event/RegistrationStateChangeListener.java index aba6456..3b4d56d 100644 --- a/src/net/java/sip/communicator/service/protocol/event/RegistrationStateChangeListener.java +++ b/src/net/java/sip/communicator/service/protocol/event/RegistrationStateChangeListener.java @@ -10,8 +10,7 @@ import java.util.*; /** * An event listener that should be implemented by parties interested in changes - * that occur in the registration state of a - * <code>ProtocolProviderService</code>. + * that occur in the registration state of a <tt>ProtocolProviderService</tt>. * * @author Emil Ivov */ @@ -19,12 +18,11 @@ public interface RegistrationStateChangeListener extends EventListener { /** - * The method is called by a <code>ProtocolProviderService</code> - * implementation whenever a change in the registration state of the - * corresponding provider had occurred. + * The method is called by a <tt>ProtocolProviderService</tt> implementation + * whenever a change in its registration state has occurred. * - * @param evt - * the event describing the status change. + * @param evt a <tt>RegistrationStateChangeEvent</tt> which describes the + * registration state change. */ public void registrationStateChanged(RegistrationStateChangeEvent evt); } diff --git a/src/net/java/sip/communicator/service/protocol/media/AbstractOperationSetTelephonyConferencing.java b/src/net/java/sip/communicator/service/protocol/media/AbstractOperationSetTelephonyConferencing.java index 3b31144..9d6812c 100644 --- a/src/net/java/sip/communicator/service/protocol/media/AbstractOperationSetTelephonyConferencing.java +++ b/src/net/java/sip/communicator/service/protocol/media/AbstractOperationSetTelephonyConferencing.java @@ -526,63 +526,38 @@ public abstract class AbstractOperationSetTelephonyConferencing< MediaAwareCallPeer<?,?,?> callPeer, MediaType mediaType) { - MediaStream stream = callPeer.getMediaHandler().getStream(mediaType); - long remoteSourceID; + long remoteSourceID + = callPeer.getMediaHandler().getRemoteSSRC(mediaType); - if (stream != null) + if (remoteSourceID != -1) { - remoteSourceID = stream.getRemoteSourceID(); - if (remoteSourceID != -1) - { - /* - * TODO Technically, we are detecting conflicts within a Call - * while we should be detecting them within the whole - * CallConference. - */ - MediaAwareCall<?,?,?> call = callPeer.getCall(); + /* + * TODO Technically, we are detecting conflicts within a Call + * while we should be detecting them within the whole + * CallConference. + */ + MediaAwareCall<?,?,?> call = callPeer.getCall(); - if (call != null) + if (call != null) + { + for (MediaAwareCallPeer<?,?,?> aCallPeer + : call.getCallPeerList()) { - for (MediaAwareCallPeer<?,?,?> aCallPeer - : call.getCallPeerList()) + if (aCallPeer != callPeer) { - if (aCallPeer != callPeer) + long aRemoteSourceID + = aCallPeer.getMediaHandler().getRemoteSSRC( + mediaType); + + if (aRemoteSourceID == remoteSourceID) { - MediaStream aStream - = aCallPeer.getMediaHandler().getStream( - mediaType); - - /* - * When the Jitsi VideoBridge server-side technology - * is utilized by the local peer/user to host a - * telephony conference, one and the same - * MediaStream instance will be shared by the - * CallPeers. This will definitely lead to a - * conflict. - */ - if (aStream == stream) - { - remoteSourceID = -1; - break; - } - else - { - long aRemoteSourceID - = stream.getRemoteSourceID(); - - if (aRemoteSourceID == remoteSourceID) - { - remoteSourceID = -1; - break; - } - } + remoteSourceID = -1; + break; } } } } } - else - remoteSourceID = -1; return remoteSourceID; } @@ -706,15 +681,15 @@ public abstract class AbstractOperationSetTelephonyConferencing< * Notifies this <tt>PropertyChangeListener</tt> that the value of a * specific property of the notifier it is registered with has changed. * - * @param event a <tt>PropertyChangeEvent</tt> which describes the source of + * @param ev a <tt>PropertyChangeEvent</tt> which describes the source of * the event, the name of the property which has changed its value and the * old and new values of the property * @see PropertyChangeListener#propertyChange(PropertyChangeEvent) */ @SuppressWarnings("unchecked") - public void propertyChange(PropertyChangeEvent event) + public void propertyChange(PropertyChangeEvent ev) { - String propertyName = event.getPropertyName(); + String propertyName = ev.getPropertyName(); if (CallPeerMediaHandler.AUDIO_LOCAL_SSRC.equals( propertyName) @@ -726,8 +701,7 @@ public abstract class AbstractOperationSetTelephonyConferencing< propertyName)) { Call call - = ((CallPeerMediaHandler<MediaAwareCallPeerT>) - event.getSource()) + = ((CallPeerMediaHandler<MediaAwareCallPeerT>) ev.getSource()) .getPeer() .getCall(); 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 f5c4c98..7702c42 100644 --- a/src/net/java/sip/communicator/service/protocol/media/CallPeerMediaHandler.java +++ b/src/net/java/sip/communicator/service/protocol/media/CallPeerMediaHandler.java @@ -606,15 +606,15 @@ public abstract class CallPeerMediaHandler } /** - * Gets the last-known remote SSRC of the audio <tt>MediaStream</tt> of this - * instance. + * Gets the last-known SSRC of an RTP stream with a specific + * <tt>MediaType</tt> received by a <tt>MediaStream</tt> of this instance. * - * @return the last-known remote SSRC of the audio <tt>MediaStream</tt> of - * this instance + * @return the last-known SSRC of an RTP stream with a specific + * <tt>MediaType</tt> received by a <tt>MediaStream</tt> of this instance */ - public long getAudioRemoteSSRC() + public long getRemoteSSRC(MediaType mediaType) { - return mediaHandler.getRemoteSSRC(this, MediaType.AUDIO); + return mediaHandler.getRemoteSSRC(this, mediaType); } /** @@ -1032,14 +1032,18 @@ public abstract class CallPeerMediaHandler synchronized (localAudioLevelListenerLock) { if (localAudioLevelListener != null) + { audioStream.setLocalUserAudioLevelListener( localAudioLevelListener); + } } synchronized (streamAudioLevelListenerLock) { if (streamAudioLevelListener != null) + { audioStream.setStreamAudioLevelListener( streamAudioLevelListener); + } } synchronized (csrcAudioLevelListenerLock) { diff --git a/src/net/java/sip/communicator/service/protocol/media/DynamicRTPExtensionsRegistry.java b/src/net/java/sip/communicator/service/protocol/media/DynamicRTPExtensionsRegistry.java index 9a9e654..5c03c0c 100644 --- a/src/net/java/sip/communicator/service/protocol/media/DynamicRTPExtensionsRegistry.java +++ b/src/net/java/sip/communicator/service/protocol/media/DynamicRTPExtensionsRegistry.java @@ -192,7 +192,7 @@ public class DynamicRTPExtensionsRegistry { throw new IllegalStateException( "Impossible to map more than the 255 already mapped " - +" RTP extensions"); + +" RTP extensions"); } byte extID = nextExtensionMapping++; diff --git a/src/net/java/sip/communicator/service/protocol/media/MediaAwareCallPeer.java b/src/net/java/sip/communicator/service/protocol/media/MediaAwareCallPeer.java index 92b2b25..55054ea 100644 --- a/src/net/java/sip/communicator/service/protocol/media/MediaAwareCallPeer.java +++ b/src/net/java/sip/communicator/service/protocol/media/MediaAwareCallPeer.java @@ -773,10 +773,10 @@ public abstract class MediaAwareCallPeer if (getConferenceMemberCount() > 2) { // this peer is now a conference focus with more than three - // participants. This means that the this peer is mixing and sending - // us audio for at least two separate participants. We therefore - // need to remove the stream level listeners and switch to CSRC - // level listening + // participants. This means that this peer is mixing and sending us + // audio for at least two separate participants. We therefore need + // to remove the stream level listeners and switch to CSRC level + // listening CallPeerMediaHandler<?> mediaHandler = getMediaHandler(); mediaHandler.setStreamAudioLevelListener(null); @@ -839,7 +839,8 @@ public abstract class MediaAwareCallPeer && ((conferenceMemberCount = getConferenceMemberCount()) > 0) && (conferenceMemberCount < 3)) { - long audioRemoteSSRC = getMediaHandler().getAudioRemoteSSRC(); + long audioRemoteSSRC + = getMediaHandler().getRemoteSSRC(MediaType.AUDIO); if (audioRemoteSSRC != CallPeerMediaHandler.SSRC_UNKNOWN) { @@ -873,9 +874,11 @@ public abstract class MediaAwareCallPeer = streamAudioLevelListeners.size(); for(int i = 0; i < streamAudioLevelListenerCount; i++) + { streamAudioLevelListeners.get(i).soundLevelChanged( this, newLevel); + } } } diff --git a/src/net/java/sip/communicator/service/protocol/media/MediaHandler.java b/src/net/java/sip/communicator/service/protocol/media/MediaHandler.java index 5211d80..c5e2632 100644 --- a/src/net/java/sip/communicator/service/protocol/media/MediaHandler.java +++ b/src/net/java/sip/communicator/service/protocol/media/MediaHandler.java @@ -149,26 +149,34 @@ public class MediaHandler Object source = evt.getSource(); if (source == audioStream) + { setLocalSSRC( MediaType.AUDIO, audioStream.getLocalSourceID()); + } else if (source == videoStream) + { setLocalSSRC( MediaType.VIDEO, videoStream.getLocalSourceID()); + } } else if (MediaStream.PNAME_REMOTE_SSRC.equals(propertyName)) { Object source = evt.getSource(); if (source == audioStream) + { setRemoteSSRC( MediaType.AUDIO, audioStream.getRemoteSourceID()); + } else if (source == videoStream) + { setRemoteSSRC( MediaType.VIDEO, videoStream.getRemoteSourceID()); + } } } }; @@ -817,8 +825,7 @@ public class MediaHandler { this.audioStream .removePropertyChangeListener( - streamPropertyChangeListener); - + streamPropertyChangeListener); this.audioStream.close(); } @@ -831,7 +838,7 @@ public class MediaHandler { this.audioStream .addPropertyChangeListener( - streamPropertyChangeListener); + streamPropertyChangeListener); audioLocalSSRC = this.audioStream.getLocalSourceID(); audioRemoteSSRC = this.audioStream.getRemoteSourceID(); } 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 6106360..ede1b3a 100644 --- a/src/net/java/sip/communicator/service/protocol/media/TransportManager.java +++ b/src/net/java/sip/communicator/service/protocol/media/TransportManager.java @@ -7,7 +7,6 @@ package net.java.sip.communicator.service.protocol.media; import java.net.*; -import java.util.*; import net.java.sip.communicator.service.netaddr.*; import net.java.sip.communicator.service.protocol.*; |