diff options
author | Lyubomir Marinov <lyubomir.marinov@jitsi.org> | 2013-11-13 22:42:37 +0200 |
---|---|---|
committer | Lyubomir Marinov <lyubomir.marinov@jitsi.org> | 2013-11-14 01:12:59 +0200 |
commit | 755b17033e7ee6395aa7a140d78e365b6f429c58 (patch) | |
tree | b3fd2265989b7e38d812e6eb8b3221cb4a113851 /src/net/java/sip/communicator/impl/protocol/jabber/OperationSetTelephonyConferencingJabberImpl.java | |
parent | c307d5ebab5e5f20c5550d6bf341731b8b47497a (diff) | |
download | jitsi-755b17033e7ee6395aa7a140d78e365b6f429c58.zip jitsi-755b17033e7ee6395aa7a140d78e365b6f429c58.tar.gz jitsi-755b17033e7ee6395aa7a140d78e365b6f429c58.tar.bz2 |
Fixes warnings, formatting, naming consistency.
Diffstat (limited to 'src/net/java/sip/communicator/impl/protocol/jabber/OperationSetTelephonyConferencingJabberImpl.java')
-rw-r--r-- | src/net/java/sip/communicator/impl/protocol/jabber/OperationSetTelephonyConferencingJabberImpl.java | 1147 |
1 files changed, 570 insertions, 577 deletions
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 2961bef..9adc434 100644 --- a/src/net/java/sip/communicator/impl/protocol/jabber/OperationSetTelephonyConferencingJabberImpl.java +++ b/src/net/java/sip/communicator/impl/protocol/jabber/OperationSetTelephonyConferencingJabberImpl.java @@ -1,577 +1,570 @@ -/* - * Jitsi, the OpenSource Java VoIP and Instant Messaging client. - * - * Distributable under LGPL license. - * See terms of license at gnu.org. - */ -package net.java.sip.communicator.impl.protocol.jabber; - -import java.util.*; - -import net.java.sip.communicator.impl.protocol.jabber.extensions.coin.*; -import net.java.sip.communicator.impl.protocol.jabber.extensions.jingle.*; -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.jitsi.util.xml.*; -import org.jivesoftware.smack.*; -import org.jivesoftware.smack.filter.*; -import org.jivesoftware.smack.packet.*; -import org.jivesoftware.smack.packet.IQ.Type; -import org.jivesoftware.smack.util.*; -import org.jivesoftware.smackx.packet.*; - -/** - * Implements <tt>OperationSetTelephonyConferencing</tt> for Jabber. - * - * @author Lyubomir Marinov - * @author Sebastien Vincent - * @author Boris Grozev - */ -public class OperationSetTelephonyConferencingJabberImpl - extends AbstractOperationSetTelephonyConferencing< - ProtocolProviderServiceJabberImpl, - OperationSetBasicTelephonyJabberImpl, - CallJabberImpl, - CallPeerJabberImpl, - String> - implements RegistrationStateChangeListener, - PacketListener, - PacketFilter - -{ - /** - * The <tt>Logger</tt> used by the - * <tt>OperationSetTelephonyConferencingJabberImpl</tt> class and its - * instances for logging output. - */ - private static final Logger logger - = Logger.getLogger(OperationSetTelephonyConferencingJabberImpl.class); - - /** - * The minimum interval in milliseconds between COINs sent to a single - * <tt>CallPeer</tt>. - */ - private static final int COIN_MIN_INTERVAL = 200; - - /** - * Synchronization object. - */ - private final Object lock = new Object(); - - /** - * Initializes a new <tt>OperationSetTelephonyConferencingJabberImpl</tt> - * instance which is to provide telephony conferencing services for the - * specified Jabber <tt>ProtocolProviderService</tt> implementation. - * - * @param parentProvider the Jabber <tt>ProtocolProviderService</tt> - * implementation which has requested the creation of the new instance and - * for which the new instance is to provide telephony conferencing services - */ - public OperationSetTelephonyConferencingJabberImpl( - ProtocolProviderServiceJabberImpl parentProvider) - { - super(parentProvider); - } - - /** - * Notifies all <tt>CallPeer</tt>s associated with a specific <tt>Call</tt> - * about changes in the telephony conference-related information. In - * contrast, {@link #notifyAll()} notifies all <tt>CallPeer</tt>s associated - * with the telephony conference in which a specific <tt>Call</tt> is - * participating. - * - * @param call the <tt>Call</tt> whose <tt>CallPeer</tt>s are to be notified - * about changes in the telephony conference-related information - */ - @Override - protected void notifyCallPeers(Call call) - { - if (call.isConferenceFocus()) - { - synchronized (lock) - { - // send conference-info to all CallPeers of the specified call. - for (Iterator<? extends CallPeer> i = call.getCallPeers(); - i.hasNext();) - { - notify(i.next()); - } - } - } - } - - /** - * Notifies a specific <tt>CallPeer</tt> about changes in the telephony - * conference-related information. - * - * @param callPeer the <tt>CallPeer</tt> to notify. - */ - private void notify(CallPeer callPeer) - { - if(!(callPeer instanceof CallPeerJabberImpl)) - return; - - //Don't send COINs to peers with might not be ready to accept COINs yet - CallPeerState peerState = callPeer.getState(); - if (peerState == CallPeerState.CONNECTING - || peerState == CallPeerState.UNKNOWN - || peerState == CallPeerState.INITIATING_CALL - || peerState == CallPeerState.DISCONNECTED - || peerState == CallPeerState.FAILED) - return; - - final CallPeerJabberImpl callPeerJabber = (CallPeerJabberImpl)callPeer; - - final long timeSinceLastCoin = System.currentTimeMillis() - - callPeerJabber.getLastConferenceInfoSentTimestamp(); - if (timeSinceLastCoin < COIN_MIN_INTERVAL) - { - if (callPeerJabber.isConfInfoScheduled()) - return; - - logger.info("Scheduling to send a COIN to " + callPeerJabber); - callPeerJabber.setConfInfoScheduled(true); - new Thread(new Runnable(){ - @Override - public void run() - { - try - { - Thread.sleep(1 + COIN_MIN_INTERVAL - timeSinceLastCoin); - } - catch (InterruptedException ie) {} - - OperationSetTelephonyConferencingJabberImpl.this - .notify(callPeerJabber); - } - }).start(); - - return; - } - - // check that callPeer supports COIN before sending him a - // conference-info - String to = getBasicTelephony().getFullCalleeURI(callPeer.getAddress()); - - // XXX if this generates actual disco#info requests we might want to - // cache it. - try - { - DiscoverInfo discoverInfo - = parentProvider.getDiscoveryManager().discoverInfo(to); - - if (!discoverInfo.containsFeature( - ProtocolProviderServiceJabberImpl.URN_XMPP_JINGLE_COIN)) - { - logger.info(callPeer.getAddress() + " does not support COIN"); - callPeerJabber.setConfInfoScheduled(false); - return; - } - } - catch (XMPPException xmppe) - { - logger.warn("Failed to retrieve DiscoverInfo for " + to, xmppe); - } - - ConferenceInfoDocument currentConfInfo - = getCurrentConferenceInfo(callPeerJabber); - ConferenceInfoDocument lastSentConfInfo - = callPeerJabber.getLastConferenceInfoSent(); - - ConferenceInfoDocument diff; - - if (lastSentConfInfo == null) - diff = currentConfInfo; - else - diff = getConferenceInfoDiff(lastSentConfInfo, currentConfInfo); - - if (diff != null) - { - int newVersion - = lastSentConfInfo == null - ? 1 - : lastSentConfInfo.getVersion() + 1; - diff.setVersion(newVersion); - - IQ iq = getConferenceInfo(callPeerJabber, diff); - - if (iq != null) - { - parentProvider.getConnection().sendPacket(iq); - - // We save currentConfInfo, because it is of state "full", while - // diff could be a partial - currentConfInfo.setVersion(newVersion); - callPeerJabber.setLastConferenceInfoSent(currentConfInfo); - callPeerJabber.setLastConferenceInfoSentTimestamp( - System.currentTimeMillis()); - } - } - callPeerJabber.setConfInfoScheduled(false); - } - - /** - * Generates the conference-info IQ to be sent to a specific - * <tt>CallPeer</tt> in order to notify it of the current state of the - * conference managed by the local peer. - * - * @param callPeer the <tt>CallPeer</tt> to generate conference-info XML for - * @param confInfo the <tt>ConferenceInformationDocument</tt> which is to be - * included in the IQ - * @return the conference-info IQ to be sent to the specified - * <tt>callPeer</tt> in order to notify it of the current state of the - * conference managed by the local peer - */ - private IQ getConferenceInfo(CallPeerJabberImpl callPeer, - final ConferenceInfoDocument confInfo) - { - String callPeerSID = callPeer.getSID(); - - if (callPeerSID == null) - return null; - - IQ iq = new IQ(){ - @Override - public String getChildElementXML() - { - return confInfo.toXml(); - } - }; - - CallJabberImpl call = callPeer.getCall(); - - iq.setFrom(call.getProtocolProvider().getOurJID()); - iq.setTo(callPeer.getAddress()); - iq.setType(Type.SET); - - return iq; - } - - /** - * Implementation of method <tt>registrationStateChange</tt> from - * interface RegistrationStateChangeListener for setting up (or down) - * our <tt>JingleManager</tt> when an <tt>XMPPConnection</tt> is available - * - * @param evt the event received - */ - @Override - public void registrationStateChanged(RegistrationStateChangeEvent evt) - { - super.registrationStateChanged(evt); - - RegistrationState registrationState = evt.getNewState(); - - if (RegistrationState.REGISTERED.equals(registrationState)) - { - if(logger.isDebugEnabled()) - logger.debug("Subscribes to Coin packets"); - subscribeForCoinPackets(); - } - else if (RegistrationState.UNREGISTERED.equals(registrationState)) - { - if(logger.isDebugEnabled()) - logger.debug("Unsubscribes to Coin packets"); - unsubscribeForCoinPackets(); - } - } - - /** - * Creates a new outgoing <tt>Call</tt> into which conference callees are to - * be invited by this <tt>OperationSetTelephonyConferencing</tt>. - * - * @return a new outgoing <tt>Call</tt> into which conference callees are to - * be invited by this <tt>OperationSetTelephonyConferencing</tt> - * @throws OperationFailedException if anything goes wrong - */ - @Override - protected CallJabberImpl createOutgoingCall() - throws OperationFailedException - { - return new CallJabberImpl(getBasicTelephony()); - } - - /** - * {@inheritDoc} - * - * Implements the protocol-dependent part of the logic of inviting a callee - * to a <tt>Call</tt>. The protocol-independent part of that logic is - * implemented by - * {@link AbstractOperationSetTelephonyConferencing#inviteCalleeToCall(String,Call)}. - */ - @Override - protected CallPeer doInviteCalleeToCall( - String calleeAddress, - CallJabberImpl call) - throws OperationFailedException - { - return - getBasicTelephony().createOutgoingCall( - call, - calleeAddress, - Arrays.asList( - new PacketExtension[] - { - new CoinPacketExtension(true) - })); - } - - /** - * Parses a <tt>String</tt> value which represents a callee address - * specified by the user into an object which is to actually represent the - * callee during the invitation to a conference <tt>Call</tt>. - * - * @param calleeAddressString a <tt>String</tt> value which represents a - * callee address to be parsed into an object which is to actually represent - * the callee during the invitation to a conference <tt>Call</tt> - * @return an object which is to actually represent the specified - * <tt>calleeAddressString</tt> during the invitation to a conference - * <tt>Call</tt> - * @throws OperationFailedException if parsing the specified - * <tt>calleeAddressString</tt> fails - */ - @Override - protected String parseAddressString(String calleeAddressString) - throws OperationFailedException - { - return getBasicTelephony().getFullCalleeURI(calleeAddressString); - } - - /** - * Subscribes us to notifications about incoming Coin packets. - */ - private void subscribeForCoinPackets() - { - parentProvider.getConnection().addPacketListener(this, this); - } - - /** - * Unsubscribes us from notifications about incoming Coin packets. - */ - private void unsubscribeForCoinPackets() - { - XMPPConnection connection = parentProvider.getConnection(); - - if (connection != null) - connection.removePacketListener(this); - } - - /** - * Tests whether or not the specified packet should be handled by this - * operation set. This method is called by smack prior to packet delivery - * and it would only accept <tt>CoinIQ</tt>s. - * - * @param packet the packet to test. - * @return true if and only if <tt>packet</tt> passes the filter. - */ - public boolean accept(Packet packet) - { - return (packet instanceof CoinIQ); - } - - /** - * Handles incoming jingle packets and passes them to the corresponding - * method based on their action. - * - * @param packet the packet to process. - */ - public void processPacket(Packet packet) - { - CoinIQ coinIQ = (CoinIQ) packet; - String errorMessage = null; - - //first ack all "set" requests. - IQ.Type type = coinIQ.getType(); - if (type == IQ.Type.SET) - { - IQ ack = IQ.createResultIQ(coinIQ); - - parentProvider.getConnection().sendPacket(ack); - } - else if(type == IQ.Type.ERROR) - { - XMPPError error = coinIQ.getError(); - if(error != null) - { - String msg = error.getMessage(); - errorMessage = ((msg != null)? (msg + " ") : "") - + "Error code: " + error.getCode(); - } - - logger.error("Received error in COIN packet. "+errorMessage); - } - - String sid = coinIQ.getSID(); - - if (sid != null) - { - CallPeerJabberImpl callPeer - = getBasicTelephony().getActiveCallsRepository().findCallPeer( - sid); - - - if (callPeer != null) - { - if(type == IQ.Type.ERROR) - { - callPeer.fireConferenceMemberErrorEvent(errorMessage); - return; - } - - if (logger.isDebugEnabled()) - logger.debug("Processing COIN from " + coinIQ.getFrom() - + " (version=" + coinIQ.getVersion() + ")"); - - handleCoin(callPeer, coinIQ); - } - } - } - - /** - * Handles a specific <tt>CoinIQ</tt> sent from a specific - * <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(CallPeerJabberImpl callPeer, CoinIQ coinIQ) - { - try - { - setConferenceInfoXML(callPeer, coinIQ.getChildElementXML()); - } - catch (XMLException e) - { - logger.error("Could not handle received COIN from " + callPeer - + ": " + coinIQ); - } - } - - /** - * {@inheritDoc} - * - * For COINs (XEP-0298), we use the attributes of the - * <tt>conference-info</tt> element to piggyback a Jingle SID. This is - * temporary and should be removed once we choose a better way to pass the - * SID. - */ - protected ConferenceInfoDocument getCurrentConferenceInfo( - MediaAwareCallPeer callPeer) - { - ConferenceInfoDocument confInfo - = super.getCurrentConferenceInfo(callPeer); - - if (callPeer instanceof CallPeerJabberImpl - && confInfo != null) - { - confInfo.setSid(((CallPeerJabberImpl)callPeer).getSID()); - } - return confInfo; - } - - /** - * {@inheritDoc} - */ - @Override - protected String getLocalEntity(CallPeer callPeer) - { - JingleIQ sessionIQ = ((CallPeerJabberImpl)callPeer).getSessionIQ(); - String from = sessionIQ.getFrom(); - String chatRoomName = StringUtils.parseBareAddress(from); - OperationSetMultiUserChatJabberImpl opSetMUC - = (OperationSetMultiUserChatJabberImpl)parentProvider.getOperationSet(OperationSetMultiUserChat.class); - ChatRoom room = null; - room = opSetMUC.getChatRoom(chatRoomName); - - if(room != null) - return "xmpp:" + chatRoomName + "/" + room.getUserNickname(); - - return "xmpp:" + parentProvider.getOurJID(); - } - - /** - * {@inheritDoc} - */ - @Override - protected String getLocalDisplayName() - { - return null; - } - - /** - * {@inheritDoc} - * - * The URI of the returned <tt>ConferenceDescription</tt> is the occupant - * JID with which we have joined the room. - * - * If a videobridge is available for our <tt>ProtocolProviderService</tt> - * we use it. TODO: this should be relaxed when we refactor the videobrdige - * implementation, so that any videobrdige (on any protocol provider) can - * be used. - * - */ - @Override - public ConferenceDescription setupConference(final ChatRoom chatRoom) - { - OperationSetVideoBridge videoBridge - = parentProvider.getOperationSet(OperationSetVideoBridge.class); - boolean isVideoBridge = (videoBridge != null) && videoBridge.isActive(); - - CallJabberImpl call = new CallJabberImpl(getBasicTelephony()); - call.setAutoAnswer(true); - - String uri = "xmpp:" + chatRoom.getIdentifier() + - "/" + chatRoom.getUserNickname(); - - ConferenceDescription cd - = new ConferenceDescription(uri, call.getCallID()); - - call.addCallChangeListener(new CallChangeListener() - { - - @Override - public void callStateChanged(CallChangeEvent evt) - { - if(CallState.CALL_ENDED.equals(evt.getNewValue())) - { - chatRoom.publishConference(null, null); - } - - } - - @Override - public void callPeerRemoved(CallPeerEvent evt) - { - - } - - @Override - public void callPeerAdded(CallPeerEvent evt) - { - - } - }); - if (isVideoBridge) - { - call.setConference(new MediaAwareCallConference(true)); - - - //For videobridge we set the transports to RAW-UDP, otherwise - //we leave them empty (meaning both RAW-UDP and ICE could be used) - cd.addTransport( - ProtocolProviderServiceJabberImpl.URN_XMPP_JINGLE_RAW_UDP_0); - } - - if (logger.isInfoEnabled()) - { - logger.info("Setup a conference with uri=" + uri + " and callid=" + - call.getCallID() + ". Videobridge in use: " + isVideoBridge); - } - - return cd; - } -} +/*
+ * Jitsi, the OpenSource Java VoIP and Instant Messaging client.
+ *
+ * Distributable under LGPL license.
+ * See terms of license at gnu.org.
+ */
+package net.java.sip.communicator.impl.protocol.jabber;
+
+import java.util.*;
+
+import net.java.sip.communicator.impl.protocol.jabber.extensions.coin.*;
+import net.java.sip.communicator.impl.protocol.jabber.extensions.jingle.*;
+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.jitsi.util.xml.*;
+import org.jivesoftware.smack.*;
+import org.jivesoftware.smack.filter.*;
+import org.jivesoftware.smack.packet.*;
+import org.jivesoftware.smack.packet.IQ.Type;
+import org.jivesoftware.smack.util.*;
+import org.jivesoftware.smackx.packet.*;
+
+/**
+ * Implements <tt>OperationSetTelephonyConferencing</tt> for Jabber.
+ *
+ * @author Lyubomir Marinov
+ * @author Sebastien Vincent
+ * @author Boris Grozev
+ */
+public class OperationSetTelephonyConferencingJabberImpl
+ extends AbstractOperationSetTelephonyConferencing<
+ ProtocolProviderServiceJabberImpl,
+ OperationSetBasicTelephonyJabberImpl,
+ CallJabberImpl,
+ CallPeerJabberImpl,
+ String>
+ implements RegistrationStateChangeListener,
+ PacketListener,
+ PacketFilter
+
+{
+ /**
+ * The <tt>Logger</tt> used by the
+ * <tt>OperationSetTelephonyConferencingJabberImpl</tt> class and its
+ * instances for logging output.
+ */
+ private static final Logger logger
+ = Logger.getLogger(OperationSetTelephonyConferencingJabberImpl.class);
+
+ /**
+ * The minimum interval in milliseconds between COINs sent to a single
+ * <tt>CallPeer</tt>.
+ */
+ private static final int COIN_MIN_INTERVAL = 200;
+
+ /**
+ * Synchronization object.
+ */
+ private final Object lock = new Object();
+
+ /**
+ * Initializes a new <tt>OperationSetTelephonyConferencingJabberImpl</tt>
+ * instance which is to provide telephony conferencing services for the
+ * specified Jabber <tt>ProtocolProviderService</tt> implementation.
+ *
+ * @param parentProvider the Jabber <tt>ProtocolProviderService</tt>
+ * implementation which has requested the creation of the new instance and
+ * for which the new instance is to provide telephony conferencing services
+ */
+ public OperationSetTelephonyConferencingJabberImpl(
+ ProtocolProviderServiceJabberImpl parentProvider)
+ {
+ super(parentProvider);
+ }
+
+ /**
+ * Notifies all <tt>CallPeer</tt>s associated with a specific <tt>Call</tt>
+ * about changes in the telephony conference-related information. In
+ * contrast, {@link #notifyAll()} notifies all <tt>CallPeer</tt>s associated
+ * with the telephony conference in which a specific <tt>Call</tt> is
+ * participating.
+ *
+ * @param call the <tt>Call</tt> whose <tt>CallPeer</tt>s are to be notified
+ * about changes in the telephony conference-related information
+ */
+ @Override
+ protected void notifyCallPeers(Call call)
+ {
+ if (call.isConferenceFocus())
+ {
+ synchronized (lock)
+ {
+ // send conference-info to all CallPeers of the specified call.
+ for (Iterator<? extends CallPeer> i = call.getCallPeers();
+ i.hasNext();)
+ {
+ notify(i.next());
+ }
+ }
+ }
+ }
+
+ /**
+ * Notifies a specific <tt>CallPeer</tt> about changes in the telephony
+ * conference-related information.
+ *
+ * @param callPeer the <tt>CallPeer</tt> to notify.
+ */
+ private void notify(CallPeer callPeer)
+ {
+ if(!(callPeer instanceof CallPeerJabberImpl))
+ return;
+
+ //Don't send COINs to peers with might not be ready to accept COINs yet
+ CallPeerState peerState = callPeer.getState();
+ if (peerState == CallPeerState.CONNECTING
+ || peerState == CallPeerState.UNKNOWN
+ || peerState == CallPeerState.INITIATING_CALL
+ || peerState == CallPeerState.DISCONNECTED
+ || peerState == CallPeerState.FAILED)
+ return;
+
+ final CallPeerJabberImpl callPeerJabber = (CallPeerJabberImpl)callPeer;
+
+ final long timeSinceLastCoin = System.currentTimeMillis()
+ - callPeerJabber.getLastConferenceInfoSentTimestamp();
+ if (timeSinceLastCoin < COIN_MIN_INTERVAL)
+ {
+ if (callPeerJabber.isConfInfoScheduled())
+ return;
+
+ logger.info("Scheduling to send a COIN to " + callPeerJabber);
+ callPeerJabber.setConfInfoScheduled(true);
+ new Thread(new Runnable(){
+ @Override
+ public void run()
+ {
+ try
+ {
+ Thread.sleep(1 + COIN_MIN_INTERVAL - timeSinceLastCoin);
+ }
+ catch (InterruptedException ie) {}
+
+ OperationSetTelephonyConferencingJabberImpl.this
+ .notify(callPeerJabber);
+ }
+ }).start();
+
+ return;
+ }
+
+ // check that callPeer supports COIN before sending him a
+ // conference-info
+ String to = getBasicTelephony().getFullCalleeURI(callPeer.getAddress());
+
+ // XXX if this generates actual disco#info requests we might want to
+ // cache it.
+ try
+ {
+ DiscoverInfo discoverInfo
+ = parentProvider.getDiscoveryManager().discoverInfo(to);
+
+ if (!discoverInfo.containsFeature(
+ ProtocolProviderServiceJabberImpl.URN_XMPP_JINGLE_COIN))
+ {
+ logger.info(callPeer.getAddress() + " does not support COIN");
+ callPeerJabber.setConfInfoScheduled(false);
+ return;
+ }
+ }
+ catch (XMPPException xmppe)
+ {
+ logger.warn("Failed to retrieve DiscoverInfo for " + to, xmppe);
+ }
+
+ ConferenceInfoDocument currentConfInfo
+ = getCurrentConferenceInfo(callPeerJabber);
+ ConferenceInfoDocument lastSentConfInfo
+ = callPeerJabber.getLastConferenceInfoSent();
+
+ ConferenceInfoDocument diff;
+
+ if (lastSentConfInfo == null)
+ diff = currentConfInfo;
+ else
+ diff = getConferenceInfoDiff(lastSentConfInfo, currentConfInfo);
+
+ if (diff != null)
+ {
+ int newVersion
+ = lastSentConfInfo == null
+ ? 1
+ : lastSentConfInfo.getVersion() + 1;
+ diff.setVersion(newVersion);
+
+ IQ iq = getConferenceInfo(callPeerJabber, diff);
+
+ if (iq != null)
+ {
+ parentProvider.getConnection().sendPacket(iq);
+
+ // We save currentConfInfo, because it is of state "full", while
+ // diff could be a partial
+ currentConfInfo.setVersion(newVersion);
+ callPeerJabber.setLastConferenceInfoSent(currentConfInfo);
+ callPeerJabber.setLastConferenceInfoSentTimestamp(
+ System.currentTimeMillis());
+ }
+ }
+ callPeerJabber.setConfInfoScheduled(false);
+ }
+
+ /**
+ * Generates the conference-info IQ to be sent to a specific
+ * <tt>CallPeer</tt> in order to notify it of the current state of the
+ * conference managed by the local peer.
+ *
+ * @param callPeer the <tt>CallPeer</tt> to generate conference-info XML for
+ * @param confInfo the <tt>ConferenceInformationDocument</tt> which is to be
+ * included in the IQ
+ * @return the conference-info IQ to be sent to the specified
+ * <tt>callPeer</tt> in order to notify it of the current state of the
+ * conference managed by the local peer
+ */
+ private IQ getConferenceInfo(CallPeerJabberImpl callPeer,
+ final ConferenceInfoDocument confInfo)
+ {
+ String callPeerSID = callPeer.getSID();
+
+ if (callPeerSID == null)
+ return null;
+
+ IQ iq = new IQ(){
+ @Override
+ public String getChildElementXML()
+ {
+ return confInfo.toXml();
+ }
+ };
+
+ CallJabberImpl call = callPeer.getCall();
+
+ iq.setFrom(call.getProtocolProvider().getOurJID());
+ iq.setTo(callPeer.getAddress());
+ iq.setType(Type.SET);
+
+ return iq;
+ }
+
+ /**
+ * Implementation of method <tt>registrationStateChange</tt> from
+ * interface RegistrationStateChangeListener for setting up (or down)
+ * our <tt>JingleManager</tt> when an <tt>XMPPConnection</tt> is available
+ *
+ * @param evt the event received
+ */
+ @Override
+ public void registrationStateChanged(RegistrationStateChangeEvent evt)
+ {
+ super.registrationStateChanged(evt);
+
+ RegistrationState registrationState = evt.getNewState();
+
+ if (RegistrationState.REGISTERED.equals(registrationState))
+ {
+ if(logger.isDebugEnabled())
+ logger.debug("Subscribes to Coin packets");
+ subscribeForCoinPackets();
+ }
+ else if (RegistrationState.UNREGISTERED.equals(registrationState))
+ {
+ if(logger.isDebugEnabled())
+ logger.debug("Unsubscribes to Coin packets");
+ unsubscribeForCoinPackets();
+ }
+ }
+
+ /**
+ * Creates a new outgoing <tt>Call</tt> into which conference callees are to
+ * be invited by this <tt>OperationSetTelephonyConferencing</tt>.
+ *
+ * @return a new outgoing <tt>Call</tt> into which conference callees are to
+ * be invited by this <tt>OperationSetTelephonyConferencing</tt>
+ * @throws OperationFailedException if anything goes wrong
+ */
+ @Override
+ protected CallJabberImpl createOutgoingCall()
+ throws OperationFailedException
+ {
+ return new CallJabberImpl(getBasicTelephony());
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * Implements the protocol-dependent part of the logic of inviting a callee
+ * to a <tt>Call</tt>. The protocol-independent part of that logic is
+ * implemented by
+ * {@link AbstractOperationSetTelephonyConferencing#inviteCalleeToCall(String,Call)}.
+ */
+ @Override
+ protected CallPeer doInviteCalleeToCall(
+ String calleeAddress,
+ CallJabberImpl call)
+ throws OperationFailedException
+ {
+ return
+ getBasicTelephony().createOutgoingCall(
+ call,
+ calleeAddress,
+ Arrays.asList(
+ new PacketExtension[]
+ {
+ new CoinPacketExtension(true)
+ }));
+ }
+
+ /**
+ * Parses a <tt>String</tt> value which represents a callee address
+ * specified by the user into an object which is to actually represent the
+ * callee during the invitation to a conference <tt>Call</tt>.
+ *
+ * @param calleeAddressString a <tt>String</tt> value which represents a
+ * callee address to be parsed into an object which is to actually represent
+ * the callee during the invitation to a conference <tt>Call</tt>
+ * @return an object which is to actually represent the specified
+ * <tt>calleeAddressString</tt> during the invitation to a conference
+ * <tt>Call</tt>
+ * @throws OperationFailedException if parsing the specified
+ * <tt>calleeAddressString</tt> fails
+ */
+ @Override
+ protected String parseAddressString(String calleeAddressString)
+ throws OperationFailedException
+ {
+ return getBasicTelephony().getFullCalleeURI(calleeAddressString);
+ }
+
+ /**
+ * Subscribes us to notifications about incoming Coin packets.
+ */
+ private void subscribeForCoinPackets()
+ {
+ parentProvider.getConnection().addPacketListener(this, this);
+ }
+
+ /**
+ * Unsubscribes us from notifications about incoming Coin packets.
+ */
+ private void unsubscribeForCoinPackets()
+ {
+ XMPPConnection connection = parentProvider.getConnection();
+
+ if (connection != null)
+ connection.removePacketListener(this);
+ }
+
+ /**
+ * Tests whether or not the specified packet should be handled by this
+ * operation set. This method is called by smack prior to packet delivery
+ * and it would only accept <tt>CoinIQ</tt>s.
+ *
+ * @param packet the packet to test.
+ * @return true if and only if <tt>packet</tt> passes the filter.
+ */
+ public boolean accept(Packet packet)
+ {
+ return (packet instanceof CoinIQ);
+ }
+
+ /**
+ * Handles incoming jingle packets and passes them to the corresponding
+ * method based on their action.
+ *
+ * @param packet the packet to process.
+ */
+ public void processPacket(Packet packet)
+ {
+ CoinIQ coinIQ = (CoinIQ) packet;
+ String errorMessage = null;
+
+ //first ack all "set" requests.
+ IQ.Type type = coinIQ.getType();
+ if (type == IQ.Type.SET)
+ {
+ IQ ack = IQ.createResultIQ(coinIQ);
+
+ parentProvider.getConnection().sendPacket(ack);
+ }
+ else if(type == IQ.Type.ERROR)
+ {
+ XMPPError error = coinIQ.getError();
+ if(error != null)
+ {
+ String msg = error.getMessage();
+ errorMessage = ((msg != null)? (msg + " ") : "")
+ + "Error code: " + error.getCode();
+ }
+
+ logger.error("Received error in COIN packet. "+errorMessage);
+ }
+
+ String sid = coinIQ.getSID();
+
+ if (sid != null)
+ {
+ CallPeerJabberImpl callPeer
+ = getBasicTelephony().getActiveCallsRepository().findCallPeer(
+ sid);
+
+
+ if (callPeer != null)
+ {
+ if(type == IQ.Type.ERROR)
+ {
+ callPeer.fireConferenceMemberErrorEvent(errorMessage);
+ return;
+ }
+
+ if (logger.isDebugEnabled())
+ logger.debug("Processing COIN from " + coinIQ.getFrom()
+ + " (version=" + coinIQ.getVersion() + ")");
+
+ handleCoin(callPeer, coinIQ);
+ }
+ }
+ }
+
+ /**
+ * Handles a specific <tt>CoinIQ</tt> sent from a specific
+ * <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(CallPeerJabberImpl callPeer, CoinIQ coinIQ)
+ {
+ try
+ {
+ setConferenceInfoXML(callPeer, coinIQ.getChildElementXML());
+ }
+ catch (XMLException e)
+ {
+ logger.error("Could not handle received COIN from " + callPeer
+ + ": " + coinIQ);
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * For COINs (XEP-0298), we use the attributes of the
+ * <tt>conference-info</tt> element to piggyback a Jingle SID. This is
+ * temporary and should be removed once we choose a better way to pass the
+ * SID.
+ */
+ protected ConferenceInfoDocument getCurrentConferenceInfo(
+ MediaAwareCallPeer callPeer)
+ {
+ ConferenceInfoDocument confInfo
+ = super.getCurrentConferenceInfo(callPeer);
+
+ if (callPeer instanceof CallPeerJabberImpl
+ && confInfo != null)
+ {
+ confInfo.setSid(((CallPeerJabberImpl)callPeer).getSID());
+ }
+ return confInfo;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ protected String getLocalEntity(CallPeer callPeer)
+ {
+ JingleIQ sessionIQ = ((CallPeerJabberImpl)callPeer).getSessionIQ();
+ String from = sessionIQ.getFrom();
+ String chatRoomName = StringUtils.parseBareAddress(from);
+ OperationSetMultiUserChatJabberImpl opSetMUC
+ = (OperationSetMultiUserChatJabberImpl)
+ parentProvider.getOperationSet(OperationSetMultiUserChat.class);
+ ChatRoom room = null;
+ room = opSetMUC.getChatRoom(chatRoomName);
+
+ if(room != null)
+ return "xmpp:" + chatRoomName + "/" + room.getUserNickname();
+
+ return "xmpp:" + parentProvider.getOurJID();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ protected String getLocalDisplayName()
+ {
+ return null;
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * The URI of the returned <tt>ConferenceDescription</tt> is the occupant
+ * JID with which we have joined the room.
+ *
+ * If a Videobridge is available for our <tt>ProtocolProviderService</tt>
+ * we use it. TODO: this should be relaxed when we refactor the Videobridge
+ * implementation, so that any Videobridge (on any protocol provider) can
+ * be used.
+ */
+ @Override
+ public ConferenceDescription setupConference(final ChatRoom chatRoom)
+ {
+ OperationSetVideoBridge videoBridge
+ = parentProvider.getOperationSet(OperationSetVideoBridge.class);
+ boolean isVideobridge = (videoBridge != null) && videoBridge.isActive();
+
+ CallJabberImpl call = new CallJabberImpl(getBasicTelephony());
+ call.setAutoAnswer(true);
+
+ String uri = "xmpp:" + chatRoom.getIdentifier() +
+ "/" + chatRoom.getUserNickname();
+
+ ConferenceDescription cd
+ = new ConferenceDescription(uri, call.getCallID());
+
+ call.addCallChangeListener(new CallChangeListener()
+ {
+ @Override
+ public void callStateChanged(CallChangeEvent ev)
+ {
+ if(CallState.CALL_ENDED.equals(ev.getNewValue()))
+ chatRoom.publishConference(null, null);
+ }
+
+ @Override
+ public void callPeerRemoved(CallPeerEvent ev)
+ {
+ }
+
+ @Override
+ public void callPeerAdded(CallPeerEvent ev)
+ {
+ }
+ });
+ if (isVideobridge)
+ {
+ call.setConference(new MediaAwareCallConference(true));
+
+ //For Jitsi Videobridge we set the transports to RAW-UDP, otherwise
+ //we leave them empty (meaning both RAW-UDP and ICE could be used)
+ cd.addTransport(
+ ProtocolProviderServiceJabberImpl.URN_XMPP_JINGLE_RAW_UDP_0);
+ }
+
+ if (logger.isInfoEnabled())
+ {
+ logger.info("Setup a conference with uri=" + uri + " and callid=" +
+ call.getCallID() + ". Videobridge in use: " + isVideobridge);
+ }
+
+ return cd;
+ }
+}
|