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 34ebaa574..2c8922489 100644 --- a/src/net/java/sip/communicator/impl/protocol/jabber/OperationSetTelephonyConferencingJabberImpl.java +++ b/src/net/java/sip/communicator/impl/protocol/jabber/OperationSetTelephonyConferencingJabberImpl.java @@ -27,6 +27,7 @@ * * @author Lyubomir Marinov * @author Sebastien Vincent + * @author Boris Grozev */ public class OperationSetTelephonyConferencingJabberImpl extends AbstractOperationSetTelephonyConferencing< @@ -506,4 +507,42 @@ private void handleCoin(CallPeerJabberImpl callPeer, CoinIQ coinIQ) { setConferenceInfoXML(callPeer, -1, coinIQ.getChildElementXML()); } + + /** + * {@inheritDoc} + * + * For COINs (XEP-0298), we use the attributes of the + * conference-info 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(CallPeer callPeer) + { + ConferenceInfoDocument confInfo + = super.getCurrentConferenceInfo(callPeer); + + if (callPeer instanceof CallPeerJabberImpl) + { + confInfo.setSid(((CallPeerJabberImpl)callPeer).getSID()); + } + return confInfo; + } + + /** + * {@inheritDoc} + */ + @Override + protected String getLocalEntity(CallPeer callPeer) + { + return "xmpp:" + parentProvider.getOurJID(); + } + + /** + * {@inheritDoc} + */ + @Override + protected String getLocalDisplayName() + { + return null; + } } diff --git a/src/net/java/sip/communicator/impl/protocol/sip/OperationSetTelephonyConferencingSipImpl.java b/src/net/java/sip/communicator/impl/protocol/sip/OperationSetTelephonyConferencingSipImpl.java index 596b92b75..fa58e59c2 100644 --- a/src/net/java/sip/communicator/impl/protocol/sip/OperationSetTelephonyConferencingSipImpl.java +++ b/src/net/java/sip/communicator/impl/protocol/sip/OperationSetTelephonyConferencingSipImpl.java @@ -30,6 +30,7 @@ * Implements OperationSetTelephonyConferencing for SIP. * * @author Lyubomir Marinov + * @author Boris Grozev */ public class OperationSetTelephonyConferencingSipImpl extends AbstractOperationSetTelephonyConferencing< @@ -552,7 +553,7 @@ private void getUserXML(CallPeer callPeer, StringBuffer xml) * Implements the protocol-dependent part of the logic of inviting a callee * to a Call. The protocol-independent part of that logic is * implemented by - * {@link AbstractOperationSetTelephonyConferencing#inviteCalleToCall(String,Call)}. + * {@link AbstractOperationSetTelephonyConferencing#inviteCalleeToCall(String,Call)}. */ @Override protected CallPeerSipImpl doInviteCalleeToCall( @@ -1108,4 +1109,35 @@ protected void processTerminatedRequest( } } } + + /** + * {@inheritDoc} + */ + @Override + protected String getLocalEntity(CallPeer callPeer) + { + if (callPeer instanceof CallPeerSipImpl) + { + Dialog dialog = ((CallPeerSipImpl)callPeer).getDialog(); + + if (dialog != null) + { + Address localPartyAddress = dialog.getLocalParty(); + + if (localPartyAddress != null) + return stripParametersFromAddress( + localPartyAddress.getURI().toString()); + } + } + return null; + } + + /** + * {@inheritDoc} + */ + @Override + protected String getLocalDisplayName() + { + return parentProvider.getOurDisplayName(); + } } diff --git a/src/net/java/sip/communicator/service/protocol/AbstractCallPeer.java b/src/net/java/sip/communicator/service/protocol/AbstractCallPeer.java index 7a44d2009..a1fbf9976 100644 --- a/src/net/java/sip/communicator/service/protocol/AbstractCallPeer.java +++ b/src/net/java/sip/communicator/service/protocol/AbstractCallPeer.java @@ -131,6 +131,19 @@ public abstract class AbstractCallPeer unmodifiableConferenceMembers; + /** + * The last Conference Information (RFC4575) document sent to this + * CallPeer + */ + private ConferenceInfoDocument lastConferenceInfoSent = null; + + /** + * The time (as obtained by System.currentTimeMillis() at which + * a Conference Information (RFC4575) document was last sent to this + * CallPeer. + */ + private long lastConferenceInfoSentTimestamp = -1; + /** * Initializes a new AbstractCallPeer instance. */ 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 37be06b43..048f17bf8 100644 --- a/src/net/java/sip/communicator/service/protocol/media/AbstractOperationSetTelephonyConferencing.java +++ b/src/net/java/sip/communicator/service/protocol/media/AbstractOperationSetTelephonyConferencing.java @@ -33,6 +33,7 @@ * @param * * @author Lyubomir Marinov + * @author Boris Grozev */ public abstract class AbstractOperationSetTelephonyConferencing< ProtocolProviderServiceT extends ProtocolProviderService, @@ -993,4 +994,175 @@ protected static String stripParametersFromAddress(String address) } return address; } + + /** + * Creates a ConferenceInfoDocument which describes the current + * state of the conference in which callPeer participates. + * + * @return a ConferenceInfoDocument which describes the current + * state of the conference in which this CallPeer participates. + */ + protected ConferenceInfoDocument getCurrentConferenceInfo(CallPeer callPeer) + { + ConferenceInfoDocument confInfo; + try + { + confInfo = new ConferenceInfoDocument(); + } + catch (Exception e) + { + return null; + } + confInfo.setState(ConferenceInfoDocument.State.FULL); + confInfo.setEntity(getLocalEntity(callPeer)); + + Call call = callPeer.getCall(); + List conferenceCallPeers = CallConference.getCallPeers(call); + confInfo.setUserCount( + 1 /* the local peer/user */ + conferenceCallPeers.size()); + + /* The local user */ + addPeerToConferenceInfo(confInfo, callPeer, false); + + /* Remote users */ + for (CallPeer conferenceCallPeer : conferenceCallPeers) + addPeerToConferenceInfo(confInfo, conferenceCallPeer, true); + + return null; + } + + /** + * Adds a user element to confInfo which describes + * callPeer, or the local peer if remote is false. + * + * @param confInfo the ConferenceInformationDocument to which to + * add a user element + * @param callPeer the CallPeer which should be described + * @param remote true to describe callPeer, or + * false to describe the local peer. + */ + private void addPeerToConferenceInfo( + ConferenceInfoDocument confInfo, + CallPeer callPeer, + boolean remote) + { + String entity + = remote + ? callPeer.getURI() + : getLocalEntity(callPeer); + ConferenceInfoDocument.User user = confInfo.addNewUser(entity); + + String displayName + = remote + ? callPeer.getDisplayName() + : getLocalDisplayName(); + user.setDisplayText(displayName); + + ConferenceInfoDocument.Endpoint endpoint + = user.addNewEndpoint(entity); + + endpoint.setStatus( + remote + ? getEndpointStatus(callPeer) + : ConferenceInfoDocument.EndpointStatusType.connected); + + if (callPeer instanceof MediaAwareCallPeer) + { + MediaAwareCallPeer mediaAwarePeer + = (MediaAwareCallPeer) callPeer; + CallPeerMediaHandler mediaHandler + = mediaAwarePeer.getMediaHandler(); + int id = 1; + + for (MediaType mediaType : MediaType.values()) + { + MediaStream stream = mediaHandler.getStream(mediaType); + if (stream != null) + { + ConferenceInfoDocument.Media media + = endpoint.addNewMedia(Integer.toString(id)); + long srcId + = remote + ? getRemoteSourceID(mediaAwarePeer, mediaType) + : stream.getLocalSourceID(); + + if (srcId != -1) + media.setSrcId(Long.toString(srcId)); + + media.setType(mediaType.toString()); + + MediaDirection direction + = remote + ? getRemoteDirection(mediaAwarePeer, mediaType) + : stream.getDirection(); + + if (direction == null) + direction = MediaDirection.INACTIVE; + + media.setStatus(direction.toString()); + id++; + } + } + } + } + + /** + * Returns a string to be used for the entity attribute of the + * user element for the local peer, in a Conference Information + * document to be sent to callPeer + * + * @param callPeer The CallPeer for which we are creating a + * Conference Information document. + * @return a string to be used for the entity attribute of the + * user element for the local peer, in a Conference Information + * document to be sent to callPeer + */ + protected abstract String getLocalEntity(CallPeer callPeer); + + /** + * Returns the display name for the local peer, which is to be used when + * we send Conference Information. + * @return the display name for the local peer, which is to be used when + * we send Conference Information. + */ + protected abstract String getLocalDisplayName(); + + /** + * Gets the EndpointStatusType to use when describing + * callPeer in a Conference Information document. + * + * @param callPeer the CallPeer which is to get its state described + * in a status XML element of an endpoint XML element + * @return the EndpointStatusType to use when describing + * callPeer in a Conference Information document. + */ + private ConferenceInfoDocument.EndpointStatusType getEndpointStatus( + CallPeer callPeer) + { + CallPeerState callPeerState = callPeer.getState(); + + if (CallPeerState.ALERTING_REMOTE_SIDE.equals(callPeerState)) + return ConferenceInfoDocument.EndpointStatusType.alerting; + if (CallPeerState.CONNECTING.equals(callPeerState) + || CallPeerState + .CONNECTING_WITH_EARLY_MEDIA.equals(callPeerState)) + return ConferenceInfoDocument.EndpointStatusType.pending; + if (CallPeerState.DISCONNECTED.equals(callPeerState)) + return ConferenceInfoDocument.EndpointStatusType.disconnected; + if (CallPeerState.INCOMING_CALL.equals(callPeerState)) + return ConferenceInfoDocument.EndpointStatusType.dialing_in; + if (CallPeerState.INITIATING_CALL.equals(callPeerState)) + return ConferenceInfoDocument.EndpointStatusType.dialing_out; + + /* + * he/she is neither "hearing" the conference mix nor is his/her + * media being mixed in the conference + */ + if (CallPeerState.ON_HOLD_LOCALLY.equals(callPeerState) + || CallPeerState.ON_HOLD_MUTUALLY.equals(callPeerState)) + return ConferenceInfoDocument.EndpointStatusType.on_hold; + if (CallPeerState.CONNECTED.equals(callPeerState)) + return ConferenceInfoDocument.EndpointStatusType.connected; + return null; + } }