From 3294ef4ba326ae74df152acfdd7a6dcddb87986e Mon Sep 17 00:00:00 2001 From: Lyubomir Marinov Date: Tue, 27 Nov 2012 22:17:19 +0000 Subject: [PATCH] Allows the telephony conferences utilizing the Jitsi VideoBridge server-side technology to associate an RTP stream with the participant who is contributing it. Fixes multiple NullPointerExceptions in MediaStreamStatsImpl and OneToOneCallPeerPanel. Fixes an ArrayIndexOutOfBoundsException in AccountID. --- lib/installer-exclude/libjitsi.jar | Bin 1304751 -> 1304710 bytes .../impl/gui/main/call/CallPanel.java | 38 ++-- .../gui/main/call/OneToOneCallPeerPanel.java | 59 +++-- ...ctCallPeerMediaHandlerJabberGTalkImpl.java | 37 ++- .../impl/protocol/jabber/CallJabberImpl.java | 82 +++++++ .../protocol/jabber/CallPeerJabberImpl.java | 93 +++++--- .../CallPeerMediaHandlerJabberImpl.java | 148 +++++++++++- .../jabber/IceUdpTransportManager.java | 4 +- .../OperationSetBasicTelephonyJabberImpl.java | 202 +++++++++-------- ...ionSetTelephonyConferencingJabberImpl.java | 39 ++-- .../jabber/OperationSetVideoBridgeImpl.java | 213 ++++++++++++++++-- .../protocol/jabber/P2PTransportManager.java | 96 ++++---- .../jabber/RawUdpTransportManager.java | 7 +- .../extensions/caps/EntityCapsManager.java | 13 +- .../extensions/cobri/CobriConferenceIQ.java | 163 +++++++++++++- .../extensions/cobri/CobriIQProvider.java | 27 ++- .../service/protocol/AbstractCallPeer.java | 3 +- .../service/protocol/AccountID.java | 51 ++--- .../protocol/ActiveCallsRepository.java | 7 +- .../RegistrationStateChangeListener.java | 12 +- ...ractOperationSetTelephonyConferencing.java | 76 ++----- .../protocol/media/CallPeerMediaHandler.java | 16 +- .../media/DynamicRTPExtensionsRegistry.java | 2 +- .../protocol/media/MediaAwareCallPeer.java | 13 +- .../service/protocol/media/MediaHandler.java | 13 +- .../protocol/media/TransportManager.java | 1 - 26 files changed, 1008 insertions(+), 407 deletions(-) diff --git a/lib/installer-exclude/libjitsi.jar b/lib/installer-exclude/libjitsi.jar index da6d06c8db37ceb60b056e1c67f830c36d6752db..fdf66d3cd40b9e3a6a2a1c71c01da8283fee16be 100644 GIT binary patch delta 80001 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 D}VU$j-KJI2uhT4 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 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 f1d3466dc..e79b01b35 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 CallPanel(CallConference callConference, CallContainer callWindow) this.callConference = callConference; this.callWindow = callWindow; - uiVideoHandler = new UIVideoHandler2(callConference); + uiVideoHandler = new UIVideoHandler2(this.callConference); callDurationTimer = new Timer( @@ -345,9 +345,10 @@ public void actionPerformed(ActionEvent e) * 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 @@ else if (buttonName.equals(DIAL_BUTTON)) 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 @@ else if (buttonName.equals(INFO_BUTTON)) { 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 d04411beb..4897908cf 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 @@ private void createSoundLevelIndicators() = 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 @@ private void createSoundLevelIndicators() + "DISABLE_SOUND_LEVEL_INDICATORS", false)) { - this.callPeer.addStreamSoundLevelListener( + callPeer.addStreamSoundLevelListener( new SoundLevelListener() { public void soundLevelChanged(Object source, int level) @@ -347,15 +350,26 @@ public void soundLevelChanged(Object source, int level) 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 @@ private void initSecuritySettings() CallPeerSecurityStatusEvent securityEvent = callPeer.getCurrentSecuritySettings(); - if (securityEvent != null - && securityEvent instanceof CallPeerSecurityOnEvent) - { + if (securityEvent instanceof CallPeerSecurityOnEvent) securityOn((CallPeerSecurityOnEvent) securityEvent); - } } /** @@ -733,8 +744,10 @@ public void run() 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 8dfee62af..0e535b094 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 @@ protected SrtpCryptoAttribute selectSdesCryptoSuite( { List cryptoPacketExtensions = encryptionPacketExtension.getCryptoList(); - Vector peerAttributes - = new Vector(cryptoPacketExtensions.size()); + List peerAttributes + = new ArrayList(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 @@ protected void setAndAddPreferredEncryptionProtocol( RtpDescriptionPacketExtension remoteDescription) { // Sets ZRTP or SDES, depending on the preferences for this account. - List preferredEncryptionProtocols = getPeer() - .getProtocolProvider() - .getAccountID() - .getSortedEnabledEncryptionProtocolList(); + List 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 @@ protected void setAndAddPreferredEncryptionProtocol( 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 @@ else if(preferredEncryptionProtocols.get(i).equals( 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 213bf29bf..a7995f5c3 100644 --- a/src/net/java/sip/communicator/impl/protocol/jabber/CallJabberImpl.java +++ b/src/net/java/sip/communicator/impl/protocol/jabber/CallJabberImpl.java @@ -604,6 +604,88 @@ public void modifyVideoContent(boolean allowed) peer.sendModifyVideoContent(allowed); } + /** + * Notifies this instance that a specific CobriConferenceIQ has + * been received. + * + * @param conferenceIQ the CobriConferenceIQ which has been + * received + * @return true if the specified conferenceIQ was + * processed by this instance and no further processing is to be performed + * by other possible processors of CobriConferenceIQs; otherwise, + * false. Because a CobriConferenceIQ request sent from + * the Jitsi VideoBridge server to the application as its client concerns a + * specific CallJabberImpl implementation, no further processing by + * other CallJabberImpl instances is necessary once the + * CobriConferenceIQ is processed by the associated + * CallJabberImpl 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. * 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 4ec4dd004..b2632fc6f 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 @@ 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 synchronized void answer() try { - getMediaHandler().getTransportManager(). - wrapupConnectivityEstablishment(); - answer = getMediaHandler().generateSessionAccept(); + CallPeerMediaHandlerJabberImpl mediaHandler = getMediaHandler(); + + mediaHandler + .getTransportManager().wrapupConnectivityEstablishment(); + answer = mediaHandler.generateSessionAccept(); } catch(Exception exc) { @@ -361,6 +364,26 @@ protected synchronized void initiateSession( protocolProvider.getConnection().sendPacket(sessionInitIQ); } + /** + * Notifies this instance that a specific CobriConferenceIQ has + * been received. This CallPeerJabberImpl uses the part of the + * information provided in the specified conferenceIQ which + * concerns it only. + * + * @param conferenceIQ the CobriConferenceIQ 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}. * @@ -373,20 +396,27 @@ public void processContentAccept(JingleIQ content) 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 void processContentAdd(final JingleIQ content) { new Thread() { + @Override public void run() { try @@ -537,25 +568,27 @@ public void processContentModify(JingleIQ content) 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 void processSessionAccept(JingleIQ sessionInitIQ) 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 6af49cb27..eaa5563c9 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 @@ 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 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.*; /** @@ -142,6 +143,61 @@ public ContentPacketExtension getRemoteContent(String contentType) return null; } + /** + * {@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 CallPeer + * 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). * @@ -976,6 +1032,86 @@ private void removeContent( } } + /** + * Notifies this instance that a specific CobriConferenceIQ has + * been received. This CallPeerMediaHandler uses the part of the + * information provided in the specified conferenceIQ which + * concerns it only. + * + * @param conferenceIQ the CobriConferenceIQ 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 ContentPacketExtension and initialize its * corresponding MediaStream. @@ -986,7 +1122,7 @@ private void removeContent( * @throws OperationFailedException if we fail to handle content * for reasons like failing to initialize media devices or streams. * @throws IllegalArgumentException if there's a problem with the syntax or - * the semantics of content. Method is synchronized in order to + * the semantics of content. 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 @@ private void wrapupConnectivityEstablishment() /** * Returns the quality control for video calls if any. + * * @return the implemented quality control. */ public QualityControl getQualityControl() @@ -1695,6 +1832,7 @@ public QualityControl getQualityControl() /** * 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 void setSupportQualityControls(boolean value) /** * Closes the CallPeerMediaHandler. */ + @Override public synchronized void close() { super.close(); @@ -1721,16 +1860,17 @@ public synchronized void close() /** * Overrides to give access to the transport manager to send events * about ICE state changes. + * * @param property the name of the property of this * PropertyChangeNotifier 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 b2c9c468f..850183146 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 PacketExtension createTransport(IceMediaStream stream) for(Component component : stream.getComponents()) { - for(Candidate candidate : component.getLocalCandidates()) + for(Candidate candidate : component.getLocalCandidates()) trans.addCandidate(createCandidate(candidate)); } @@ -685,7 +685,7 @@ public PacketExtension createTransport(IceMediaStream stream) * @return a new {@link CandidatePacketExtension} corresponding to the state * of the candidate 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 053e51e25..0e5ae0db4 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 void registrationStateChanged(RegistrationStateChangeEvent evt) } else if (registrationState == RegistrationState.UNREGISTERED) { - // plug jingle unregistration unsubscribeForJinglePackets(); if (logger.isInfoEnabled()) @@ -751,14 +750,14 @@ private void subscribeForJinglePackets() } /** - * 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 @@ private void unsubscribeForJinglePackets() */ 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 boolean accept(Packet packet) 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 boolean accept(Packet packet) 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 @@ else if(packet instanceof SessionIQ) { 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 @@ else if(packet instanceof SessionIQ) */ 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 @@ private void processJingleIQ(final JingleIQ jingleIQ) 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 @@ private void processJingleIQ(final JingleIQ jingleIQ) 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 @@ && getFullCalleeURI(attendant.getAddress()) && protocolProvider.getOurJID().equals( transfer.getTo())) { - // OK transfer correspond to us + // OK, we are legally involved in the transfer. call = attendantCall; } } @@ -1000,18 +1002,16 @@ && getFullCalleeURI(attendant.getAddress()) } 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 @@ else if (action == JingleAction.SESSION_INFO) 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 @@ private void processSessionIQ(SessionIQ sessionIQ) // 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 511cc4399..3931c14f4 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 @@ private IQ getConferenceInfo(CallPeerJabberImpl callPeer, int version) * * @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 @@ private void subscribeForCoinPackets() } /** - * 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 @@ private void unsubscribeForCoinPackets() */ public boolean accept(Packet packet) { - if(!(packet instanceof CoinIQ)) - { - return false; - } - - return true; + return (packet instanceof CoinIQ); } /** @@ -487,17 +479,20 @@ public void processPacket(Packet packet) sid); if (callPeer != null) - handleCoin(coinIQ, callPeer); + handleCoin(callPeer, coinIQ); } } /** - * Handle Coin IQ. + * Handles a specific CoinIQ sent from a specific + * CallPeer. * - * @param coinIQ Coin IQ - * @param callPeer a CallPeer + * @param callPeer the CallPeer from which the specified + * CoinIQ was sent + * @param coinIQ the CoinIQ which was sent from the specified + * callPeer */ - 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 2408cd736..f4ff56b09 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 @@ 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 OperationSetVideoBridge for Jabber. * * @author Yana Stamcheva + * @author Lyubomir Marinov */ public class OperationSetVideoBridgeImpl - implements OperationSetVideoBridge + implements OperationSetVideoBridge, + PacketFilter, + PacketListener, + RegistrationStateChangeListener { /** - * The parent protocol provider. + * The Logger used by the OperationSetVideoBridgeImpl + * class and its instances for logging output. + */ + private static final Logger logger + = Logger.getLogger(OperationSetVideoBridgeImpl.class); + + /** + * The ProtocolProviderService 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}. + * OperationSetVideoBridgeImpl returns true if the + * specified packet is a {@link CobriConferenceIQ}; otherwise, + * false. + * + * @param packet the Packet to be determined whether this instance + * is interested in it + * @return true if the specified packet is a + * CobriConferenceIQ; otherwise, false + */ + public boolean accept(Packet packet) + { + return (packet instanceof CobriConferenceIQ); } /** @@ -54,12 +87,14 @@ public OperationSetVideoBridgeImpl(ProtocolProviderServiceJabberImpl */ 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 CallPeer inviteCalleeToCall(String uri, Call call) throws OperationFailedException, OperationNotSupportedException { - return protocolProvider.getOperationSet( - OperationSetTelephonyConferencing.class).inviteCalleeToCall( - uri, - call); + return + protocolProvider + .getOperationSet(OperationSetTelephonyConferencing.class) + .inviteCalleeToCall(uri, call); } /** @@ -100,7 +135,151 @@ public boolean isActive() { String jitsiVideoBridge = protocolProvider.getJitsiVideoBridge(); - return (jitsiVideoBridge != null - && jitsiVideoBridge.length() > 0); + return ((jitsiVideoBridge != null) && (jitsiVideoBridge.length() > 0)); + } + + /** + * Notifies this instance that a specific CobriConferenceIQ has + * been received. + * + * @param conferenceIQ the CobriConferenceIQ 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 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 true from {@link #accept(Packet)}) has been + * received. + * + * @param packet the Packet 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 RegistrationState + * of {@link #protocolProvider}. Subscribes this instance to + * {@link CobriConferenceIQ}s as soon as protocolProvider is + * registered and unsubscribes it as soon as protocolProvider 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 d56660e93..f8f028962 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 @@ * Google P2P TransportManager. * * @author Sebastien Vincent + * @author Lyubomir Marinov */ public class P2PTransportManager extends IceUdpTransportManager @@ -61,13 +62,16 @@ public P2PTransportManager(CallPeerJabberImpl callPeer) * @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 @@ protected Agent createIceAgent() * 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 @@ protected Agent createIceAgent() * TransportManagerJabberImpl * @see TransportManagerJabberImpl#getXmlNamespace() */ + @Override public String getXmlNamespace() { return "http://www.google.com/transport/p2p"; @@ -99,6 +104,7 @@ public String getXmlNamespace() * * @return PacketExtension */ + @Override protected PacketExtension getTransportPacketExtension() { return new GTalkTransportPacketExtension(); @@ -113,37 +119,46 @@ protected PacketExtension getTransportPacketExtension() * * @return the {@link GTalkTransportPacketExtension} */ + @Override public PacketExtension createTransport(IceMediaStream stream) { GTalkTransportPacketExtension trans = new GTalkTransportPacketExtension(); if(stream != null) + { for(Component component : stream.getComponents()) { - List candToRemove = - new ArrayList(); - List candidates = - component.getLocalCandidates(); + /* Remove the bases of the UPNP candidates. */ + List candidates + = component.getLocalCandidates(); + List 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( + 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 PacketExtension createTransport(IceMediaStream stream) * @return a new {@link CandidatePacketExtension} corresponding to the state * of the candidate 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 @@ private GTalkCandidatePacketExtension createCandidate(Candidate candidate) * {@link #wrapupCandidateHarvest()}. * @throws OperationFailedException in case we fail allocating ports */ + @Override public void startCandidateHarvest( - List ourOffer, - final TransportInfoSender transportInfoSender) + List ourOffer, + final TransportInfoSender transportInfoSender) throws OperationFailedException { final List offer = ourOffer; @@ -224,13 +234,11 @@ public void startCandidateHarvest( } for(ContentPacketExtension ourContent : offer) - { - ourContent.addChildExtension( - getTransportPacketExtension()); - } + ourContent.addChildExtension(getTransportPacketExtension()); new Thread() { + @Override public void run() { Collection transportInfoContents @@ -246,7 +254,8 @@ public void run() = ourContent.getFirstChildOfType( RtpDescriptionPacketExtension.class); - ourContent.addChildExtension(getTransportPacketExtension()); + ourContent.addChildExtension( + getTransportPacketExtension()); IceMediaStream stream = null; try @@ -275,7 +284,7 @@ public void run() transportInfoContents.add(transportInfoContent); transportInfoSender.sendTransportInfo( - transportInfoContents); + transportInfoContents); } } } @@ -303,28 +312,23 @@ public synchronized boolean startConnectivityEstablishment( 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 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 synchronized boolean startConnectivityEstablishment( 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 synchronized boolean startConnectivityEstablishment( for(IceMediaStream stream : iceAgent.getStreams()) { for(Component component : stream.getComponents()) - { component.updateRemoteCandidate(); - } } return false; @@ -399,7 +401,6 @@ public synchronized boolean startConnectivityEstablishment( GTalkTransportPacketExtension transport = content.getFirstChildOfType( GTalkTransportPacketExtension.class); - List candidates = transport.getChildExtensionsOfType( GTalkCandidatePacketExtension.class); @@ -440,7 +441,6 @@ public synchronized boolean startConnectivityEstablishment( */ if (candidate.getGeneration() != generation) continue; - if(candidate.getProtocol().equalsIgnoreCase("ssltcp")) continue; @@ -462,7 +462,7 @@ public synchronized boolean startConnectivityEstablishment( 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 dea530668..6af0f5865 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 MediaStreamTarget getStreamTarget(MediaType mediaType) * Gets the {@link CobriConferenceIQ.Channel} which belongs to a content * associated with a specific MediaType and is to be either locally * or remotely used. + *

+ * Note: Modifications to the CobriConferenceIQ.Channel + * instance returned by the method propagate to (the state of) this + * instance. + *

* * @param mediaType the MediaType associated with the content which * contains the CobriConferenceIQ.Channel to get @@ -348,7 +353,7 @@ public MediaStreamTarget getStreamTarget(MediaType mediaType) * in accord with the specified local indicator if such a channel * exists; otherwise, null */ - 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 b8e9bf057..301d4fdf7 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.packet.*; import org.xmlpull.mxp1.*; import org.xmlpull.v1.*; -// disambiguation /** * Keeps track of entity capabilities. @@ -35,7 +34,7 @@ * 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 void processPacket(Packet packet) /* 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 void processPacket(Packet packet) * 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 d44c6ca74..db23b3ae0 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 @@ -38,6 +38,13 @@ public class CobriConferenceIQ public static final String NAMESPACE = "http://jitsi.org/protocol/videobridge#conference"; + /** + * An array of longs which represents the lack of any (RTP) SSRCs + * seen/received on a Channel. Explicitly defined to reduce + * unnecessary allocations. + */ + public static final long[] NO_SSRCS = new long[0]; + /** * The list of {@link Content}s included into this conference IQ. */ @@ -233,6 +240,13 @@ public static class Channel */ 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 Channel. + */ + public static final String SSRC_ELEMENT_NAME = "ssrc"; + /** * The number of seconds of inactivity after which the channel * represented by this instance expires. @@ -266,6 +280,13 @@ public static class Channel */ private int rtpPort; + /** + * The list of (RTP) SSRCs which have been seen/received on this + * Channel 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 payload-type element defined by XEP-0167: Jingle RTP * Sessions to this channel. @@ -289,6 +310,33 @@ public boolean addPayloadType(PayloadTypePacketExtension payloadType) : payloadTypes.add(payloadType); } + /** + * Adds a specific (RTP) SSRC to the list of SSRCs seen/received on this + * Channel. 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 Channel + * @return true if the list of SSRCs seen/received on this + * Channel has been modified as part of the method call; + * otherwise, false + */ + 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 * channel represented by this instance expires. @@ -331,6 +379,18 @@ public int getRTPPort() return rtpPort; } + /** + * Gets (a copy of) the list of (RTP) SSRCs seen/received on this + * Channel. + * + * @return an array of longs which represents (a copy of) the + * list of (RTP) SSRCs seen/received on this Channel + */ + public synchronized long[] getSSRCs() + { + return (ssrcs.length == 0) ? NO_SSRCS : ssrcs.clone(); + } + /** * Removes a payload-type element defined by XEP-0167: Jingle * RTP Sessions from this channel. @@ -346,6 +406,54 @@ public boolean removePayloadType(PayloadTypePacketExtension payloadType) return payloadTypes.remove(payloadType); } + /** + * Removes a specific (RTP) SSRC from the list of SSRCs seen/received on + * this Channel. 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 Channel + * @return true if the list of SSRCs seen/received on this + * Channel has been modified as part of the method call; + * otherwise, false + */ + 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 * channel represented by this instance expires. @@ -389,6 +497,24 @@ public void setRTPPort(int rtpPort) this.rtpPort = rtpPort; } + /** + * Sets the list of (RTP) SSRCs seen/received on this Channel. + * + * @param ssrcs the list of (RTP) SSRCs to be set as seen/received on + * this Channel + */ + 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 void toXML(StringBuilder xml) 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 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("'); + } + } + xml.append("'); } else { - xml.append('>'); - for (PayloadTypePacketExtension payloadType : payloadTypes) - xml.append(payloadType.toXML()); - xml.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 aab8ad35c..54d4ccf2b 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 IQ parseIQ(XmlPullParser parser) CobriConferenceIQ.Channel channel = null; CobriConferenceIQ.Content content = null; PacketExtensionProvider payloadTypePacketExtensionProvider = null; + StringBuilder ssrc = null; while (!done) { @@ -64,14 +65,20 @@ public IQ parseIQ(XmlPullParser parser) { 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,8 +136,13 @@ else if (CobriConferenceIQ.Content.ELEMENT_NAME 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(); @@ -181,6 +193,13 @@ else if (PayloadTypePacketExtension.ELEMENT_NAME.equals( } 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 e490dd1c4..44f4a6828 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 void addConferenceMember(ConferenceMember conferenceMember) protected ConferenceMember findConferenceMember(long ssrc) { List 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 ba1cf8602..c37312089 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 boolean isEncryptionProtocolEnabled(String encryptionProtocolName) public List getSortedEnabledEncryptionProtocolList() { Map encryptionProtocols - = this.getIntegerPropertiesByPrefix( + = getIntegerPropertiesByPrefix( ProtocolProviderFactory.ENCRYPTION_PROTOCOL, true); Map 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 List getSortedEnabledEncryptionProtocolList() true); } - List sortedEncryptionProtocolList + List sortedEncryptionProtocols = new ArrayList(encryptionProtocols.size()); - Iterator names = encryptionProtocols.keySet().iterator(); - String name; - int index; + // First: add all protocol in the right order. - while(names.hasNext()) + for (Map.Entry 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 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 e1ceeb44a..ebe4008a7 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 Iterator getActiveCalls() { synchronized(activeCalls) { - return new LinkedList(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(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 aba64567a..3b4d56d25 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 @@ /** * An event listener that should be implemented by parties interested in changes - * that occur in the registration state of a - * ProtocolProviderService. + * that occur in the registration state of a ProtocolProviderService. * * @author Emil Ivov */ @@ -19,12 +18,11 @@ public interface RegistrationStateChangeListener extends EventListener { /** - * The method is called by a ProtocolProviderService - * implementation whenever a change in the registration state of the - * corresponding provider had occurred. + * The method is called by a ProtocolProviderService implementation + * whenever a change in its registration state has occurred. * - * @param evt - * the event describing the status change. + * @param evt a RegistrationStateChangeEvent 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 3b3114497..9d6812cac 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 @@ protected long getRemoteSourceID( 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 @@ protected abstract CalleeAddressT parseAddressString( * Notifies this PropertyChangeListener that the value of a * specific property of the notifier it is registered with has changed. * - * @param event a PropertyChangeEvent which describes the source of + * @param ev a PropertyChangeEvent 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 void propertyChange(PropertyChangeEvent event) propertyName)) { Call call - = ((CallPeerMediaHandler) - event.getSource()) + = ((CallPeerMediaHandler) 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 f5c4c982b..7702c420a 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 void startSrtpMultistream(SrtpControl master) } /** - * Gets the last-known remote SSRC of the audio MediaStream of this - * instance. + * Gets the last-known SSRC of an RTP stream with a specific + * MediaType received by a MediaStream of this instance. * - * @return the last-known remote SSRC of the audio MediaStream of - * this instance + * @return the last-known SSRC of an RTP stream with a specific + * MediaType received by a MediaStream 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 @@ void registerAudioLevelListeners(AudioMediaStream audioStream) 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 9a9e6541d..5c03c0cd4 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 @@ private byte nextExtensionID() { 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 92b2b255d..55054eacf 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 void conferenceMemberAdded(CallPeerConferenceEvent conferenceEvent) 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 void audioLevelChanged(int newLevel) && ((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 void audioLevelChanged(int newLevel) = 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 5211d80c6..c5e26327b 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 void propertyChange(PropertyChangeEvent evt) 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 @@ private void setAudioStream(AudioMediaStream audioStream) { this.audioStream .removePropertyChangeListener( - streamPropertyChangeListener); - + streamPropertyChangeListener); this.audioStream.close(); } @@ -831,7 +838,7 @@ private void setAudioStream(AudioMediaStream audioStream) { 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 61063609b..ede1b3aba 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.*;