diff options
author | Sebastien Vincent <seb@jitsi.org> | 2011-04-01 09:50:31 +0000 |
---|---|---|
committer | Sebastien Vincent <seb@jitsi.org> | 2011-04-01 09:50:31 +0000 |
commit | 95788da2d130b6498719a325849b8ed318f9fdfc (patch) | |
tree | 461a8948ffa4f143563051245f3275099ceed6e8 | |
parent | f81ff286431c2965f705a7bdcacd22596d09b618 (diff) | |
download | jitsi-95788da2d130b6498719a325849b8ed318f9fdfc.zip jitsi-95788da2d130b6498719a325849b8ed318f9fdfc.tar.gz jitsi-95788da2d130b6498719a325849b8ed318f9fdfc.tar.bz2 |
Add Coin (Conference Information) support and audio levels in XMPP conference.
42 files changed, 3959 insertions, 355 deletions
diff --git a/src/net/java/sip/communicator/impl/gui/main/call/CallPanel.java b/src/net/java/sip/communicator/impl/gui/main/call/CallPanel.java index 95c3d19..6693901 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 @@ -766,9 +766,11 @@ public class CallPanel }); } - public void conferenceMemberAdded(CallPeerConferenceEvent conferenceEvent) {} + public void conferenceMemberAdded(CallPeerConferenceEvent conferenceEvent) + {} - public void conferenceMemberRemoved(CallPeerConferenceEvent conferenceEvent) {} + public void conferenceMemberRemoved(CallPeerConferenceEvent conferenceEvent) + {} /** * Checks if the contained call is a conference call. diff --git a/src/net/java/sip/communicator/impl/gui/main/call/conference/ConferencePeerPanel.java b/src/net/java/sip/communicator/impl/gui/main/call/conference/ConferencePeerPanel.java index 606e66c..0249b6a 100644 --- a/src/net/java/sip/communicator/impl/gui/main/call/conference/ConferencePeerPanel.java +++ b/src/net/java/sip/communicator/impl/gui/main/call/conference/ConferencePeerPanel.java @@ -37,6 +37,11 @@ public class ConferencePeerPanel Skinnable { /** + * Serial version UID. + */ + private static final long serialVersionUID = 0L; + + /** * The parent dialog containing this panel. */ private final CallPanel callPanel; diff --git a/src/net/java/sip/communicator/impl/neomedia/MediaUtils.java b/src/net/java/sip/communicator/impl/neomedia/MediaUtils.java index 178c306..6df5b53 100644 --- a/src/net/java/sip/communicator/impl/neomedia/MediaUtils.java +++ b/src/net/java/sip/communicator/impl/neomedia/MediaUtils.java @@ -200,9 +200,9 @@ public class MediaUtils /* H263+ */ Map<String, String> h263FormatParams - = new HashMap<String, String>(); + = new HashMap<String, String>(); Map<String, String> h263AdvancedAttributes - = new LinkedHashMap<String, String>(); + = new LinkedHashMap<String, String>(); // maximum resolution we can receive is the size of our screen device if(res != null) diff --git a/src/net/java/sip/communicator/impl/neomedia/device/VideoMediaDeviceSession.java b/src/net/java/sip/communicator/impl/neomedia/device/VideoMediaDeviceSession.java index 3b0f8a2..fc761d1 100644 --- a/src/net/java/sip/communicator/impl/neomedia/device/VideoMediaDeviceSession.java +++ b/src/net/java/sip/communicator/impl/neomedia/device/VideoMediaDeviceSession.java @@ -29,7 +29,7 @@ import net.java.sip.communicator.util.*; * Extends <tt>MediaDeviceSession</tt> to add video-specific functionality. * * @author Lubomir Marinov - * @author Sébastien Vincent + * @author Sebastien Vincent */ public class VideoMediaDeviceSession extends MediaDeviceSession 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 a73210f..cb49959 100644 --- a/src/net/java/sip/communicator/impl/protocol/jabber/CallJabberImpl.java +++ b/src/net/java/sip/communicator/impl/protocol/jabber/CallJabberImpl.java @@ -163,6 +163,19 @@ public class CallJabberImpl throw (ThreadDeath) t; } + CoinPacketExtension coin + = (CoinPacketExtension) + jingleIQ.getExtension( + CoinPacketExtension.ELEMENT_NAME, + CoinPacketExtension.NAMESPACE); + + if(coin != null) + { + boolean b = (Boolean.parseBoolean((String) + coin.getAttribute(CoinPacketExtension.ISFOCUS_ATTR_NAME))); + callPeer.setConferenceFocus(b); + } + //before notifying about this call, make sure that it looks alright callPeer.processSessionInitiate(jingleIQ); 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 fea2b2c..40d2c54 100644 --- a/src/net/java/sip/communicator/impl/protocol/jabber/CallPeerJabberImpl.java +++ b/src/net/java/sip/communicator/impl/protocol/jabber/CallPeerJabberImpl.java @@ -160,6 +160,25 @@ public class CallPeerJabberImpl try { getMediaHandler().processOffer(offer); + + CoinPacketExtension coin = null; + + for(PacketExtension ext : sessionInitIQ.getExtensions()) + { + if(ext.getElementName().equals( + CoinPacketExtension.ELEMENT_NAME)) + { + coin = (CoinPacketExtension)ext; + break; + } + } + + /* does the call peer acts as a conference focus ? */ + if(coin != null) + { + setConferenceFocus(Boolean.parseBoolean( + (String)coin.getAttribute("isfocus"))); + } } catch(Exception ex) { @@ -230,6 +249,7 @@ public class CallPeerJabberImpl sessionInitIQ.addExtension(sessionInitiateExtension); } } + protocolProvider.getConnection().sendPacket(sessionInitIQ); } @@ -397,7 +417,7 @@ public class CallPeerJabberImpl */ public String getJingleSID() { - return sessionInitIQ.getSID(); + return sessionInitIQ != null ? sessionInitIQ.getSID() : null; } /** @@ -409,7 +429,7 @@ public class CallPeerJabberImpl */ public String getSessInitID() { - return sessionInitIQ.getPacketID(); + return sessionInitIQ != null ? sessionInitIQ.getPacketID() : null; } /** @@ -699,6 +719,23 @@ public class CallPeerJabberImpl } /** + * Send a <tt>content</tt> message to reflect change in audio setup (start, + * stop or conference starts). + * + * @param isConference if the call if now a conference call + */ + public void sendCoinSessionInfo(boolean isConference) + { + JingleIQ sessionInfoIQ = JinglePacketFactory.createSessionInfo( + getProtocolProvider().getOurJID(), + this.peerJID, getJingleSID()); + CoinPacketExtension coinExt = new CoinPacketExtension(isConference); + sessionInfoIQ.addExtension(coinExt); + + getProtocolProvider().getConnection().sendPacket(sessionInfoIQ); + } + + /** * Send a <tt>content</tt> message to reflect change in video setup (start * or stop). Message can be content-modify if video content exists, * content-add if we start video but video is not enabled on the peer or diff --git a/src/net/java/sip/communicator/impl/protocol/jabber/ConferenceMemberJabberImpl.java b/src/net/java/sip/communicator/impl/protocol/jabber/ConferenceMemberJabberImpl.java new file mode 100644 index 0000000..c1aa9a6 --- /dev/null +++ b/src/net/java/sip/communicator/impl/protocol/jabber/ConferenceMemberJabberImpl.java @@ -0,0 +1,133 @@ +/* + * SIP Communicator, the OpenSource Java VoIP and Instant Messaging client. + * + * Distributable under LGPL license. + * See terms of license at gnu.org. + */ +package net.java.sip.communicator.impl.protocol.jabber; + +import net.java.sip.communicator.service.protocol.*; + +/** + * Represents a member and its details in a Jabber telephony conference managed + * by a <tt>CallPeer</tt> in its role as a conference focus. + * + * @author Sebastien Vincent + */ +public class ConferenceMemberJabberImpl + extends AbstractConferenceMember +{ + /** + * A Public Switched Telephone Network (PSTN) ALERTING or SIP 180 Ringing + * was returned for the outbound call; endpoint is being alerted. + */ + public static final String ALERTING = "alerting"; + + /** + * The endpoint is a participant in the conference. Depending on the media + * policies, he/she can send and receive media to and from other + * participants. + */ + public static final String CONNECTED = "connected"; + + /** + * Endpoint is dialing into the conference, not yet in the roster (probably + * being authenticated). + */ + public static final String DIALING_IN = "dialing-in"; + + /** + * Focus has dialed out to connect the endpoint to the conference, but the + * endpoint is not yet in the roster (probably being authenticated). + */ + public static final String DIALING_OUT = "dialing-out"; + + /** + * The endpoint is not a participant in the conference, and no active dialog + * exists between the endpoint and the focus. + */ + public static final String DISCONNECTED = "disconnected"; + + /** + * Active signaling dialog exists between an endpoint and a focus, but + * endpoint is "on-hold" for this conference, i.e., he/she is neither + * "hearing" the conference mix nor is his/her media being mixed in the + * conference. + */ + public static final String ON_HOLD = "on-hold"; + + /** + * Endpoint is not yet in the session, but it is anticipated that he/she + * will join in the near future. + */ + public static final String PENDING = "pending"; + + /** + * Constructor. + * + * @param callPeer the <tt>CallPeer</tt> + * @param address address of the conference member + */ + public ConferenceMemberJabberImpl(CallPeerJabberImpl callPeer, + String address) + { + super(callPeer, address); + } + + /** + * Overrides {@link AbstractCallPeer#getDisplayName()} in order to return + * the Jabber address of this <tt>ConferenceMember</tt> if the display name + * is empty. + * + * @return if the <tt>displayName</tt> property of this instance is an empty + * <tt>String</tt> value, returns the <tt>address</tt> property of this + * instance; otherwise, returns the value of the <tt>displayName</tt> + * property of this instance + */ + @Override + public String getDisplayName() + { + String displayName = super.getDisplayName(); + + if ((displayName == null) || (displayName.length() < 1)) + { + String address = getAddress(); + + if ((address != null) && (address.length() > 0)) + return address; + } + return displayName; + } + + /** + * Sets the <tt>state</tt> property of this <tt>ConferenceMember</tt> by + * translating it from its conference-info XML endpoint status. + * + * @param endpointStatus the conference-info XML endpoint status of this + * <tt>ConferenceMember</tt> indicated by its + * <tt>conferenceFocusCallPeer</tt> + */ + void setEndpointStatus(String endpointStatus) + { + ConferenceMemberState state; + + if (ALERTING.equalsIgnoreCase(endpointStatus)) + state = ConferenceMemberState.ALERTING; + else if (CONNECTED.equalsIgnoreCase(endpointStatus)) + state = ConferenceMemberState.CONNECTED; + else if (DIALING_IN.equalsIgnoreCase(endpointStatus)) + state = ConferenceMemberState.DIALING_IN; + else if (DIALING_OUT.equalsIgnoreCase(endpointStatus)) + state = ConferenceMemberState.DIALING_OUT; + else if (DISCONNECTED.equalsIgnoreCase(endpointStatus)) + state = ConferenceMemberState.DISCONNECTED; + else if (ON_HOLD.equalsIgnoreCase(endpointStatus)) + state = ConferenceMemberState.ON_HOLD; + else if (PENDING.equalsIgnoreCase(endpointStatus)) + state = ConferenceMemberState.PENDING; + else + state = ConferenceMemberState.UNKNOWN; + + setState(state); + } +} 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 ad94d21..2ce3529 100644 --- a/src/net/java/sip/communicator/impl/protocol/jabber/OperationSetBasicTelephonyJabberImpl.java +++ b/src/net/java/sip/communicator/impl/protocol/jabber/OperationSetBasicTelephonyJabberImpl.java @@ -721,6 +721,20 @@ public class OperationSetBasicTelephonyJabberImpl ofe); } } + + packetExtension + = jingleIQ.getExtension( + CoinPacketExtension.ELEMENT_NAME, + CoinPacketExtension.NAMESPACE); + + if (packetExtension instanceof CoinPacketExtension) + { + CoinPacketExtension coinExt = + (CoinPacketExtension)packetExtension; + callPeer.setConferenceFocus( + Boolean.parseBoolean(coinExt.getAttributeAsString( + CoinPacketExtension.ISFOCUS_ATTR_NAME))); + } } } else if (action == JingleAction.CONTENT_ACCEPT) 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 cdeac58..677a9d8 100644 --- a/src/net/java/sip/communicator/impl/protocol/jabber/OperationSetTelephonyConferencingJabberImpl.java +++ b/src/net/java/sip/communicator/impl/protocol/jabber/OperationSetTelephonyConferencingJabberImpl.java @@ -6,13 +6,27 @@ */ package net.java.sip.communicator.impl.protocol.jabber; +import java.util.*; + +import org.jivesoftware.smack.*; +import org.jivesoftware.smack.filter.*; +import org.jivesoftware.smack.packet.*; +import org.jivesoftware.smack.packet.IQ.*; +import org.jivesoftware.smackx.packet.*; + +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.neomedia.*; 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.Logger; /** * Implements <tt>OperationSetTelephonyConferencing</tt> for Jabber. * * @author Lyubomir Marinov + * @author Sebastien Vincent */ public class OperationSetTelephonyConferencingJabberImpl extends AbstractOperationSetTelephonyConferencing< @@ -21,7 +35,29 @@ public class OperationSetTelephonyConferencingJabberImpl 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 value of the <tt>version</tt> attribute to be specified in the + * outgoing <tt>conference-info</tt> root XML elements. + */ + private int version = 1; + + /** + * Synchronization object. + */ + private final Object objSync = new Object(); /** * Initializes a new <tt>OperationSetTelephonyConferencingJabberImpl</tt> @@ -39,6 +75,316 @@ public class OperationSetTelephonyConferencingJabberImpl } /** + * Notifies this <tt>OperationSetTelephonyConferencing</tt> that its + * <tt>basicTelephony</tt> property has changed its value from a specific + * <tt>oldValue</tt> to a specific <tt>newValue</tt> + * + * @param oldValue the old value of the <tt>basicTelephony</tt> property + * @param newValue the new value of the <tt>basicTelephony</tt> property + */ + @Override + protected void basicTelephonyChanged( + OperationSetBasicTelephonyJabberImpl oldValue, + OperationSetBasicTelephonyJabberImpl newValue) + { + if (oldValue != null) + oldValue.removeCallListener(this); + if (newValue != null) + newValue.addCallListener(this); + } + + /** + * Notifies all CallPeer associated with and established in a + * specific call for conference information. + * + * @param call the <tt>Call</tt> + */ + protected void notifyAll(Call call) + { + if(!call.isConferenceFocus()) + { + return; + } + + synchronized(objSync) + { + // send conference-info to all CallPeer of Call + Iterator<? extends CallPeer> it = call.getCallPeers(); + + while(it.hasNext()) + { + CallPeer callPeer = it.next(); + System.out.print(callPeer.getAddress()); + notify(callPeer); + } + version++; + } + } + + /** + * Notifies all CallPeer associated with and established in a + * specific call has occurred + * @param call the <tt>Call</tt> + * @param callPeer the <tt>CallPeer</tt> + */ + private void notify(CallPeer callPeer) + { + // check that callPeer supports COIN before sending him a + // conference-info + String to = getBasicTelephony().getFullCalleeURI(callPeer.getAddress()); + + try + { + DiscoverInfo discoverInfo + = parentProvider.getDiscoveryManager().discoverInfo(to); + + if (!discoverInfo.containsFeature( + ProtocolProviderServiceJabberImpl + .URN_XMPP_JINGLE_COIN)) + { + logger.info(callPeer.getAddress() + " does not support COIN"); + return; + } + } + catch (XMPPException xmppe) + { + logger.warn("Failed to retrieve DiscoverInfo for " + to, xmppe); + } + + IQ iq = getConferenceInfo((CallPeerJabberImpl)callPeer, version); + + if(iq != null) + { + parentProvider.getConnection().sendPacket(iq); + } + } + + /** + * Get media packet extension for the specified <tt>CallPeerJabberImpl</tt>. + * + * @param callPeer <tt>CallPeer</tt> + * @param remote if the callPeer is remote or local + * @return list of media packet extension + */ + private List<MediaPacketExtension> getMedia( + CallPeerJabberImpl callPeer, + boolean remote) + { + MediaPacketExtension ext = null; + CallPeerMediaHandlerJabberImpl mediaHandler = + callPeer.getMediaHandler(); + List<MediaPacketExtension> ret = + new ArrayList<MediaPacketExtension>(); + long i = 1; + + for(MediaType mediaType : MediaType.values()) + { + MediaStream stream = mediaHandler.getStream(mediaType); + + if (stream != null) + { + long srcId = remote + ? stream.getRemoteSourceID() + : stream.getLocalSourceID(); + + if (srcId != -1) + { + ext = new MediaPacketExtension(Long.toString(i)); + ext.setSrcID(Long.toString(srcId)); + ext.setType(mediaType.toString()); + MediaDirection direction = stream.getDirection(); + + if (direction == null) + direction = MediaDirection.INACTIVE; + ext.setStatus(direction.toString()); + ret.add(ext); + i++; + } + } + } + + return ret; + } + + /** + * Get user packet extension for the specified <tt>CallPeerJabberImpl</tt>. + * + * @param callPeer <tt>CallPeer</tt> + * @return user packet extension + */ + private UserPacketExtension getUser( + CallPeerJabberImpl callPeer) + { + UserPacketExtension ext = new UserPacketExtension( + callPeer.getAddress()); + EndpointPacketExtension endpoint = null; + List<MediaPacketExtension> medias = null; + + ext.setDisplayText(callPeer.getDisplayName()); + EndpointStatusType status = getEndpointStatus(callPeer); + + endpoint = new EndpointPacketExtension(callPeer.getAddress()); + endpoint.setStatus(status); + + medias = getMedia(callPeer, true); + + if(medias != null) + { + for(MediaPacketExtension media : medias) + { + endpoint.addChildExtension(media); + } + } + + ext.addChildExtension(endpoint); + + return ext; + } + + /** + * Generates the text content to be put in the <tt>status</tt> XML element + * of an <tt>endpoint</tt> XML element and which describes the state of a + * specific <tt>CallPeer</tt>. + * + * @param callPeer the <tt>CallPeer</tt> which is to get its state described + * in a <tt>status</tt> XML element of an <tt>endpoint</tt> XML element + * @return the text content to be put in the <tt>status</tt> XML element of + * an <tt>endpoint</tt> XML element and which describes the state of the + * specified <tt>callPeer</tt> + */ + private EndpointStatusType getEndpointStatus(CallPeerJabberImpl callPeer) + { + CallPeerState callPeerState = callPeer.getState(); + + if (CallPeerState.ALERTING_REMOTE_SIDE.equals(callPeerState)) + return EndpointStatusType.alerting; + if (CallPeerState.CONNECTING.equals(callPeerState) + || CallPeerState + .CONNECTING_WITH_EARLY_MEDIA.equals(callPeerState)) + return EndpointStatusType.pending; + if (CallPeerState.DISCONNECTED.equals(callPeerState)) + return EndpointStatusType.disconnected; + if (CallPeerState.INCOMING_CALL.equals(callPeerState)) + return EndpointStatusType.dialing_in; + if (CallPeerState.INITIATING_CALL.equals(callPeerState)) + return 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 EndpointStatusType.on_hold; + if (CallPeerState.CONNECTED.equals(callPeerState)) + return EndpointStatusType.connected; + return null; + } + + /** + * 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 version the value of the version attribute of the + * <tt>conference-info</tt> root element of the conference-info XML to be + * generated + * @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, int version) + { + CoinIQ iq = new CoinIQ(); + CallJabberImpl call = callPeer.getCall(); + + iq.setFrom(call.getProtocolProvider().getOurJID()); + iq.setTo(callPeer.getAddress()); + iq.setType(Type.SET); + iq.setEntity(getBasicTelephony().getProtocolProvider().getOurJID()); + iq.setVersion(version); + iq.setState(StateType.full); + + if(callPeer.getJingleSID() == null) + return null; + iq.setSID(callPeer.getJingleSID()); + + // conference-description + iq.addExtension(new DescriptionPacketExtension()); + + // conference-state + StatePacketExtension state = new StatePacketExtension(); + state.setUserCount(call.getCallPeerCount() + 1); + iq.addExtension(state); + + // users + UsersPacketExtension users = new UsersPacketExtension(); + + // user + UserPacketExtension user = new UserPacketExtension( + parentProvider.getOurJID()); + + // endpoint + EndpointPacketExtension endpoint = new EndpointPacketExtension( + parentProvider.getOurJID()); + endpoint.setStatus(EndpointStatusType.connected); + + // media + List<MediaPacketExtension> medias = getMedia(callPeer, false); + + for(MediaPacketExtension media : medias) + { + endpoint.addChildExtension(media); + } + user.addChildExtension(endpoint); + users.addChildExtension(user); + + // other users + Iterator<CallPeerJabberImpl> callPeerIter = call.getCallPeers(); + + while (callPeerIter.hasNext()) + { + UserPacketExtension ext = getUser(callPeerIter.next()); + users.addChildExtension(ext); + } + + iq.addExtension(users); + 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 + */ + public void registrationStateChanged(RegistrationStateChangeEvent evt) + { + super.registrationStateChanged(evt); + + RegistrationState registrationState = evt.getNewState(); + + if (registrationState == RegistrationState.REGISTERED) + { + if(logger.isInfoEnabled()) + { + logger.info("Subscribes to Coin packets"); + } + subscribeForCoinPackets(); + } + else if (registrationState == RegistrationState.UNREGISTERED) + { + if(logger.isInfoEnabled()) + { + logger.info("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>. * @@ -75,7 +421,22 @@ public class OperationSetTelephonyConferencingJabberImpl boolean wasConferenceFocus) throws OperationFailedException { - return getBasicTelephony().createOutgoingCall(call, calleeAddress); + if (!wasConferenceFocus && call.isConferenceFocus()) + { + // reinvite other peers if any, to inform them that from now + // it is a conference call + Iterator<CallPeerJabberImpl> callPeerIter = call.getCallPeers(); + + while (callPeerIter.hasNext()) + { + CallPeerJabberImpl callPeer = callPeerIter.next(); + callPeer.sendCoinSessionInfo(true); + } + } + + CoinPacketExtension confInfo = new CoinPacketExtension(true); + return getBasicTelephony().createOutgoingCall(call, calleeAddress, + Arrays.asList(new PacketExtension[] { confInfo })); } /** @@ -97,4 +458,244 @@ public class OperationSetTelephonyConferencingJabberImpl { return getBasicTelephony().getFullCalleeURI(calleeAddressString); } + + /** + * Subscribes us to notifications about incoming Coin packets. + */ + private void subscribeForCoinPackets() + { + parentProvider.getConnection().addPacketListener(this, this); + } + + /** + * Unsubscribes us to notifications about incoming Coin packets. + */ + private void unsubscribeForCoinPackets() + { + if(parentProvider.getConnection() != null) + { + parentProvider.getConnection().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) + { + if(!(packet instanceof CoinIQ)) + { + return false; + } + + return true; + } + + /** + * 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; + + //first ack all "set" requests. + if(coinIQ.getType() == IQ.Type.SET) + { + IQ ack = IQ.createResultIQ(coinIQ); + parentProvider.getConnection().sendPacket(ack); + } + + String sid = coinIQ.getSID(); + + if(sid == null) + { + return; + } + + CallPeerJabberImpl callPeer + = getBasicTelephony().getActiveCallsRepository().findCallPeer(sid); + + if(callPeer == null) + { + return; + } + + handleCoin(coinIQ, callPeer); + } + + /** + * Removes the parameters (specified after a slash) from a specific + * address <tt>String</tt> if any are present in it. + * + * @param address the <tt>String</tt> value representing an address from + * which any parameters are to be removed + * @return a <tt>String</tt> representing the specified <tt>address</tt> + * without any parameters + */ + private static String stripParametersFromAddress(String address) + { + if (address != null) + { + int parametersBeginIndex = address.indexOf('/'); + + if (parametersBeginIndex > -1) + address = address.substring(0, parametersBeginIndex); + } + return address; + } + + /** + * Handle Coin IQ. + * + * @param coinIQ Coin IQ + * @param callPeer a <tt>CallPeer</tt> + */ + private void handleCoin(CoinIQ coinIQ, CallPeerJabberImpl callPeer) + { + ConferenceMember[] conferenceMembersToRemove + = callPeer.getConferenceMembers(); + int conferenceMembersToRemoveCount = conferenceMembersToRemove.length; + UsersPacketExtension users = null; + Collection<PacketExtension> usersList = coinIQ.getExtensions(); + + for(PacketExtension ext : usersList) + { + if(ext.getElementName().equals(UsersPacketExtension.ELEMENT_NAME)) + { + users = (UsersPacketExtension)ext; + break; + } + } + + if(users == null) + { + return; + } + + Collection<UserPacketExtension> userList = + users.getChildExtensionsOfType(UserPacketExtension.class); + + if(userList.size() == 0) + { + return; + } + + for(UserPacketExtension u : userList) + { + String address = null; + + if(u.getAttribute("entity") != null) + { + address + = stripParametersFromAddress( + (String)u.getAttribute("entity")); + } + + if ((address == null) || (address.length() < 1)) + continue; + + /* + * Determine the ConferenceMembers which are no longer in the + * list. + */ + ConferenceMemberJabberImpl existingConferenceMember = null; + + for (int conferenceMemberIndex = 0; + conferenceMemberIndex < conferenceMembersToRemoveCount; + conferenceMemberIndex++) + { + ConferenceMemberJabberImpl conferenceMember + = (ConferenceMemberJabberImpl) + conferenceMembersToRemove[conferenceMemberIndex]; + + if ((conferenceMember != null) + && address + .equalsIgnoreCase( + conferenceMember.getAddress())) + { + conferenceMembersToRemove[conferenceMemberIndex] = null; + existingConferenceMember = conferenceMember; + break; + } + } + + // Create the new ones. + boolean addConferenceMember = false; + if (existingConferenceMember == null) + { + existingConferenceMember + = new ConferenceMemberJabberImpl(callPeer, address); + addConferenceMember = true; + } + else + { + addConferenceMember = false; + } + + // Update the existing ones. + if (existingConferenceMember != null) + { + String displayName = u.getDisplayText(); + List<EndpointPacketExtension> endpoints = + u.getChildExtensionsOfType(EndpointPacketExtension.class); + String endpointStatus = null; + String ssrc = null; + + if(endpoints.size() > 0) + { + EndpointPacketExtension endpoint = endpoints.get(0); + endpointStatus = endpoint.getStatus().toString(); + + List<MediaPacketExtension> medias = + endpoint.getChildExtensionsOfType( + MediaPacketExtension.class); + + for(MediaPacketExtension media : medias) + { + if(media.getType().equalsIgnoreCase( + MediaType.AUDIO.toString())) + { + ssrc = media.getSrcID(); + } + } + } + + existingConferenceMember.setDisplayName(displayName); + existingConferenceMember.setEndpointStatus(endpointStatus); + + if (ssrc != null) + { + existingConferenceMember.setSSRC(Long.parseLong(ssrc)); + } + + if (addConferenceMember) + { + callPeer.addConferenceMember(existingConferenceMember); + } + } + } + + /* + * Remove the ConferenceMember instance which are no longer present in + * the conference-info XML document. + */ + for (int conferenceMemberIndex = 0; + conferenceMemberIndex < conferenceMembersToRemoveCount; + conferenceMemberIndex++) + { + ConferenceMember conferenceMemberToRemove + = conferenceMembersToRemove[conferenceMemberIndex]; + + if (conferenceMemberToRemove != null) + callPeer.removeConferenceMember(conferenceMemberToRemove); + } + } } diff --git a/src/net/java/sip/communicator/impl/protocol/jabber/ProtocolProviderServiceJabberImpl.java b/src/net/java/sip/communicator/impl/protocol/jabber/ProtocolProviderServiceJabberImpl.java index 8d5c2aa..b852d7c 100644 --- a/src/net/java/sip/communicator/impl/protocol/jabber/ProtocolProviderServiceJabberImpl.java +++ b/src/net/java/sip/communicator/impl/protocol/jabber/ProtocolProviderServiceJabberImpl.java @@ -20,6 +20,7 @@ import net.java.sip.communicator.service.protocol.jabberconstants.*; import net.java.sip.communicator.util.*; import net.java.sip.communicator.impl.protocol.jabber.extensions.jingle.*; import net.java.sip.communicator.impl.protocol.jabber.extensions.inputevt.*; +import net.java.sip.communicator.impl.protocol.jabber.extensions.coin.*; import net.java.sip.communicator.impl.protocol.jabber.sasl.*; import net.java.sip.communicator.service.certificate.*; @@ -106,6 +107,19 @@ public class ProtocolProviderServiceJabberImpl = TransferPacketExtension.NAMESPACE; /** + * Jingle's Discover Info URN for "XEP-XXXX :Delivering Conference + * Information to Jingle Participants (Coin)" support. + */ + public static final String URN_XMPP_JINGLE_COIN = "urn:xmpp:coin"; + + /** + * Jingle's Discover Info URN for "XEP-0294: Jingle RTP Header Extensions + * Negotiation" support. + */ + public static final String URN_XMPP_JINGLE_RTP_HDREXT = + "urn:xmpp:jingle:apps:rtp:rtp-hdrext:0"; + + /** * Used to connect to a XMPP server. */ private XMPPConnection connection = null; @@ -1158,6 +1172,9 @@ public class ProtocolProviderServiceJabberImpl supportedFeatures.add("http://jabber.org/protocol/muc#rooms"); supportedFeatures.add("http://jabber.org/protocol/muc#traffic"); + // RTP HDR extension + supportedFeatures.add(URN_XMPP_JINGLE_RTP_HDREXT); + //register our jingle provider //register our home grown Jingle Provider. ProviderManager providerManager = ProviderManager.getInstance(); @@ -1170,6 +1187,12 @@ public class ProtocolProviderServiceJabberImpl InputEvtIQ.NAMESPACE, new InputEvtIQProvider()); + // register our coin provider + providerManager.addIQProvider(CoinIQ.ELEMENT_NAME, + CoinIQ.NAMESPACE, + new CoinIQProvider()); + supportedFeatures.add(URN_XMPP_JINGLE_COIN); + //initialize the telephony operation set OperationSetBasicTelephonyJabberImpl basicTelephony = new OperationSetBasicTelephonyJabberImpl(this); diff --git a/src/net/java/sip/communicator/impl/protocol/jabber/extensions/AbstractPacketExtension.java b/src/net/java/sip/communicator/impl/protocol/jabber/extensions/AbstractPacketExtension.java index 53a3854..ff0cc01 100644 --- a/src/net/java/sip/communicator/impl/protocol/jabber/extensions/AbstractPacketExtension.java +++ b/src/net/java/sip/communicator/impl/protocol/jabber/extensions/AbstractPacketExtension.java @@ -40,7 +40,7 @@ public abstract class AbstractPacketExtension /** * A map of all attributes that this extension is currently using. */ - private final Map<String, String> attributes + protected final Map<String, String> attributes = new LinkedHashMap<String, String>(); /** @@ -367,7 +367,7 @@ public abstract class AbstractPacketExtension * Returns this packet's first direct child extension that matches the * specified <tt>type</tt>. * - * @param <T> the specific type of <tt>PacketExtension</tt> to be returned + * @param <T> the specific type of <tt>PacketExtension</tt> to be returned * * @param type the <tt>Class</tt> of the extension we are looking for. * diff --git a/src/net/java/sip/communicator/impl/protocol/jabber/extensions/coin/CoinIQ.java b/src/net/java/sip/communicator/impl/protocol/jabber/extensions/coin/CoinIQ.java new file mode 100644 index 0000000..9e55efb --- /dev/null +++ b/src/net/java/sip/communicator/impl/protocol/jabber/extensions/coin/CoinIQ.java @@ -0,0 +1,190 @@ +/* + * SIP Communicator, the OpenSource Java VoIP and Instant Messaging client. + * + * Distributable under LGPL license. + * See terms of license at gnu.org. + */ +package net.java.sip.communicator.impl.protocol.jabber.extensions.coin; + +import org.jivesoftware.smack.packet.*; + +/** + * Coin (Conference Info) IQ. It is used to inform conference participants + * about useful information (users, ...). + * + * @author Sebastien Vincent + */ +public class CoinIQ + extends IQ +{ + /** + * The namespace that coin belongs to. + */ + public static final String NAMESPACE = + "urn:ietf:params:xml:ns:conference-info"; + + /** + * The name of the element that contains the coin data. + */ + public static final String ELEMENT_NAME = "conference-info"; + + /** + * Entity attribute name. + */ + public static final String ENTITY_ATTR_NAME = "entity"; + + /** + * Version attribute name. + */ + public static final String VERSION_ATTR_NAME = "version"; + + /** + * Version attribute name. + */ + public static final String STATE_ATTR_NAME = "state"; + + /** + * Jingle session ID attribute name. + */ + public static final String SID_ATTR_NAME = "sid"; + + /** + * Version. + */ + private int version = 0; + + /** + * Entity name. + */ + private String entity = null; + + /** + * State. + */ + private StateType state = StateType.full; + + /** + * Jingle session ID. + */ + private String sid = null; + + /** + * Get version. + * + * @return version + */ + public int getVersion() + { + return version; + } + + /** + * Get state. + * + * @return state + */ + public StateType getState() + { + return state; + } + + /** + * Get session ID. + * + * @return session ID + */ + public String getSID() + { + return sid; + } + + /** + * Set version. + * + * @param version version + */ + public void setVersion(int version) + { + this.version = version; + } + + /** + * Set state. + * + * @param state state to set + */ + public void setState(StateType state) + { + this.state = state; + } + + /** + * Set session ID. + * + * @param sid session ID to set + */ + public void setSID(String sid) + { + this.sid = sid; + } + + /** + * Get entity. + * + * @return entity + */ + public String getEntity() + { + return entity; + } + + /** + * Set entity. + * + * @param entity entity + */ + public void setEntity(String entity) + { + this.entity = entity; + } + + /** + * Returns the XML string of this Jingle IQ's "section" sub-element. + * + * Extensions of this class must override this method. + * + * @return the child element section of the IQ XML. + */ + @Override + public String getChildElementXML() + { + StringBuilder bldr = new StringBuilder("<"); + + bldr.append(ELEMENT_NAME); + bldr.append(" xmlns='" + NAMESPACE + "'"); + bldr.append(" state='" + state + "'"); + bldr.append(" entity='" + entity + "'"); + bldr.append(" version='" + version + "'"); + + if(sid != null) + { + bldr.append(" sid='" + sid + "'"); + } + + if(getExtensions().size() == 0) + { + bldr.append("/>"); + } + else + { + bldr.append(">"); + for(PacketExtension pe : getExtensions()) + { + bldr.append(pe.toXML()); + } + } + + bldr.append("</").append(ELEMENT_NAME).append(">"); + return bldr.toString(); + } +} diff --git a/src/net/java/sip/communicator/impl/protocol/jabber/extensions/coin/CoinIQProvider.java b/src/net/java/sip/communicator/impl/protocol/jabber/extensions/coin/CoinIQProvider.java new file mode 100644 index 0000000..f65f598 --- /dev/null +++ b/src/net/java/sip/communicator/impl/protocol/jabber/extensions/coin/CoinIQProvider.java @@ -0,0 +1,154 @@ +/* + * SIP Communicator, the OpenSource Java VoIP and Instant Messaging client. + * + * Distributable under LGPL license. + * See terms of license at gnu.org. + */ +package net.java.sip.communicator.impl.protocol.jabber.extensions.coin; + +import org.jivesoftware.smack.packet.*; +import org.jivesoftware.smack.provider.*; +import org.xmlpull.v1.*; + +/** + * An implementation of a Coin IQ provider that parses incoming Coin IQs. + * + * @author Sebastien Vincent + */ +public class CoinIQProvider + implements IQProvider +{ + /** + * Provider for description packet extension. + */ + private final PacketExtensionProvider descriptionProvider = new + DescriptionProvider(); + + /** + * Provider for users packet extension. + */ + private final PacketExtensionProvider usersProvider = new UsersProvider(); + + /** + * Provider for state packet extension. + */ + private final StateProvider stateProvider = new StateProvider(); + + /** + * Constructor. + */ + public CoinIQProvider() + { + } + + /** + * Parse the Coin IQ sub-document and returns the corresponding + * <tt>CoinIQ</tt>. + * + * @param parser XML parser + * @return <tt>CoinIQ</tt> + * @throws Exception if something goes wrong during parsing + */ + public IQ parseIQ(XmlPullParser parser) + throws Exception + { + CoinIQ coinIQ = new CoinIQ(); + + String entity = parser + .getAttributeValue("", CoinIQ.ENTITY_ATTR_NAME); + String version = parser.getAttributeValue("", CoinIQ.VERSION_ATTR_NAME); + StateType state = StateType.full; + String stateStr = parser.getAttributeValue("", + EndpointPacketExtension.STATE_ATTR_NAME); + String sid = parser.getAttributeValue("", CoinIQ.SID_ATTR_NAME); + + if(stateStr != null) + { + state = StateType.parseString(stateStr); + } + + coinIQ.setEntity(entity); + coinIQ.setVersion(Integer.parseInt(version)); + coinIQ.setState(state); + coinIQ.setSID(sid); + + // Now go on and parse the jingle element's content. + int eventType; + String elementName = null; + boolean done = false; + + while (!done) + { + eventType = parser.next(); + elementName = parser.getName(); + + if (eventType == XmlPullParser.START_TAG) + { + if(elementName.equals(DescriptionPacketExtension.ELEMENT_NAME)) + { + PacketExtension childExtension = + descriptionProvider.parseExtension(parser); + coinIQ.addExtension(childExtension); + } + else if(elementName.equals(UsersPacketExtension.ELEMENT_NAME)) + { + PacketExtension childExtension = + usersProvider.parseExtension(parser); + coinIQ.addExtension(childExtension); + } + else if(elementName.equals(StatePacketExtension.ELEMENT_NAME)) + { + PacketExtension childExtension = + stateProvider.parseExtension(parser); + coinIQ.addExtension(childExtension); + } + } + + if (eventType == XmlPullParser.END_TAG) + { + if (parser.getName().equals(CoinIQ.ELEMENT_NAME)) + { + done = true; + } + } + } + + return coinIQ; + } + + /** + * Returns the content of the next {@link XmlPullParser#TEXT} element that + * we encounter in <tt>parser</tt>. + * + * @param parser the parse that we'll be probing for text. + * + * @return the content of the next {@link XmlPullParser#TEXT} element we + * come across or <tt>null</tt> if we encounter a closing tag first. + * + * @throws java.lang.Exception if an error occurs parsing the XML. + */ + public static String parseText(XmlPullParser parser) + throws Exception + { + boolean done = false; + + int eventType; + String text = null; + + while (!done) + { + eventType = parser.next(); + + if (eventType == XmlPullParser.TEXT) + { + text = parser.getText(); + } + else if (eventType == XmlPullParser.END_TAG) + { + done = true; + } + } + + return text; + } +} diff --git a/src/net/java/sip/communicator/impl/protocol/jabber/extensions/coin/DescriptionPacketExtension.java b/src/net/java/sip/communicator/impl/protocol/jabber/extensions/coin/DescriptionPacketExtension.java new file mode 100644 index 0000000..52e61b6 --- /dev/null +++ b/src/net/java/sip/communicator/impl/protocol/jabber/extensions/coin/DescriptionPacketExtension.java @@ -0,0 +1,190 @@ +/* + * SIP Communicator, the OpenSource Java VoIP and Instant Messaging client. + * + * Distributable under LGPL license. + * See terms of license at gnu.org. + */ +package net.java.sip.communicator.impl.protocol.jabber.extensions.coin; + +import java.util.*; + +import net.java.sip.communicator.impl.protocol.jabber.extensions.*; + +/** + * Description packet extension. + * + * @author Sebastien Vincent + */ +public class DescriptionPacketExtension + extends AbstractPacketExtension +{ + /** + * The namespace that description belongs to. + */ + public static final String NAMESPACE = null; + + /** + * The name of the element that contains the description data. + */ + public static final String ELEMENT_NAME = "conference-description"; + + /** + * Subject element name. + */ + public static final String ELEMENT_SUBJECT = "subject"; + + /** + * Display text element name. + */ + public static final String ELEMENT_DISPLAY_TEXT = "display-text"; + + /** + * Free text element name. + */ + public static final String ELEMENT_FREE_TEXT = "free-text"; + + /** + * Max user count element name. + */ + public static final String ELEMENT_MAX_USER_COUNT = + "maximum-user-count"; + + /** + * The subject. + */ + private String subject = ""; + + /** + * Display text. + */ + private String displayText = null; + + /** + * Free text. + */ + private String freeText = null; + + /** + * Maximum user count. + */ + private int maximumUserCount = 0; + + /** + * Constructor. + */ + public DescriptionPacketExtension() + { + super(NAMESPACE, ELEMENT_NAME); + } + + /** + * Set subject. + * + * @param subject subject + */ + public void setSubject(String subject) + { + this.subject = subject; + } + + /** + * Set display text. + * + * @param displayText display text + */ + public void setDisplayText(String displayText) + { + this.displayText = displayText; + } + + /** + * Set free text. + * + * @param freeText free text + */ + public void setFreeText(String freeText) + { + this.freeText = freeText; + } + + /** + * Get subject. + * + * @return subject + */ + public String getSubject() + { + return subject; + } + + /** + * Get display text. + * + * @return display text + */ + public String getDisplayText() + { + return displayText; + } + + /** + * Get free text. + * + * @return free text + */ + public String getFreeText() + { + return freeText; + } + + /** + * Get an XML string representation. + * + * @return XML string representation + */ + @Override + public String toXML() + { + StringBuilder bldr = new StringBuilder(); + + bldr.append("<").append(getElementName()).append(" "); + + if(getNamespace() != null) + bldr.append("xmlns='").append(getNamespace()).append("'"); + + //add the rest of the attributes if any + for(Map.Entry<String, String> entry : attributes.entrySet()) + { + bldr.append(" ") + .append(entry.getKey()) + .append("='") + .append(entry.getValue()) + .append("'"); + } + + bldr.append(">"); + + if(subject != null) + bldr.append("<").append(ELEMENT_SUBJECT).append(">").append( + subject).append("</").append(ELEMENT_SUBJECT).append(">"); + + if(displayText != null) + bldr.append("<").append(ELEMENT_DISPLAY_TEXT).append(">").append( + displayText).append("</").append( + ELEMENT_DISPLAY_TEXT).append(">"); + + if(freeText != null) + bldr.append("<").append(ELEMENT_FREE_TEXT).append(">").append( + freeText).append("</").append( + ELEMENT_FREE_TEXT).append(">"); + + if(maximumUserCount != 0) + bldr.append("<").append(ELEMENT_MAX_USER_COUNT).append(">").append( + maximumUserCount).append("</").append( + ELEMENT_MAX_USER_COUNT).append(">"); + + + bldr.append("</").append(ELEMENT_NAME).append(">"); + return bldr.toString(); + } +} diff --git a/src/net/java/sip/communicator/impl/protocol/jabber/extensions/coin/DescriptionProvider.java b/src/net/java/sip/communicator/impl/protocol/jabber/extensions/coin/DescriptionProvider.java new file mode 100644 index 0000000..54f7bab --- /dev/null +++ b/src/net/java/sip/communicator/impl/protocol/jabber/extensions/coin/DescriptionProvider.java @@ -0,0 +1,79 @@ +/* + * SIP Communicator, the OpenSource Java VoIP and Instant Messaging client. + * + * Distributable under LGPL license. + * See terms of license at gnu.org. + */ +package net.java.sip.communicator.impl.protocol.jabber.extensions.coin; + +import org.jivesoftware.smack.provider.*; +import org.xmlpull.v1.*; + +/** + * Parser for DescriptionPacketExtension. + * + * @author Sebastien Vincent + */ +public class DescriptionProvider + implements PacketExtensionProvider +{ + /** + * Parses a description extension sub-packet and creates a {@link + * DescriptionPacketExtension} instance. At the beginning of the method + * call, the xml parser will be positioned on the opening element of the + * packet extension. As required by the smack API, at the end of the method + * call, the parser will be positioned on the closing element of the packet + * extension. + * + * @param parser an XML parser positioned at the opening + * <tt>description</tt> element. + * + * @return a new {@link DescriptionPacketExtension} instance. + * @throws java.lang.Exception if an error occurs parsing the XML. + */ + public DescriptionPacketExtension parseExtension(XmlPullParser parser) + throws Exception + { + boolean done = false; + int eventType; + String elementName = null; + + DescriptionPacketExtension ext + = new DescriptionPacketExtension(); + + while (!done) + { + eventType = parser.next(); + elementName = parser.getName(); + + if (eventType == XmlPullParser.START_TAG) + { + if(elementName.equals( + DescriptionPacketExtension.ELEMENT_SUBJECT)) + { + ext.setSubject(CoinIQProvider.parseText(parser)); + } + else if(elementName.equals( + DescriptionPacketExtension.ELEMENT_FREE_TEXT)) + { + ext.setFreeText(CoinIQProvider.parseText(parser)); + } + else if(elementName.equals( + DescriptionPacketExtension.ELEMENT_DISPLAY_TEXT)) + { + ext.setDisplayText(CoinIQProvider.parseText(parser)); + } + } + else if (eventType == XmlPullParser.END_TAG) + { + if (parser.getName().equals( + DescriptionPacketExtension.ELEMENT_NAME)) + { + done = true; + } + } + } + + return ext; + } +} diff --git a/src/net/java/sip/communicator/impl/protocol/jabber/extensions/coin/DisconnectionType.java b/src/net/java/sip/communicator/impl/protocol/jabber/extensions/coin/DisconnectionType.java new file mode 100644 index 0000000..582902c --- /dev/null +++ b/src/net/java/sip/communicator/impl/protocol/jabber/extensions/coin/DisconnectionType.java @@ -0,0 +1,82 @@ +/* + * SIP Communicator, the OpenSource Java VoIP and Instant Messaging client. + * + * Distributable under LGPL license. + * See terms of license at gnu.org. + */ +package net.java.sip.communicator.impl.protocol.jabber.extensions.coin; + +/** + * Disconnection type. + * + * @author Sebastien Vincent + */ +public enum DisconnectionType +{ + /** + * Departed. + */ + departed("departed"), + + /** + * Booted. + */ + booted("booted"), + + /** + * Failed. + */ + failed("failed"), + + /** + * Busy + */ + busy("busy"); + + /** + * The name of this type. + */ + private final String type; + + /** + * Creates a <tt>DisconnectionType</tt> instance with the specified name. + * + * @param type type name. + */ + private DisconnectionType(String type) + { + this.type = type; + } + + /** + * Returns the type name. + * + * @return type name + */ + @Override + public String toString() + { + return type; + } + + /** + * Returns a <tt>DisconnectionType</tt>. + * + * @param typeStr the <tt>String</tt> that we'd like to + * parse. + * @return an DisconnectionType. + * + * @throws IllegalArgumentException in case <tt>typeStr</tt> is + * not a valid <tt>EndPointType</tt>. + */ + public static DisconnectionType parseString(String typeStr) + throws IllegalArgumentException + { + for (DisconnectionType value : values()) + if (value.toString().equals(typeStr)) + return value; + + throw new IllegalArgumentException( + typeStr + " is not a valid reason"); + } +} diff --git a/src/net/java/sip/communicator/impl/protocol/jabber/extensions/coin/EndpointPacketExtension.java b/src/net/java/sip/communicator/impl/protocol/jabber/extensions/coin/EndpointPacketExtension.java new file mode 100644 index 0000000..6348e67 --- /dev/null +++ b/src/net/java/sip/communicator/impl/protocol/jabber/extensions/coin/EndpointPacketExtension.java @@ -0,0 +1,227 @@ +/* + * SIP Communicator, the OpenSource Java VoIP and Instant Messaging client. + * + * Distributable under LGPL license. + * See terms of license at gnu.org. + */ +package net.java.sip.communicator.impl.protocol.jabber.extensions.coin; + +import java.util.*; + +import org.jivesoftware.smack.packet.*; + +import net.java.sip.communicator.impl.protocol.jabber.extensions.*; + +/** + * Endpoint packet extension. + * + * @author Sebastien Vincent + */ +public class EndpointPacketExtension + extends AbstractPacketExtension +{ + /** + * The namespace that endpoint belongs to. + */ + public static final String NAMESPACE = null; + + /** + * The name of the element that contains the endpoint data. + */ + public static final String ELEMENT_NAME = "endpoint"; + + /** + * Entity attribute name. + */ + public static final String ENTITY_ATTR_NAME = "entity"; + + /** + * Entity attribute name. + */ + public static final String STATE_ATTR_NAME = "state"; + + /** + * Display text element name. + */ + public static final String ELEMENT_DISPLAY_TEXT = "display-text"; + + /** + * Status element name. + */ + public static final String ELEMENT_STATUS = "status"; + + /** + * Disconnection element name. + */ + public static final String ELEMENT_DISCONNECTION = "disconnection-method"; + + /** + * Joining element name. + */ + public static final String ELEMENT_JOINING = "joining-method"; + + /** + * Display text. + */ + private String displayText = null; + + /** + * Status. + */ + private EndpointStatusType status = null; + + /** + * Disconnection type. + */ + private DisconnectionType disconnectionType = null; + + /** + * Joining type. + */ + private JoiningType joiningType = null; + + /** + * Constructor. + * + * @param entity entity + */ + public EndpointPacketExtension(String entity) + { + super(NAMESPACE, ELEMENT_NAME); + setAttribute("entity", entity); + } + + /** + * Set the display text. + * + * @param displayText display text + */ + public void setDisplayText(String displayText) + { + this.displayText = displayText; + } + + /** + * Set status. + * + * @param status status + */ + public void setStatus(EndpointStatusType status) + { + this.status = status; + } + + /** + * Set disconnection type. + * + * @param disconnectionType disconnection type. + */ + public void setDisconnectionType(DisconnectionType disconnectionType) + { + this.disconnectionType = disconnectionType; + } + + /** + * Set joining type. + * + * @param joiningType joining type. + */ + public void setJoiningType(JoiningType joiningType) + { + this.joiningType = joiningType; + } + + /** + * Get display text. + * + * @return display text + */ + public String getDisplayText() + { + return displayText; + } + + /** + * Get status. + * + * @return status. + */ + public EndpointStatusType getStatus() + { + return status; + } + + /** + * Get disconnection type. + * + * @return disconnection type. + */ + public DisconnectionType getDisconnectionType() + { + return disconnectionType; + } + + /** + * Get joining type. + * + * @return joining type. + */ + public JoiningType getJoiningType() + { + return joiningType; + } + + /** + * Returns an XML representation of this extension. + * + * @return an XML representation of this extension. + */ + public String toXML() + { + StringBuilder bldr = new StringBuilder(); + + bldr.append("<").append(getElementName()).append(" "); + + if(getNamespace() != null) + bldr.append("xmlns='").append(getNamespace()).append("'"); + + //add the rest of the attributes if any + for(Map.Entry<String, String> entry : attributes.entrySet()) + { + bldr.append(" ") + .append(entry.getKey()) + .append("='") + .append(entry.getValue()) + .append("'"); + } + + bldr.append(">"); + + if(displayText != null) + bldr.append("<").append(ELEMENT_DISPLAY_TEXT).append(">").append( + displayText).append("</").append( + ELEMENT_DISPLAY_TEXT).append(">"); + if(status != null) + bldr.append("<").append(ELEMENT_STATUS).append(">").append( + status).append("</").append( + ELEMENT_STATUS).append(">"); + + if(disconnectionType != null) + bldr.append("<").append(ELEMENT_DISCONNECTION).append(">").append( + disconnectionType).append("</").append( + ELEMENT_DISCONNECTION).append(">"); + + if(joiningType != null) + bldr.append("<").append(ELEMENT_JOINING).append(">").append( + joiningType).append("</").append( + ELEMENT_JOINING).append(">"); + + for(PacketExtension ext : getChildExtensions()) + { + bldr.append(ext.toXML()); + } + + bldr.append("</").append(ELEMENT_NAME).append(">"); + return bldr.toString(); + } +} diff --git a/src/net/java/sip/communicator/impl/protocol/jabber/extensions/coin/EndpointProvider.java b/src/net/java/sip/communicator/impl/protocol/jabber/extensions/coin/EndpointProvider.java new file mode 100644 index 0000000..bb37832 --- /dev/null +++ b/src/net/java/sip/communicator/impl/protocol/jabber/extensions/coin/EndpointProvider.java @@ -0,0 +1,108 @@ +/* + * SIP Communicator, the OpenSource Java VoIP and Instant Messaging client. + * + * Distributable under LGPL license. + * See terms of license at gnu.org. + */ +package net.java.sip.communicator.impl.protocol.jabber.extensions.coin; + +import org.jivesoftware.smack.packet.*; +import org.jivesoftware.smack.provider.*; +import org.xmlpull.v1.*; + +/** + * Parser for EndpointPacketExtension. + * + * @author Sebastien Vincent + */ +public class EndpointProvider + implements PacketExtensionProvider +{ + /** + * Parses a endpoint extension sub-packet and creates a {@link + * EndpointPacketExtension} instance. At the beginning of the method + * call, the xml parser will be positioned on the opening element of the + * packet extension. As required by the smack API, at the end of the method + * call, the parser will be positioned on the closing element of the packet + * extension. + * + * @param parser an XML parser positioned at the opening + * <tt>Endpoint</tt> element. + * + * @return a new {@link EndpointPacketExtension} instance. + * @throws java.lang.Exception if an error occurs parsing the XML. + */ + public PacketExtension parseExtension(XmlPullParser parser) + throws Exception + { + boolean done = false; + int eventType; + String elementName = null; + String entity = parser.getAttributeValue("", + EndpointPacketExtension.ENTITY_ATTR_NAME); + StateType state = StateType.full; + String stateStr = parser.getAttributeValue("", + EndpointPacketExtension.STATE_ATTR_NAME); + + if(stateStr != null) + { + state = StateType.parseString(stateStr); + } + + EndpointPacketExtension ext + = new EndpointPacketExtension(entity); + + ext.setAttribute(EndpointPacketExtension.STATE_ATTR_NAME, state); + + while (!done) + { + eventType = parser.next(); + elementName = parser.getName(); + + if (eventType == XmlPullParser.START_TAG) + { + if(elementName.equals( + EndpointPacketExtension.ELEMENT_DISPLAY_TEXT)) + { + ext.setDisplayText(CoinIQProvider.parseText(parser)); + } + else if(elementName.equals( + EndpointPacketExtension.ELEMENT_DISCONNECTION)) + { + ext.setDisconnectionType( + DisconnectionType.parseString(parser.getText())); + } + else if(elementName.equals( + EndpointPacketExtension.ELEMENT_JOINING)) + { + ext.setJoiningType(JoiningType.parseString( + CoinIQProvider.parseText(parser))); + } + else if(elementName.equals( + EndpointPacketExtension.ELEMENT_STATUS)) + { + ext.setStatus(EndpointStatusType.parseString( + CoinIQProvider.parseText(parser))); + } + else if(elementName.equals(MediaPacketExtension.ELEMENT_NAME)) + { + PacketExtensionProvider provider + = new MediaProvider(); + PacketExtension childExtension = provider.parseExtension( + parser); + ext.addChildExtension(childExtension); + } + } + else if (eventType == XmlPullParser.END_TAG) + { + if (parser.getName().equals( + EndpointPacketExtension.ELEMENT_NAME)) + { + done = true; + } + } + } + + return ext; + } +} diff --git a/src/net/java/sip/communicator/impl/protocol/jabber/extensions/coin/EndpointStatusType.java b/src/net/java/sip/communicator/impl/protocol/jabber/extensions/coin/EndpointStatusType.java new file mode 100644 index 0000000..2ea3ce5 --- /dev/null +++ b/src/net/java/sip/communicator/impl/protocol/jabber/extensions/coin/EndpointStatusType.java @@ -0,0 +1,107 @@ +/* + * SIP Communicator, the OpenSource Java VoIP and Instant Messaging client. + * + * Distributable under LGPL license. + * See terms of license at gnu.org. + */ +package net.java.sip.communicator.impl.protocol.jabber.extensions.coin; + +/** + * Endpoint status type. + * + * @author Sebastien Vincent + */ +public enum EndpointStatusType +{ + /** + * Pending. + */ + pending("pending"), + + /** + * Dialing-out. + */ + dialing_out ("dialing-out"), + + /** + * Dialing-in. + */ + dialing_in("dialing-in"), + + /** + * Alerting. + */ + alerting("alerting"), + + /** + * On-hold. + */ + on_hold("on-hold"), + + /** + * Connected. + */ + connected("connected"), + + /** + * Muted via focus. + */ + muted_via_focus("mute-via-focus"), + + /** + * Disconnecting. + */ + disconnecting("disconnecting"), + + /** + * Disconnected. + */ + disconnected("disconnected"); + + /** + * The name of this type. + */ + private final String type; + + /** + * Creates a <tt>EndPointType</tt> instance with the specified name. + * + * @param type type name. + */ + private EndpointStatusType(String type) + { + this.type = type; + } + + /** + * Returns the type name. + * + * @return type name + */ + @Override + public String toString() + { + return type; + } + + /** + * Returns a <tt>EndPointType</tt>. + * + * @param typeStr the <tt>String</tt> that we'd like to + * parse. + * @return an EndPointType. + * + * @throws IllegalArgumentException in case <tt>typeStr</tt> is + * not a valid <tt>EndPointType</tt>. + */ + public static EndpointStatusType parseString(String typeStr) + throws IllegalArgumentException + { + for (EndpointStatusType value : values()) + if (value.toString().equals(typeStr)) + return value; + + throw new IllegalArgumentException( + typeStr + " is not a valid reason"); + } +} diff --git a/src/net/java/sip/communicator/impl/protocol/jabber/extensions/coin/ExecutionPacketExtension.java b/src/net/java/sip/communicator/impl/protocol/jabber/extensions/coin/ExecutionPacketExtension.java new file mode 100644 index 0000000..e7fcaaa --- /dev/null +++ b/src/net/java/sip/communicator/impl/protocol/jabber/extensions/coin/ExecutionPacketExtension.java @@ -0,0 +1,192 @@ +/* + * SIP Communicator, the OpenSource Java VoIP and Instant Messaging client. + * + * Distributable under LGPL license. + * See terms of license at gnu.org. + */ +package net.java.sip.communicator.impl.protocol.jabber.extensions.coin; + +import java.util.*; + +import net.java.sip.communicator.impl.protocol.jabber.extensions.*; + +/** + * Execution packet extension. + * + * @author Sebastien Vincent + */ +public class ExecutionPacketExtension + extends AbstractPacketExtension +{ + /** + * The namespace that media belongs to. + */ + public static final String NAMESPACE = null; + + /** + * The name of the element that contains the media data. + */ + public static final String ELEMENT_REFERRED_NAME = "referred"; + + /** + * The name of the element that contains the media data. + */ + public static final String ELEMENT_DISCONNECTION_NAME = + "disconnection-info"; + + /** + * The name of the element that contains the media data. + */ + public static final String ELEMENT_JOINING_NAME = "joining-info"; + + /** + * The name of the element that contains the media data. + */ + public static final String ELEMENT_MODIFIED_NAME = "modified"; + + /** + * "By" element name. + */ + public static final String ELEMENT_BY = "by"; + + /** + * "Reason" element name. + */ + public static final String ELEMENT_REASON = "reason"; + + /** + * "When" element name. + */ + public static final String ELEMENT_WHEN = "display-text"; + + /** + * Date of the execution. + */ + private String when = null; + + /** + * By. + */ + private String by = null; + + /** + * Reason. + */ + private String reason = null; + + /** + * Set "by" field. + * + * @param by string to set + */ + public void setBy(String by) + { + this.by = by; + } + + /** + * Get "by" field. + * + * @return "by" field + */ + public String getBy() + { + return by; + } + + /** + * Set "when" field. + * + * @param when string to set + */ + public void setWhen(String when) + { + this.when = when; + } + + /** + * Get "when" field. + * + * @return "when" field + */ + public String getWhen() + { + return when; + } + + /** + * Set "reason" field. + * + * @param reason string to set + */ + public void setReason(String reason) + { + this.reason = reason; + } + + /** + * Get "reason" field. + * + * @return "reason" field + */ + public String getReason() + { + return reason; + } + + /** + * Constructor. + * + * @param elementName name of the element + */ + public ExecutionPacketExtension(String elementName) + { + super(NAMESPACE, elementName); + } + + /** + * Get an XML string representation. + * + * @return XML string representation + */ + @Override + public String toXML() + { + StringBuilder bldr = new StringBuilder(); + + bldr.append("<").append(getElementName()).append(" "); + + if(getNamespace() != null) + bldr.append("xmlns='").append(getNamespace()).append("'"); + + //add the rest of the attributes if any + for(Map.Entry<String, String> entry : attributes.entrySet()) + { + bldr.append(" ") + .append(entry.getKey()) + .append("='") + .append(entry.getValue()) + .append("'"); + } + + bldr.append(">"); + + if(by != null) + bldr.append("<").append(ELEMENT_BY).append(">").append( + by).append("</").append( + ELEMENT_BY).append(">"); + + if(when != null) + bldr.append("<").append(ELEMENT_WHEN).append(">").append( + when).append("</").append( + ELEMENT_WHEN).append(">"); + + if(reason != null) + bldr.append("<").append(ELEMENT_REASON).append(">").append( + reason).append("</").append( + ELEMENT_REASON).append(">"); + + bldr.append("</").append(getElementName()).append(">"); + return bldr.toString(); + } +} diff --git a/src/net/java/sip/communicator/impl/protocol/jabber/extensions/coin/HostInfoPacketExtension.java b/src/net/java/sip/communicator/impl/protocol/jabber/extensions/coin/HostInfoPacketExtension.java new file mode 100644 index 0000000..b68dd81 --- /dev/null +++ b/src/net/java/sip/communicator/impl/protocol/jabber/extensions/coin/HostInfoPacketExtension.java @@ -0,0 +1,137 @@ +/* + * SIP Communicator, the OpenSource Java VoIP and Instant Messaging client. + * + * Distributable under LGPL license. + * See terms of license at gnu.org. + */ +package net.java.sip.communicator.impl.protocol.jabber.extensions.coin; + +import java.util.*; + +import net.java.sip.communicator.impl.protocol.jabber.extensions.*; + +/** + * Host Information packet extension. + * + * @author Sebastien Vincent + */ +public class HostInfoPacketExtension + extends AbstractPacketExtension +{ + /** + * The namespace that media belongs to. + */ + public static final String NAMESPACE = null; + + /** + * The name of the element that contains the media data. + */ + public static final String ELEMENT_NAME = "host-info"; + + /** + * Display text element name. + */ + public static final String ELEMENT_DISPLAY_TEXT = "display-text"; + + /** + * Web page element name. + */ + public static final String ELEMENT_WEB_PAGE = "web-page"; + + /** + * Display text. + */ + private String displayText = null; + + /** + * Web page. + */ + private String webPage = null; + + /** + * Constructor. + */ + public HostInfoPacketExtension() + { + super(NAMESPACE, ELEMENT_NAME); + } + + /** + * Set display text. + * @param displayText display text + */ + public void setDisplayText(String displayText) + { + this.displayText = displayText; + } + + /** + * Get display text. + * + * @return display text + */ + public String getDisplayText() + { + return displayText; + } + + /** + * Set web page. + * @param webPage web page + */ + public void setWebPage(String webPage) + { + this.webPage = webPage; + } + + /** + * Get web page. + * + * @return web page + */ + public String getWebPage() + { + return webPage; + } + + /** + * Get an XML string representation. + * + * @return XML string representation + */ + @Override + public String toXML() + { + StringBuilder bldr = new StringBuilder(); + + bldr.append("<").append(getElementName()).append(" "); + + if(getNamespace() != null) + bldr.append("xmlns='").append(getNamespace()).append("'"); + + //add the rest of the attributes if any + for(Map.Entry<String, String> entry : attributes.entrySet()) + { + bldr.append(" ") + .append(entry.getKey()) + .append("='") + .append(entry.getValue()) + .append("'"); + } + + bldr.append(">"); + + if(displayText != null) + bldr.append("<").append(ELEMENT_DISPLAY_TEXT).append(">").append( + displayText).append("</").append( + ELEMENT_DISPLAY_TEXT).append(">"); + + if(webPage != null) + bldr.append("<").append(ELEMENT_WEB_PAGE).append(">").append( + webPage).append("</").append( + ELEMENT_WEB_PAGE).append(">"); + + bldr.append("</").append(ELEMENT_NAME).append(">"); + return bldr.toString(); + } +} diff --git a/src/net/java/sip/communicator/impl/protocol/jabber/extensions/coin/JoiningType.java b/src/net/java/sip/communicator/impl/protocol/jabber/extensions/coin/JoiningType.java new file mode 100644 index 0000000..5b0adea --- /dev/null +++ b/src/net/java/sip/communicator/impl/protocol/jabber/extensions/coin/JoiningType.java @@ -0,0 +1,77 @@ +/* + * SIP Communicator, the OpenSource Java VoIP and Instant Messaging client. + * + * Distributable under LGPL license. + * See terms of license at gnu.org. + */ +package net.java.sip.communicator.impl.protocol.jabber.extensions.coin; + +/** + * Joining type. + * + * @author Sebastien Vincent + */ +public enum JoiningType +{ + /** + * Dialed-in. + */ + dialed_in("dialed-in"), + + /** + * Dialed-out. + */ + dialed_out("dialed-out"), + + /** + * Focus owner. + */ + focus_owner("focus-owner"); + + /** + * The name of this type. + */ + private final String type; + + /** + * Creates a <tt>JoiningType</tt> instance with the specified name. + * + * @param type type name. + */ + private JoiningType(String type) + { + this.type = type; + } + + /** + * Returns the type name. + * + * @return type name + */ + @Override + public String toString() + { + return type; + } + + /** + * Returns a <tt>JoiningType</tt>. + * + * @param typeStr the <tt>String</tt> that we'd like to + * parse. + * @return an JoiningType. + * + * @throws IllegalArgumentException in case <tt>typeStr</tt> is + * not a valid <tt>EndPointType</tt>. + */ + public static JoiningType parseString(String typeStr) + throws IllegalArgumentException + { + for (JoiningType value : values()) + if (value.toString().equals(typeStr)) + return value; + + throw new IllegalArgumentException( + typeStr + " is not a valid reason"); + } +} diff --git a/src/net/java/sip/communicator/impl/protocol/jabber/extensions/coin/MediaPacketExtension.java b/src/net/java/sip/communicator/impl/protocol/jabber/extensions/coin/MediaPacketExtension.java new file mode 100644 index 0000000..44a4ad5 --- /dev/null +++ b/src/net/java/sip/communicator/impl/protocol/jabber/extensions/coin/MediaPacketExtension.java @@ -0,0 +1,251 @@ +/* + * SIP Communicator, the OpenSource Java VoIP and Instant Messaging client. + * + * Distributable under LGPL license. + * See terms of license at gnu.org. + */ +package net.java.sip.communicator.impl.protocol.jabber.extensions.coin; + +import java.util.*; + +import net.java.sip.communicator.impl.protocol.jabber.extensions.*; + +/** + * Media packet extension. + * + * @author Sebastien Vincent + */ +public class MediaPacketExtension + extends AbstractPacketExtension +{ + /** + * The namespace that media belongs to. + */ + public static final String NAMESPACE = null; + + /** + * The name of the element that contains the media data. + */ + public static final String ELEMENT_NAME = "media"; + + /** + * Display text element name. + */ + public static final String ELEMENT_DISPLAY_TEXT = "display-text"; + + /** + * Source ID element name. + */ + public static final String ELEMENT_SRC_ID = "src-id"; + + /** + * Label element name. + */ + public static final String ELEMENT_LABEL = "label"; + + /** + * Type element name. + */ + public static final String ELEMENT_TYPE = "type"; + + /** + * Status element name. + */ + public static final String ELEMENT_STATUS = "status"; + + /** + * ID attribute name. + */ + public static final String ID_ATTR_NAME = "id"; + + /** + * Source ID. + */ + private String srcId = null; + + /** + * Type. + */ + private String type = null; + + /** + * Label. + */ + private String label = null; + + /** + * Display text. + */ + private String displayText = null; + + /** + * Media status. + */ + private String status = null; + + /** + * Constructor. + * + * @param id media ID + */ + public MediaPacketExtension(String id) + { + super(NAMESPACE, ELEMENT_NAME); + setAttribute(ID_ATTR_NAME, id); + } + + /** + * Set label. + * + * @param label label + */ + public void setLabel(String label) + { + this.label = label; + } + + /** + * Set status. + * + * @param status status. + */ + public void setStatus(String status) + { + this.status = status; + } + + /** + * Set src-id. + * + * @param srcId src-id + */ + public void setSrcID(String srcId) + { + this.srcId = srcId; + } + + /** + * Set type. + * + * @param type type + */ + public void setType(String type) + { + this.type = type; + } + + /** + * Set display text. + * @param displayText display text + */ + public void setDisplayText(String displayText) + { + this.displayText = displayText; + } + + /** + * Get display text. + * + * @return display text + */ + public String getDisplayText() + { + return displayText; + } + + /** + * Get type. + * + * @return type + */ + public String getType() + { + return type; + } + + /** + * Get label. + * + * @return label + */ + public String getLabel() + { + return label; + } + + /** + * Get status. + * + * @return status. + */ + public String getStatus() + { + return status; + } + + /** + * Get src-id. + * + * @return src-id + */ + public String getSrcID() + { + return srcId; + } + + /** + * Get an XML string representation. + * + * @return XML string representation + */ + @Override + public String toXML() + { + StringBuilder bldr = new StringBuilder(); + + bldr.append("<").append(getElementName()).append(" "); + + if(getNamespace() != null) + bldr.append("xmlns='").append(getNamespace()).append("'"); + + //add the rest of the attributes if any + for(Map.Entry<String, String> entry : attributes.entrySet()) + { + bldr.append(" ") + .append(entry.getKey()) + .append("='") + .append(entry.getValue()) + .append("'"); + } + + bldr.append(">"); + + if(displayText != null) + bldr.append("<").append(ELEMENT_DISPLAY_TEXT).append(">").append( + displayText).append("</").append( + ELEMENT_DISPLAY_TEXT).append(">"); + + if(type != null) + bldr.append("<").append(ELEMENT_TYPE).append(">").append( + type).append("</").append( + ELEMENT_TYPE).append(">"); + + if(srcId != null) + bldr.append("<").append(ELEMENT_SRC_ID).append(">").append( + srcId).append("</").append( + ELEMENT_SRC_ID).append(">"); + + if(status != null) + bldr.append("<").append(ELEMENT_STATUS).append(">").append( + status).append("</").append( + ELEMENT_STATUS).append(">"); + + if(label != null) + bldr.append("<").append(ELEMENT_LABEL).append(">").append( + label).append("</").append( + ELEMENT_LABEL).append(">"); + + bldr.append("</").append(ELEMENT_NAME).append(">"); + return bldr.toString(); + } +} diff --git a/src/net/java/sip/communicator/impl/protocol/jabber/extensions/coin/MediaProvider.java b/src/net/java/sip/communicator/impl/protocol/jabber/extensions/coin/MediaProvider.java new file mode 100644 index 0000000..e500261 --- /dev/null +++ b/src/net/java/sip/communicator/impl/protocol/jabber/extensions/coin/MediaProvider.java @@ -0,0 +1,97 @@ +/* + * SIP Communicator, the OpenSource Java VoIP and Instant Messaging client. + * + * Distributable under LGPL license. + * See terms of license at gnu.org. + */ +package net.java.sip.communicator.impl.protocol.jabber.extensions.coin; + +import org.jivesoftware.smack.provider.*; +import org.xmlpull.v1.*; + +/** + * Parser for MediaPacketExtension. + * + * @author Sebastien Vincent + */ +public class MediaProvider + implements PacketExtensionProvider +{ + /** + * Parses a media extension sub-packet and creates a {@link + * MediaPacketExtension} instance. At the beginning of the method + * call, the xml parser will be positioned on the opening element of the + * packet extension. As required by the smack API, at the end of the method + * call, the parser will be positioned on the closing element of the packet + * extension. + * + * @param parser an XML parser positioned at the opening + * <tt>Media</tt> element. + * + * @return a new {@link MediaPacketExtension} instance. + * @throws java.lang.Exception if an error occurs parsing the XML. + */ + public MediaPacketExtension parseExtension(XmlPullParser parser) + throws Exception + { + boolean done = false; + int eventType; + String elementName = null; + String id = parser.getAttributeValue( + "", + MediaPacketExtension.ID_ATTR_NAME); + + if(id == null) + { + throw new Exception("Coin media must contains src-id element"); + } + + MediaPacketExtension ext + = new MediaPacketExtension(id); + + while (!done) + { + eventType = parser.next(); + elementName = parser.getName(); + + if (eventType == XmlPullParser.START_TAG) + { + if(elementName.equals( + MediaPacketExtension.ELEMENT_DISPLAY_TEXT)) + { + ext.setDisplayText(CoinIQProvider.parseText(parser)); + } + else if(elementName.equals( + MediaPacketExtension.ELEMENT_LABEL)) + { + ext.setLabel(CoinIQProvider.parseText(parser)); + } + else if(elementName.equals( + MediaPacketExtension.ELEMENT_SRC_ID)) + { + ext.setSrcID(CoinIQProvider.parseText(parser)); + } + else if(elementName.equals( + MediaPacketExtension.ELEMENT_STATUS)) + { + ext.setStatus(CoinIQProvider.parseText(parser)); + } + else if(elementName.equals( + MediaPacketExtension.ELEMENT_TYPE)) + { + ext.setType(CoinIQProvider.parseText(parser)); + } + } + else if (eventType == XmlPullParser.END_TAG) + { + if (parser.getName().equals( + MediaPacketExtension.ELEMENT_NAME)) + { + done = true; + } + } + } + + return ext; + } +} diff --git a/src/net/java/sip/communicator/impl/protocol/jabber/extensions/coin/MediaStatusType.java b/src/net/java/sip/communicator/impl/protocol/jabber/extensions/coin/MediaStatusType.java new file mode 100644 index 0000000..f4b48d0 --- /dev/null +++ b/src/net/java/sip/communicator/impl/protocol/jabber/extensions/coin/MediaStatusType.java @@ -0,0 +1,35 @@ +/* + * SIP Communicator, the OpenSource Java VoIP and Instant Messaging client. + * + * Distributable under LGPL license. + * See terms of license at gnu.org. + */ +package net.java.sip.communicator.impl.protocol.jabber.extensions.coin; + +/** + * Media status. + * + * @author Sebastien Vincent + */ +public enum MediaStatusType +{ + /** + * Receive only. + */ + recvonly, + + /** + * Send only. + */ + sendonly, + + /** + * Send and receive. + */ + sendrecv, + + /** + * Inactive. + */ + inactive; +} diff --git a/src/net/java/sip/communicator/impl/protocol/jabber/extensions/coin/StatePacketExtension.java b/src/net/java/sip/communicator/impl/protocol/jabber/extensions/coin/StatePacketExtension.java new file mode 100644 index 0000000..c3cdf71 --- /dev/null +++ b/src/net/java/sip/communicator/impl/protocol/jabber/extensions/coin/StatePacketExtension.java @@ -0,0 +1,174 @@ +/* + * SIP Communicator, the OpenSource Java VoIP and Instant Messaging client. + * + * Distributable under LGPL license. + * See terms of license at gnu.org. + */ +package net.java.sip.communicator.impl.protocol.jabber.extensions.coin; + +import java.util.*; + +import net.java.sip.communicator.impl.protocol.jabber.extensions.*; + +/** + * State packet extension. + * + * @author Sebastien Vincent + */ +public class StatePacketExtension + extends AbstractPacketExtension +{ + /** + * The namespace that state belongs to. + */ + public static final String NAMESPACE = null; + + /** + * The name of the element that contains the state data. + */ + public static final String ELEMENT_NAME = "conference-state"; + + /** + * Users count element name. + */ + public static final String ELEMENT_USER_COUNT = "user-count"; + + /** + * Active element name. + */ + public static final String ELEMENT_ACTIVE = "active"; + + /** + * Locked element name. + */ + public static final String ELEMENT_LOCKED = "locked"; + + /** + * User count. + */ + private int userCount = 0; + + /** + * Active state. + */ + private int active = -1; + + /** + * Locked state. + */ + private int locked = -1; + + /** + * Constructor. + */ + public StatePacketExtension() + { + super(NAMESPACE, ELEMENT_NAME); + } + + /** + * Set the user count. + * + * @param userCount user count + */ + public void setUserCount(int userCount) + { + this.userCount = userCount; + } + + /** + * Set the active state. + * + * @param active state + */ + public void setActive(int active) + { + this.active = active; + } + + /** + * Set the locked state. + * + * @param locked locked state + */ + public void setLocked(int locked) + { + this.locked = locked; + } + + /** + * Get the user count. + * + * @return user count + */ + public int getUserCount() + { + return userCount; + } + + /** + * Get the active state. + * + * @return active state + */ + public int getActive() + { + return active; + } + + /** + * Get the locked state. + * + * @return locked state + */ + public int getLocked() + { + return locked; + } + + /** + * Get an XML string representation. + * + * @return XML string representation + */ + @Override + public String toXML() + { + StringBuilder bldr = new StringBuilder(); + + bldr.append("<").append(getElementName()).append(" "); + + if(getNamespace() != null) + bldr.append("xmlns='").append(getNamespace()).append("'"); + + //add the rest of the attributes if any + for(Map.Entry<String, String> entry : attributes.entrySet()) + { + bldr.append(" ") + .append(entry.getKey()) + .append("='") + .append(entry.getValue()) + .append("'"); + } + + bldr.append(">"); + + if(userCount != 0) + bldr.append("<").append(ELEMENT_USER_COUNT).append(">").append( + userCount).append("</").append(ELEMENT_USER_COUNT).append( + ">"); + + if(active != -1) + bldr.append("<").append(ELEMENT_ACTIVE).append(">").append( + (active > 0)).append("</").append(ELEMENT_ACTIVE).append( + ">"); + + if(locked != -1) + bldr.append("<").append(ELEMENT_LOCKED).append(">").append( + (active > 0)).append("</").append(ELEMENT_LOCKED).append( + ">"); + + bldr.append("</").append(getElementName()).append(">"); + return bldr.toString(); + } +} diff --git a/src/net/java/sip/communicator/impl/protocol/jabber/extensions/coin/StateProvider.java b/src/net/java/sip/communicator/impl/protocol/jabber/extensions/coin/StateProvider.java new file mode 100644 index 0000000..f345933 --- /dev/null +++ b/src/net/java/sip/communicator/impl/protocol/jabber/extensions/coin/StateProvider.java @@ -0,0 +1,78 @@ +/* + * SIP Communicator, the OpenSource Java VoIP and Instant Messaging client. + * + * Distributable under LGPL license. + * See terms of license at gnu.org. + */ +package net.java.sip.communicator.impl.protocol.jabber.extensions.coin; + +import org.jivesoftware.smack.provider.*; +import org.xmlpull.v1.*; + +/** + * Parser for StatePacketExtension. + * + * @author Sebastien Vincent + */ +public class StateProvider + implements PacketExtensionProvider +{ + /** + * Parses a state extension sub-packet and creates a {@link + * StatePacketExtension} instance. At the beginning of the method + * call, the xml parser will be positioned on the opening element of the + * packet extension. As required by the smack API, at the end of the method + * call, the parser will be positioned on the closing element of the packet + * extension. + * + * @param parser an XML parser positioned at the opening + * <tt>State</tt> element. + * + * @return a new {@link StatePacketExtension} instance. + * @throws java.lang.Exception if an error occurs parsing the XML. + */ + public StatePacketExtension parseExtension(XmlPullParser parser) + throws Exception + { + boolean done = false; + int eventType; + String elementName = null; + + StatePacketExtension ext + = new StatePacketExtension(); + + while (!done) + { + eventType = parser.next(); + elementName = parser.getName(); + + if (eventType == XmlPullParser.START_TAG) + { + if(elementName.equals(StatePacketExtension.ELEMENT_ACTIVE)) + { + ext.setActive( + Boolean.parseBoolean(CoinIQProvider.parseText(parser)) ? 1 : 0); + } + else if(elementName.equals(StatePacketExtension.ELEMENT_LOCKED)) + { + ext.setLocked( + Boolean.parseBoolean(CoinIQProvider.parseText(parser)) ? 1 : 0); + } + if(elementName.equals(StatePacketExtension.ELEMENT_USER_COUNT)) + { + ext.setUserCount(Integer.parseInt(CoinIQProvider.parseText(parser))); + } + } + else if (eventType == XmlPullParser.END_TAG) + { + if (parser.getName().equals( + StatePacketExtension.ELEMENT_NAME)) + { + done = true; + } + } + } + + return ext; + } +}
\ No newline at end of file diff --git a/src/net/java/sip/communicator/impl/protocol/jabber/extensions/coin/StateType.java b/src/net/java/sip/communicator/impl/protocol/jabber/extensions/coin/StateType.java new file mode 100644 index 0000000..d0bee73 --- /dev/null +++ b/src/net/java/sip/communicator/impl/protocol/jabber/extensions/coin/StateType.java @@ -0,0 +1,51 @@ +/* + * SIP Communicator, the OpenSource Java VoIP and Instant Messaging client. + * + * Distributable under LGPL license. + * See terms of license at gnu.org. + */ +package net.java.sip.communicator.impl.protocol.jabber.extensions.coin; + +/** + * Status type. + * + * @author Sebastien Vincent + */ +public enum StateType +{ + /** + * Full state. + */ + full, + + /** + * Partial state. + */ + partial, + + /** + * Deleted state. + */ + deleted; + + /** + * Returns a <tt>StateType</tt>. + * + * @param typeStr the <tt>String</tt> that we'd like to + * parse. + * @return a StateType. + * + * @throws IllegalArgumentException in case <tt>typeStr</tt> is + * not a valid <tt>EndPointType</tt>. + */ + public static StateType parseString(String typeStr) + throws IllegalArgumentException + { + for (StateType value : values()) + if (value.toString().equals(typeStr)) + return value; + + throw new IllegalArgumentException( + typeStr + " is not a valid reason"); + } +} diff --git a/src/net/java/sip/communicator/impl/protocol/jabber/extensions/coin/UserPacketExtension.java b/src/net/java/sip/communicator/impl/protocol/jabber/extensions/coin/UserPacketExtension.java new file mode 100644 index 0000000..2530cbc --- /dev/null +++ b/src/net/java/sip/communicator/impl/protocol/jabber/extensions/coin/UserPacketExtension.java @@ -0,0 +1,123 @@ +/* + * SIP Communicator, the OpenSource Java VoIP and Instant Messaging client. + * + * Distributable under LGPL license. + * See terms of license at gnu.org. + */ +package net.java.sip.communicator.impl.protocol.jabber.extensions.coin; + +import java.util.*; + +import org.jivesoftware.smack.packet.*; + +import net.java.sip.communicator.impl.protocol.jabber.extensions.*; + +/** + * User packet extension. + * + * @author Sebastien Vincent + */ +public class UserPacketExtension + extends AbstractPacketExtension +{ + /** + * The namespace that user belongs to. + */ + public static final String NAMESPACE = null; + + /** + * The name of the element that contains the user data. + */ + public static final String ELEMENT_NAME = "user"; + + /** + * Entity attribute name. + */ + public static final String ENTITY_ATTR_NAME = "entity"; + + /** + * Entity attribute name. + */ + public static final String STATE_ATTR_NAME = "state"; + + /** + * Display text element name. + */ + public static final String ELEMENT_DISPLAY_TEXT = "display-text"; + + /** + * Display text. + */ + private String displayText = null; + + /** + * Constructor. + * + * @param entity entity + */ + public UserPacketExtension(String entity) + { + super(NAMESPACE, ELEMENT_NAME); + setAttribute("entity", entity); + } + + /** + * Set display text. + * @param displayText display text + */ + public void setDisplayText(String displayText) + { + this.displayText = displayText; + } + + /** + * Get display text. + * + * @return display text + */ + public String getDisplayText() + { + return displayText; + } + + /** + * Get an XML string representation. + * + * @return XML string representation + */ + @Override + public String toXML() + { + StringBuilder bldr = new StringBuilder(); + + bldr.append("<").append(getElementName()).append(" "); + + if(getNamespace() != null) + bldr.append("xmlns='").append(getNamespace()).append("'"); + + //add the rest of the attributes if any + for(Map.Entry<String, String> entry : attributes.entrySet()) + { + bldr.append(" ") + .append(entry.getKey()) + .append("='") + .append(entry.getValue()) + .append("'"); + } + + bldr.append(">"); + + if(displayText != null) + bldr.append("<").append(ELEMENT_DISPLAY_TEXT).append(">").append( + displayText).append("</").append( + ELEMENT_DISPLAY_TEXT).append(">"); + + for(PacketExtension ext : getChildExtensions()) + { + bldr.append(ext.toXML()); + } + + bldr.append("</").append(getElementName()).append(">"); + return bldr.toString(); + } +} diff --git a/src/net/java/sip/communicator/impl/protocol/jabber/extensions/coin/UserProvider.java b/src/net/java/sip/communicator/impl/protocol/jabber/extensions/coin/UserProvider.java new file mode 100644 index 0000000..39030d0 --- /dev/null +++ b/src/net/java/sip/communicator/impl/protocol/jabber/extensions/coin/UserProvider.java @@ -0,0 +1,94 @@ +/* + * SIP Communicator, the OpenSource Java VoIP and Instant Messaging client. + * + * Distributable under LGPL license. + * See terms of license at gnu.org. + */ +package net.java.sip.communicator.impl.protocol.jabber.extensions.coin; + +import org.jivesoftware.smack.packet.*; +import org.jivesoftware.smack.provider.*; +import org.xmlpull.v1.*; + +/** + * Parser for UserPacketExtension. + * + * @author Sebastien Vincent + */ +public class UserProvider + implements PacketExtensionProvider +{ + /** + * Parses a User extension sub-packet and creates a {@link + * UserPacketExtension} instance. At the beginning of the method + * call, the xml parser will be positioned on the opening element of the + * packet extension. As required by the smack API, at the end of the method + * call, the parser will be positioned on the closing element of the packet + * extension. + * + * @param parser an XML parser positioned at the opening + * <tt>User</tt> element. + * + * @return a new {@link UserPacketExtension} instance. + * @throws java.lang.Exception if an error occurs parsing the XML. + */ + public UserPacketExtension parseExtension(XmlPullParser parser) + throws Exception + { + boolean done = false; + int eventType; + String elementName = null; + String entity = parser.getAttributeValue("", + UserPacketExtension.ENTITY_ATTR_NAME); + StateType state = StateType.full; + String stateStr = parser.getAttributeValue("", + UserPacketExtension.STATE_ATTR_NAME); + + if(stateStr != null) + { + state = StateType.parseString(stateStr); + } + + if(entity == null) + { + throw new Exception( + "Coin user element must contain entity attribute"); + } + + UserPacketExtension ext = new UserPacketExtension(entity); + ext.setAttribute(UserPacketExtension.STATE_ATTR_NAME, state); + + while (!done) + { + eventType = parser.next(); + elementName = parser.getName(); + + if (eventType == XmlPullParser.START_TAG) + { + if(elementName.equals(UserPacketExtension.ELEMENT_DISPLAY_TEXT)) + { + ext.setDisplayText(CoinIQProvider.parseText(parser)); + } + else if(elementName.equals( + EndpointPacketExtension.ELEMENT_NAME)) + { + PacketExtensionProvider provider + = new EndpointProvider(); + PacketExtension childExtension = provider.parseExtension( + parser); + ext.addChildExtension(childExtension); + } + } + else if (eventType == XmlPullParser.END_TAG) + { + if (parser.getName().equals( + UserPacketExtension.ELEMENT_NAME)) + { + done = true; + } + } + } + + return ext; + } +} diff --git a/src/net/java/sip/communicator/impl/protocol/jabber/extensions/coin/UsersPacketExtension.java b/src/net/java/sip/communicator/impl/protocol/jabber/extensions/coin/UsersPacketExtension.java new file mode 100644 index 0000000..7b38ea6 --- /dev/null +++ b/src/net/java/sip/communicator/impl/protocol/jabber/extensions/coin/UsersPacketExtension.java @@ -0,0 +1,41 @@ +/* + * SIP Communicator, the OpenSource Java VoIP and Instant Messaging client. + * + * Distributable under LGPL license. + * See terms of license at gnu.org. + */ +package net.java.sip.communicator.impl.protocol.jabber.extensions.coin; + +import net.java.sip.communicator.impl.protocol.jabber.extensions.*; + +/** + * Users packet extension. + * + * @author Sebastien Vincent + */ +public class UsersPacketExtension + extends AbstractPacketExtension +{ + /** + * The namespace that users belongs to. + */ + public static final String NAMESPACE = null; + + /** + * The name of the element that contains the users data. + */ + public static final String ELEMENT_NAME = "users"; + + /** + * Entity attribute name. + */ + public static final String STATE_ATTR_NAME = "state"; + + /** + * Constructor. + */ + public UsersPacketExtension() + { + super(NAMESPACE, ELEMENT_NAME); + } +} diff --git a/src/net/java/sip/communicator/impl/protocol/jabber/extensions/coin/UsersProvider.java b/src/net/java/sip/communicator/impl/protocol/jabber/extensions/coin/UsersProvider.java new file mode 100644 index 0000000..d6b4b9c --- /dev/null +++ b/src/net/java/sip/communicator/impl/protocol/jabber/extensions/coin/UsersProvider.java @@ -0,0 +1,83 @@ +/* + * SIP Communicator, the OpenSource Java VoIP and Instant Messaging client. + * + * Distributable under LGPL license. + * See terms of license at gnu.org. + */ +package net.java.sip.communicator.impl.protocol.jabber.extensions.coin; + +import org.jivesoftware.smack.packet.*; +import org.jivesoftware.smack.provider.*; +import org.xmlpull.v1.*; + +/** + * Parser for UsersPacketExtension. + * + * @author Sebastien Vincent + */ +public class UsersProvider + implements PacketExtensionProvider +{ + /** + * Parses a users extension sub-packet and creates a {@link + * UsersPacketExtension} instance. At the beginning of the method + * call, the xml parser will be positioned on the opening element of the + * packet extension. As required by the smack API, at the end of the method + * call, the parser will be positioned on the closing element of the packet + * extension. + * + * @param parser an XML parser positioned at the opening + * <tt>Users</tt> element. + * + * @return a new {@link UsersPacketExtension} instance. + * @throws java.lang.Exception if an error occurs parsing the XML. + */ + public UsersPacketExtension parseExtension(XmlPullParser parser) + throws Exception + { + boolean done = false; + int eventType; + String elementName = null; + StateType state = StateType.full; + String stateStr = parser.getAttributeValue("", + UserPacketExtension.STATE_ATTR_NAME); + + if(stateStr != null) + { + state = StateType.parseString(stateStr); + } + + UsersPacketExtension ext + = new UsersPacketExtension(); + + ext.setAttribute(UsersPacketExtension.STATE_ATTR_NAME, state); + + while (!done) + { + eventType = parser.next(); + elementName = parser.getName(); + + if (eventType == XmlPullParser.START_TAG) + { + if(elementName.equals(UserPacketExtension.ELEMENT_NAME)) + { + PacketExtensionProvider provider + = new UserProvider(); + PacketExtension childExtension = provider.parseExtension( + parser); + ext.addChildExtension(childExtension); + } + } + else if (eventType == XmlPullParser.END_TAG) + { + if (parser.getName().equals( + UsersPacketExtension.ELEMENT_NAME)) + { + done = true; + } + } + } + + return ext; + } +} diff --git a/src/net/java/sip/communicator/impl/protocol/jabber/extensions/jingle/CoinPacketExtension.java b/src/net/java/sip/communicator/impl/protocol/jabber/extensions/jingle/CoinPacketExtension.java new file mode 100644 index 0000000..15eb2a4 --- /dev/null +++ b/src/net/java/sip/communicator/impl/protocol/jabber/extensions/jingle/CoinPacketExtension.java @@ -0,0 +1,53 @@ +/* + * SIP Communicator, the OpenSource Java VoIP and Instant Messaging client. + * + * Distributable under LGPL license. + * See terms of license at gnu.org. + */ +package net.java.sip.communicator.impl.protocol.jabber.extensions.jingle; + +import net.java.sip.communicator.impl.protocol.jabber.extensions.*; + +/** + * Represents the conference information. + * + * @author Sebastien Vincent + */ +public class CoinPacketExtension + extends AbstractPacketExtension +{ + /** + * Name of the XML element representing the extension. + */ + public final static String ELEMENT_NAME = "conference-info"; + + /** + * Namespace. + */ + public final static String NAMESPACE = ""; + + /** + * IsFocus attribute name. + */ + public final static String ISFOCUS_ATTR_NAME = "isfocus"; + + /** + * Constructs a new <tt>coin</tt> extension. + * + */ + public CoinPacketExtension() + { + super(NAMESPACE, ELEMENT_NAME); + } + + /** + * Constructs a new <tt>coin</tt> extension. + * + * @param isFocus if the peer is a mixer + */ + public CoinPacketExtension(boolean isFocus) + { + super(NAMESPACE, ELEMENT_NAME); + setAttribute(ISFOCUS_ATTR_NAME, isFocus); + } +}
\ No newline at end of file diff --git a/src/net/java/sip/communicator/impl/protocol/jabber/extensions/jingle/ExtmapPacketExtension.java b/src/net/java/sip/communicator/impl/protocol/jabber/extensions/jingle/ExtmapPacketExtension.java deleted file mode 100644 index 2a728a7..0000000 --- a/src/net/java/sip/communicator/impl/protocol/jabber/extensions/jingle/ExtmapPacketExtension.java +++ /dev/null @@ -1,136 +0,0 @@ -/* - * SIP Communicator, the OpenSource Java VoIP and Instant Messaging client. - * - * Distributable under LGPL license. - * See terms of license at gnu.org. - */ -package net.java.sip.communicator.impl.protocol.jabber.extensions.jingle; - -import java.net.*; - -import net.java.sip.communicator.impl.protocol.jabber.extensions.*; - -/** - * Represents the <tt>extmap</tt> elements described in RFC 5285. - * - * @author Emil Ivov - */ -public class ExtmapPacketExtension - extends AbstractPacketExtension -{ - /** - * The name of the "extmap" element. - */ - public static final String ELEMENT_NAME = "extmap"; - - /** - * The name of the <tt>uri</tt> attribute in the <tt>extmap</tt> element. - */ - public static final String URI_ATTR_NAME = "uri"; - - /** - * The name of the <tt>value</tt> attribute in the <tt>extmap</tt> element. - */ - public static final String VALUE_ATTR_NAME = "value"; - - /** - * The name of the <tt>direction</tt> attribute in the <tt>extmap</tt> - * element. - */ - public static final String DIRECTION_ATTR_NAME = "direction"; - - /** - * The name of the <tt>attributes</tt> attribute in the <tt>extmap</tt> - * element. - */ - public static final String ATTRIBUTES_ATTR_NAME = "attributes"; - - /** - * Creates a new {@link ExtmapPacketExtension} instance. - */ - public ExtmapPacketExtension() - { - super(null, ELEMENT_NAME); - } - - /** - * Sets the uri of the extmap attribute we are representing here. - * - * @param uri the uri of the extmap attribute we are representing here. - */ - public void setUri(URI uri) - { - super.setAttribute(URI_ATTR_NAME, uri.toString()); - } - - /** - * Returns the uri of the extmap attribute we are representing here. - * - * @return the uri of the extmap attribute we are representing here. - */ - public URI getUri() - { - return super.getAttributeAsURI(URI_ATTR_NAME); - } - - /** - * Sets that value of the extmap attribute we are representing here. - * - * @param value the value of the extmap attribute we are representing here. - */ - public void setValue(String value) - { - super.setAttribute(VALUE_ATTR_NAME, value); - } - - /** - * Returns the value of the extmap attribute we are representing here. - * - * @return the value of the extmap attribute we are representing here. - */ - public String getValue() - { - return super.getAttributeAsString(VALUE_ATTR_NAME); - } - - /** - * Sets the direction that this extmap element is to be transmitted in. - * - * @param direction the direction that this extmap element is to be - * transmitted in. - */ - public void setDirection(String direction) - { - super.setAttribute(DIRECTION_ATTR_NAME, direction); - } - - /** - * Returns the direction that this extmap element is to be transmitted in. - * - * @return the direction that this extmap element is to be transmitted in. - */ - public String getDirection() - { - return super.getAttributeAsString(DIRECTION_ATTR_NAME); - } - - /** - * Sets optional attributes for this extmap element. - * - * @param attributes optional attributes for this extmap element.. - */ - public void setAttributes(String attributes) - { - super.setAttribute(ATTRIBUTES_ATTR_NAME, attributes); - } - - /** - * Returns optional attributes for this extmap element. - * - * @return optional attributes for this extmap element. - */ - public String getAttributes() - { - return super.getAttributeAsString(ATTRIBUTES_ATTR_NAME); - } -} diff --git a/src/net/java/sip/communicator/impl/protocol/jabber/extensions/jingle/JingleIQProvider.java b/src/net/java/sip/communicator/impl/protocol/jabber/extensions/jingle/JingleIQProvider.java index 5eb137a..2ee93a5 100644 --- a/src/net/java/sip/communicator/impl/protocol/jabber/extensions/jingle/JingleIQProvider.java +++ b/src/net/java/sip/communicator/impl/protocol/jabber/extensions/jingle/JingleIQProvider.java @@ -59,12 +59,12 @@ public class JingleIQProvider implements IQProvider new DefaultPacketExtensionProvider <ParameterPacketExtension>(ParameterPacketExtension.class)); - //<extmap/> provider + //<rtp-hdrext/> provider providerManager.addExtensionProvider( - ExtmapPacketExtension.ELEMENT_NAME, - RtpDescriptionPacketExtension.NAMESPACE, + RTPHdrExtPacketExtension.ELEMENT_NAME, + RTPHdrExtPacketExtension.NAMESPACE, new DefaultPacketExtensionProvider - <ExtmapPacketExtension>(ExtmapPacketExtension.class)); + <RTPHdrExtPacketExtension>(RTPHdrExtPacketExtension.class)); //<zrtp-hash/> provider providerManager.addExtensionProvider( @@ -115,6 +115,13 @@ public class JingleIQProvider implements IQProvider new DefaultPacketExtensionProvider<InputEvtPacketExtension>( InputEvtPacketExtension.class)); + //coin <conference-info/> provider + providerManager.addExtensionProvider( + CoinPacketExtension.ELEMENT_NAME, + CoinPacketExtension.NAMESPACE, + new DefaultPacketExtensionProvider<CoinPacketExtension>( + CoinPacketExtension.class)); + /* * XEP-0251: Jingle Session Transfer <transfer/> and <transferred> * providers @@ -170,6 +177,9 @@ public class JingleIQProvider implements IQProvider DefaultPacketExtensionProvider<TransferPacketExtension> transferProvider = new DefaultPacketExtensionProvider<TransferPacketExtension>( TransferPacketExtension.class); + DefaultPacketExtensionProvider<CoinPacketExtension> coinProvider + = new DefaultPacketExtensionProvider<CoinPacketExtension>( + CoinPacketExtension.class); // Now go on and parse the jingle element's content. int eventType; @@ -206,6 +216,10 @@ public class JingleIQProvider implements IQProvider jingleIQ.addExtension( transferProvider.parseExtension(parser)); } + else if(elementName.equals(CoinPacketExtension.ELEMENT_NAME)) + { + jingleIQ.addExtension(coinProvider.parseExtension(parser)); + } //<mute/> <active/> and other session-info elements if (namespace.equals( SessionInfoPacketExtension.NAMESPACE)) diff --git a/src/net/java/sip/communicator/impl/protocol/jabber/extensions/jingle/JinglePacketFactory.java b/src/net/java/sip/communicator/impl/protocol/jabber/extensions/jingle/JinglePacketFactory.java index b3eb0a3..da8fd02 100644 --- a/src/net/java/sip/communicator/impl/protocol/jabber/extensions/jingle/JinglePacketFactory.java +++ b/src/net/java/sip/communicator/impl/protocol/jabber/extensions/jingle/JinglePacketFactory.java @@ -43,6 +43,33 @@ public class JinglePacketFactory * @param from our full jid * @param to their full jid * @param sid the ID of the Jingle session this IQ will belong to. + * + * @return a {@link JingleIQ} <tt>session-info</tt> packet carrying a + * the specified payload type. + */ + public static JingleIQ createSessionInfo(String from, + String to, + String sid) + { + JingleIQ sessionInfo = new JingleIQ(); + + sessionInfo.setFrom(from); + sessionInfo.setTo(to); + sessionInfo.setType(IQ.Type.SET); + + sessionInfo.setSID(sid); + sessionInfo.setAction(JingleAction.SESSION_INFO); + + return sessionInfo; + } + + /** + * Creates a {@link JingleIQ} <tt>session-info</tt> packet carrying a + * the specified payload type. + * + * @param from our full jid + * @param to their full jid + * @param sid the ID of the Jingle session this IQ will belong to. * @param type the exact type (e.g. ringing, hold, mute) of the session * info IQ. * @@ -54,15 +81,7 @@ public class JinglePacketFactory String sid, SessionInfoType type) { - JingleIQ ringing = new JingleIQ(); - - ringing.setFrom(from); - ringing.setTo(to); - ringing.setType(IQ.Type.SET); - - ringing.setSID(sid); - ringing.setAction(JingleAction.SESSION_INFO); - + JingleIQ ringing = createSessionInfo(from, to, sid); SessionInfoPacketExtension sessionInfoType = new SessionInfoPacketExtension(type); diff --git a/src/net/java/sip/communicator/impl/protocol/jabber/extensions/jingle/RTPHdrExtPacketExtension.java b/src/net/java/sip/communicator/impl/protocol/jabber/extensions/jingle/RTPHdrExtPacketExtension.java new file mode 100644 index 0000000..2ca8a57 --- /dev/null +++ b/src/net/java/sip/communicator/impl/protocol/jabber/extensions/jingle/RTPHdrExtPacketExtension.java @@ -0,0 +1,164 @@ +/* + * SIP Communicator, the OpenSource Java VoIP and Instant Messaging client. + * + * Distributable under LGPL license. + * See terms of license at gnu.org. + */ +package net.java.sip.communicator.impl.protocol.jabber.extensions.jingle; + +import java.net.*; + +import org.jivesoftware.smack.packet.*; + +import net.java.sip.communicator.impl.protocol.jabber.extensions.*; +import net.java.sip.communicator.impl.protocol.jabber.extensions.jingle.ContentPacketExtension.*; + +/** + * RTP header extension. + * + * @author Sebastien Vincent + */ +public class RTPHdrExtPacketExtension + extends AbstractPacketExtension +{ + /** + * The namespace. + */ + public static final String NAMESPACE = + "urn:xmpp:jingle:apps:rtp:rtp-hdrext:0"; + + /** + * The name of the "candidate" element. + */ + public static final String ELEMENT_NAME = "rtp-hdrext"; + + /** + * The name of the ID attribute. + */ + public static final String ID_ATTR_NAME = "id"; + + /** + * The name of the senders attribute. + */ + public static final String SENDERS_ATTR_NAME = "senders"; + + /** + * The name of the URI attribute. + */ + public static final String URI_ATTR_NAME = "uri"; + + /** + * The name of the <tt>attributes</tt> attribute in the <tt>extmap</tt> + * element. + */ + public static final String ATTRIBUTES_ATTR_NAME = "attributes"; + + /** + * Constructor. + */ + public RTPHdrExtPacketExtension() + { + super(NAMESPACE, ELEMENT_NAME); + } + + /** + * Set the ID. + * + * @param id ID to set + */ + public void setID(String id) + { + setAttribute(ID_ATTR_NAME, id); + } + + /** + * Get the ID. + * + * @return the ID + */ + public String getID() + { + return getAttributeAsString(ID_ATTR_NAME); + } + + /** + * Set the direction. + * + * @param senders the direction + */ + public void setSenders(SendersEnum senders) + { + setAttribute(SENDERS_ATTR_NAME, senders); + } + + /** + * Get the direction. + * + * @return the direction + */ + public SendersEnum getSenders() + { + String attributeVal = getAttributeAsString(SENDERS_ATTR_NAME); + + return attributeVal == null + ? null : SendersEnum.valueOf( attributeVal.toString() ); + } + + /** + * Set the URI. + * + * @param uri URI to set + */ + public void setURI(URI uri) + { + setAttribute(URI_ATTR_NAME, uri.toString()); + } + + /** + * Get the URI. + * + * @return the URI + */ + public URI getURI() + { + return getAttributeAsURI(URI_ATTR_NAME); + } + + /** + * Set attributes. + * + * @param attributes attributes value + */ + public void setAttributes(String attributes) + { + ParameterPacketExtension paramExt = + new ParameterPacketExtension(); + + paramExt.setName(ATTRIBUTES_ATTR_NAME); + paramExt.setValue(attributes); + addChildExtension(paramExt); + } + + /** + * Get "attributes" value. + * + * @return "attributes" value + */ + public String getAttributes() + { + for(PacketExtension ext : getChildExtensions()) + { + if(ext instanceof ParameterPacketExtension) + { + ParameterPacketExtension p = (ParameterPacketExtension)ext; + + if(p.getName().equals(ATTRIBUTES_ATTR_NAME)) + { + return p.getValue(); + } + } + } + return null; + } + +} diff --git a/src/net/java/sip/communicator/impl/protocol/jabber/extensions/jingle/RtpDescriptionPacketExtension.java b/src/net/java/sip/communicator/impl/protocol/jabber/extensions/jingle/RtpDescriptionPacketExtension.java index f381b6a..86af4a8 100644 --- a/src/net/java/sip/communicator/impl/protocol/jabber/extensions/jingle/RtpDescriptionPacketExtension.java +++ b/src/net/java/sip/communicator/impl/protocol/jabber/extensions/jingle/RtpDescriptionPacketExtension.java @@ -62,8 +62,8 @@ public class RtpDescriptionPacketExtension * A <tt>List</tt> of the optional <tt>extmap</tt> elements that allow * negotiating RTP extension headers as per RFC 5282. */ - private List<ExtmapPacketExtension> extmapList - = new ArrayList<ExtmapPacketExtension>(); + private List<RTPHdrExtPacketExtension> extmapList + = new ArrayList<RTPHdrExtPacketExtension>(); /** * The combined list of all child elements that this extension contains. @@ -197,8 +197,8 @@ public class RtpDescriptionPacketExtension else if (childExtension instanceof BandwidthPacketExtension) this.setBandwidth((BandwidthPacketExtension)childExtension); - else if (childExtension instanceof ExtmapPacketExtension) - this.addExtmap((ExtmapPacketExtension)childExtension); + else if (childExtension instanceof RTPHdrExtPacketExtension) + this.addExtmap((RTPHdrExtPacketExtension)childExtension); } /** @@ -256,7 +256,7 @@ public class RtpDescriptionPacketExtension * @param extmap an optional <tt>extmap</tt> element that allows negotiation * RTP extension headers as per RFC 5282. */ - public void addExtmap(ExtmapPacketExtension extmap) + public void addExtmap(RTPHdrExtPacketExtension extmap) { this.extmapList.add(extmap); } @@ -268,7 +268,7 @@ public class RtpDescriptionPacketExtension * @return a <tt>List</tt> of the optional <tt>extmap</tt> elements that * allow negotiating RTP extension headers as per RFC 5282. */ - public List<ExtmapPacketExtension> getExtmapList() + public List<RTPHdrExtPacketExtension> getExtmapList() { return extmapList; } diff --git a/src/net/java/sip/communicator/impl/protocol/jabber/jinglesdp/JingleUtils.java b/src/net/java/sip/communicator/impl/protocol/jabber/jinglesdp/JingleUtils.java index 50b0e85..40111f4 100644 --- a/src/net/java/sip/communicator/impl/protocol/jabber/jinglesdp/JingleUtils.java +++ b/src/net/java/sip/communicator/impl/protocol/jabber/jinglesdp/JingleUtils.java @@ -185,14 +185,14 @@ public class JingleUtils { List<RTPExtension> extensionsList = new ArrayList<RTPExtension>(); - List<ExtmapPacketExtension> extmapList = desc.getExtmapList(); + List<RTPHdrExtPacketExtension> extmapList = desc.getExtmapList(); - for (ExtmapPacketExtension extmap : extmapList) + for (RTPHdrExtPacketExtension extmap : extmapList) { RTPExtension rtpExtension = new RTPExtension( - extmap.getUri(), - MediaDirection.parseString(extmap.getDirection()), + extmap.getURI(), + getDirection(extmap.getSenders(), false), extmap.getAttributes()); if(rtpExtension != null) @@ -274,6 +274,30 @@ public class JingleUtils { SendersEnum senders = content.getSenders(); + return getDirection(senders, initiatorPerspective); + } + + /** + * Determines the direction of the media stream that <tt>content</tt> + * describes and returns the corresponding <tt>MediaDirection</tt> enum + * entry. The method looks for a direction specifier attribute (i.e. the + * content 'senders' attribute) or the absence thereof and returns the + * corresponding <tt>MediaDirection</tt> entry. The + * <tt>initiatorPerspectice</tt> allows callers to specify whether the + * direction is to be considered from the session initiator's perspective + * or that of the responder. + * + * @param senders senders direction + * @param initiatorPerspective <tt>true</tt> if the senders argument is to + * be translated into a direction from the initiator's perspective and + * <tt>false</tt> for the sender's. + * + * @return one of the <tt>MediaDirection</tt> values indicating the + * direction of the media steam described by <tt>content</tt>. + */ + public static MediaDirection getDirection(SendersEnum senders, + boolean initiatorPerspective) + { if(senders == null) return MediaDirection.SENDRECV; @@ -448,7 +472,7 @@ public class JingleUtils content.setCreator(creator); content.setName(contentName); - //senders - ony if we have them and if they are different from default + //senders - only if we have them and if they are different from default if(senders != null && senders != SendersEnum.both) content.setSenders(senders); @@ -463,6 +487,28 @@ public class JingleUtils formatToPayloadType(fmt, dynamicPayloadTypes)); } + // extmap attributes + if (rtpExtensions != null && rtpExtensions.size() > 0) + { + for (RTPExtension extension : rtpExtensions) + { + byte extID + = rtpExtensionsRegistry.obtainExtensionMapping(extension); + URI uri = extension.getURI(); + MediaDirection extDirection = extension.getDirection(); + String attributes = extension.getExtensionAttributes(); + SendersEnum sendersEnum = getSenders(extDirection, + false); + RTPHdrExtPacketExtension ext = new RTPHdrExtPacketExtension(); + + ext.setURI(uri); + ext.setSenders(sendersEnum); + ext.setID(Byte.toString(extID)); + ext.setAttributes(attributes); + + description.addChildExtension(ext); + } + } return content; } 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 450156b..d221d0c 100644 --- a/src/net/java/sip/communicator/impl/protocol/sip/OperationSetTelephonyConferencingSipImpl.java +++ b/src/net/java/sip/communicator/impl/protocol/sip/OperationSetTelephonyConferencingSipImpl.java @@ -9,7 +9,6 @@ package net.java.sip.communicator.impl.protocol.sip; import java.io.*; import java.text.*; import java.util.*; -import java.beans.*; import javax.sip.*; import javax.sip.address.*; @@ -42,10 +41,7 @@ public class OperationSetTelephonyConferencingSipImpl CallSipImpl, CallPeerSipImpl, Address> - implements CallChangeListener, - CallListener, - MethodProcessorListener, - PropertyChangeListener + implements MethodProcessorListener { /** @@ -146,45 +142,6 @@ public class OperationSetTelephonyConferencingSipImpl private static final int SUBSCRIPTION_DURATION = 3600; /** - * The <tt>CallPeerListener</tt> which listens to modifications in the - * properties/state of <tt>CallPeer</tt> so that NOTIFY requests can be sent - * from a conference focus to its conference members to update them with - * the latest information about the <tt>CallPeer</tt>. - */ - private final CallPeerListener callPeerListener = new CallPeerAdapter() - { - - /** - * Indicates that a change has occurred in the status of the source - * <tt>CallPeer</tt>. - * - * @param evt the <tt>CallPeerChangeEvent</tt> instance containing the - * source event as well as its previous and its new status - */ - @Override - public void peerStateChanged(CallPeerChangeEvent evt) - { - CallPeer peer = evt.getSourceCallPeer(); - - if (peer != null) - { - Call call = peer.getCall(); - - if (call != null) - { - CallPeerState state = peer.getState(); - - if ((state != null) - && !state.equals(CallPeerState.DISCONNECTED) - && !state.equals(CallPeerState.FAILED)) - OperationSetTelephonyConferencingSipImpl.this - .notifyAll(call); - } - } - } - }; - - /** * The utility which encodes text so that it's acceptable as the text of an * XML element or attribute. */ @@ -287,60 +244,6 @@ public class OperationSetTelephonyConferencingSipImpl } /** - * Notifies this <tt>CallListener</tt> that a specific <tt>Call</tt> has - * been established. - * - * @param event a <tt>CallEvent</tt> which specified the newly-established - * <tt>Call</tt> - */ - private void callBegun(CallEvent event) - { - Call call = event.getSourceCall(); - - call.addCallChangeListener(this); - - /* - * If there were any CallPeers in the Call prior to our realization that - * it has begun, pretend that they are added afterwards. - */ - Iterator<? extends CallPeer> callPeerIter = call.getCallPeers(); - - while (callPeerIter.hasNext()) - callPeerAdded( - new CallPeerEvent( - callPeerIter.next(), - call, - CallPeerEvent.CALL_PEER_ADDED)); - } - - /** - * Notifies this <tt>CallListener</tt> that a specific <tt>Call</tt> has - * ended. - * - * @param event a <tt>CallEvent</tt> which specified the <tt>Call</tt> which - * has just ended - */ - public void callEnded(CallEvent event) - { - Call call = event.getSourceCall(); - - /* - * If there are still CallPeers after our realization that it has ended, - * pretend that they are removed before that. - */ - Iterator<? extends CallPeer> callPeerIter = call.getCallPeers(); - - while (callPeerIter.hasNext()) - callPeerRemoved( - new CallPeerEvent( - callPeerIter.next(), - call, - CallPeerEvent.CALL_PEER_REMOVED)); - - call.removeCallChangeListener(this); - } - - /** * Notifies this <tt>CallChangeListener</tt> that a specific * <tt>CallPeer</tt> has been added to a specific <tt>Call</tt>. * @@ -350,12 +253,8 @@ public class OperationSetTelephonyConferencingSipImpl public void callPeerAdded(CallPeerEvent event) { CallPeerSipImpl callPeer = (CallPeerSipImpl) event.getSourceCallPeer(); - callPeer.addMethodProcessorListener(this); - callPeer.addCallPeerListener(callPeerListener); - callPeer.getMediaHandler().addPropertyChangeListener(this); - - callPeersChanged(event); + super.callPeerAdded(event); } /** @@ -368,37 +267,8 @@ public class OperationSetTelephonyConferencingSipImpl public void callPeerRemoved(CallPeerEvent event) { CallPeerSipImpl callPeer = (CallPeerSipImpl) event.getSourceCallPeer(); - callPeer.removeMethodProcessorListener(this); - callPeer.removeCallPeerListener(callPeerListener); - callPeer.getMediaHandler().removePropertyChangeListener(this); - - callPeersChanged(event); - } - - /** - * Notifies this <tt>CallChangeListener</tt> that the <tt>CallPeer</tt> list - * of a specific <tt>Call</tt> has been modified by adding or removing a - * specific <tt>CallPeer</tt>. - * - * @param event a <tt>CallPeerEvent</tt> which specifies the - * <tt>CallPeer</tt> which has been added to or removed from a <tt>Call</tt> - */ - private void callPeersChanged(CallPeerEvent event) - { - notifyAll(event.getSourceCall()); - } - - /** - * Notifies this <tt>CallChangeListener</tt> that a specific <tt>Call</tt> - * has changed its state. Does nothing. - * - * @param event a <tt>CallChangeEvent</tt> which specifies the <tt>Call</tt> - * which has changed its state, the very state which has been changed and - * the values of the state before and after the change - */ - public void callStateChanged(CallChangeEvent event) - { + super.callPeerRemoved(event); } /** @@ -760,18 +630,6 @@ public class OperationSetTelephonyConferencingSipImpl } /** - * Notifies this <tt>CallListener</tt> that a specific incoming - * <tt>Call</tt> has been received. - * - * @param event a <tt>CallEvent</tt> which specifies the newly-received - * incoming <tt>Call</tt> - */ - public void incomingCallReceived(CallEvent event) - { - callBegun(event); - } - - /** * Invites a callee with a specific SIP <tt>Address</tt> to be joined in a * specific <tt>Call</tt> in the sense of SIP conferencing. * @@ -878,7 +736,7 @@ public class OperationSetTelephonyConferencingSipImpl * @param call the <tt>Call</tt> in which the <tt>Subscription</tt>s to be * notified have been established */ - private void notifyAll(Call call) + protected void notifyAll(Call call) { notifyAll(SubscriptionStateHeader.ACTIVE, null, call); } @@ -929,18 +787,6 @@ public class OperationSetTelephonyConferencingSipImpl } /** - * Notifies this <tt>CallListener</tt> that a specific outgoing - * <tt>Call</tt> has been created. - * - * @param event a <tt>CallEvent</tt> which specifies the newly-created - * outgoing <tt>Call</tt> - */ - public void outgoingCallCreated(CallEvent event) - { - callBegun(event); - } - - /** * Parses a <tt>String</tt> value which represents a SIP address into a SIP * <tt>Address</tt> value. * @@ -971,32 +817,6 @@ public class OperationSetTelephonyConferencingSipImpl } /** - * Notifies this <tt>PropertyChangeListener</tt> that the value of a - * specific property of the notifier it is registered with has changed. - * - * @param event a <tt>PropertyChangeEvent</tt> which describes the source of - * 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) - */ - public void propertyChange(PropertyChangeEvent event) - { - String propertyName = event.getPropertyName(); - - if (CallPeerMediaHandlerSipImpl.AUDIO_LOCAL_SSRC.equals(propertyName) - || CallPeerMediaHandlerSipImpl.AUDIO_REMOTE_SSRC.equals(propertyName) - || CallPeerMediaHandlerSipImpl.VIDEO_LOCAL_SSRC.equals(propertyName) - || CallPeerMediaHandlerSipImpl.VIDEO_REMOTE_SSRC.equals(propertyName)) - { - Call call = ((CallPeerMediaHandlerSipImpl) event.getSource()) - .getPeer().getCall(); - - if (call != null) - notifyAll(call); - } - } - - /** * Notifies this <tt>MethodProcessorListener</tt> that a specific * <tt>CallPeer</tt> has processed a specific SIP <tt>Request</tt> and has * replied to it with a specific SIP <tt>Response</tt>. diff --git a/src/net/java/sip/communicator/service/protocol/ActiveCallsRepository.java b/src/net/java/sip/communicator/service/protocol/ActiveCallsRepository.java index fc21e25..c9ab985 100644 --- a/src/net/java/sip/communicator/service/protocol/ActiveCallsRepository.java +++ b/src/net/java/sip/communicator/service/protocol/ActiveCallsRepository.java @@ -17,6 +17,8 @@ import net.java.sip.communicator.util.*; * and others. This class is meant for use by protocol implementations and * cannot be accessed from other bundles. * + * @param <T> <tt>Call</tt> + * @param <U> <tt>OperationSetBasicTelephony</tt> * @author Emil Ivov */ public abstract class ActiveCallsRepository<T extends Call, 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 2ef7501..2095fee 100644 --- a/src/net/java/sip/communicator/service/protocol/media/AbstractOperationSetTelephonyConferencing.java +++ b/src/net/java/sip/communicator/service/protocol/media/AbstractOperationSetTelephonyConferencing.java @@ -6,6 +6,7 @@ */ package net.java.sip.communicator.service.protocol.media; +import java.beans.*; import java.util.*; import net.java.sip.communicator.service.protocol.*; @@ -41,7 +42,10 @@ public abstract class AbstractOperationSetTelephonyConferencing< ProtocolProviderServiceT>, CalleeAddressT extends Object> implements OperationSetTelephonyConferencing, - RegistrationStateChangeListener + RegistrationStateChangeListener, + PropertyChangeListener, + CallListener, + CallChangeListener { /** @@ -58,6 +62,46 @@ public abstract class AbstractOperationSetTelephonyConferencing< protected final ProtocolProviderServiceT parentProvider; /** + * The <tt>CallPeerListener</tt> which listens to modifications in the + * properties/state of <tt>CallPeer</tt> so that NOTIFY requests can be sent + * from a conference focus to its conference members to update them with + * the latest information about the <tt>CallPeer</tt>. + */ + private final CallPeerListener callPeerListener = new CallPeerAdapter() + { + /** + * Indicates that a change has occurred in the status of the source + * <tt>CallPeer</tt>. + * + * @param evt the <tt>CallPeerChangeEvent</tt> instance containing the + * source event as well as its previous and its new status + */ + @Override + public void peerStateChanged(CallPeerChangeEvent evt) + { + CallPeer peer = evt.getSourceCallPeer(); + + if (peer != null) + { + Call call = peer.getCall(); + + if (call != null) + { + CallPeerState state = peer.getState(); + + if ((state != null) + && !state.equals(CallPeerState.DISCONNECTED) + && !state.equals(CallPeerState.FAILED)) + { + AbstractOperationSetTelephonyConferencing.this + .notifyAll(call); + } + } + } + } + }; + + /** * Initializes a new <tt>AbstractOperationSetTelephonyConferencing</tt> * instance which is to provide telephony conferencing services for the * specified <tt>ProtocolProviderService</tt> implementation. @@ -266,4 +310,184 @@ public abstract class AbstractOperationSetTelephonyConferencing< } } } + + /** + * Notifies this <tt>CallChangeListener</tt> that a specific + * <tt>CallPeer</tt> has been added to a specific <tt>Call</tt>. + * + * @param event a <tt>CallPeerEvent</tt> which specifies the + * <tt>CallPeer</tt> which has been added to a <tt>Call</tt> + */ + @SuppressWarnings("unchecked") + public void callPeerAdded(CallPeerEvent event) + { + MediaAwareCallPeerT callPeer = + (MediaAwareCallPeerT)event.getSourceCallPeer(); + + callPeer.addCallPeerListener(callPeerListener); + callPeer.getMediaHandler().addPropertyChangeListener(this); + callPeersChanged(event); + } + + /** + * Notifies this <tt>CallChangeListener</tt> that a specific + * <tt>CallPeer</tt> has been remove from a specific <tt>Call</tt>. + * + * @param event a <tt>CallPeerEvent</tt> which specifies the + * <tt>CallPeer</tt> which has been removed from a <tt>Call</tt> + */ + @SuppressWarnings("unchecked") + public void callPeerRemoved(CallPeerEvent event) + { + MediaAwareCallPeerT callPeer = + (MediaAwareCallPeerT) event.getSourceCallPeer(); + + callPeer.removeCallPeerListener(callPeerListener); + callPeer.getMediaHandler().removePropertyChangeListener(this); + callPeersChanged(event); + } + + /** + * Notifies this <tt>CallChangeListener</tt> that the <tt>CallPeer</tt> list + * of a specific <tt>Call</tt> has been modified by adding or removing a + * specific <tt>CallPeer</tt>. + * + * @param event a <tt>CallPeerEvent</tt> which specifies the + * <tt>CallPeer</tt> which has been added to or removed from a <tt>Call</tt> + */ + private void callPeersChanged(CallPeerEvent event) + { + notifyAll(event.getSourceCall()); + } + + /** + * Notifies this <tt>PropertyChangeListener</tt> that the value of a + * specific property of the notifier it is registered with has changed. + * + * @param event a <tt>PropertyChangeEvent</tt> which describes the source of + * 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) + { + String propertyName = event.getPropertyName(); + + if (CallPeerMediaHandler.AUDIO_LOCAL_SSRC.equals( + propertyName) + || CallPeerMediaHandler.AUDIO_REMOTE_SSRC.equals( + propertyName) + || CallPeerMediaHandler.VIDEO_LOCAL_SSRC.equals( + propertyName) + || CallPeerMediaHandler.VIDEO_REMOTE_SSRC.equals( + propertyName)) + { + Call call = ((CallPeerMediaHandler<MediaAwareCallPeerT>) + event.getSource()).getPeer().getCall(); + + if (call != null) + { + notifyAll(call); + } + } + } + + /** + * Notifies this <tt>CallListener</tt> that a specific incoming + * <tt>Call</tt> has been received. + * + * @param event a <tt>CallEvent</tt> which specifies the newly-received + * incoming <tt>Call</tt> + */ + public void incomingCallReceived(CallEvent event) + { + callBegun(event); + } + + /** + * Notifies this <tt>CallListener</tt> that a specific outgoing + * <tt>Call</tt> has been created. + * + * @param event a <tt>CallEvent</tt> which specifies the newly-created + * outgoing <tt>Call</tt> + */ + public void outgoingCallCreated(CallEvent event) + { + callBegun(event); + } + + /** + * Notifies this <tt>CallListener</tt> that a specific <tt>Call</tt> has + * ended. + * + * @param event a <tt>CallEvent</tt> which specified the <tt>Call</tt> which + * has just ended + */ + public void callEnded(CallEvent event) + { + Call call = event.getSourceCall(); + + /* + * If there are still CallPeers after our realization that it has ended, + * pretend that they are removed before that. + */ + Iterator<? extends CallPeer> callPeerIter = call.getCallPeers(); + + while (callPeerIter.hasNext()) + callPeerRemoved( + new CallPeerEvent( + callPeerIter.next(), + call, + CallPeerEvent.CALL_PEER_REMOVED)); + + call.removeCallChangeListener(this); + } + + /** + * Notifies this <tt>CallListener</tt> that a specific <tt>Call</tt> has + * been established. + * + * @param event a <tt>CallEvent</tt> which specified the newly-established + * <tt>Call</tt> + */ + protected void callBegun(CallEvent event) + { + Call call = event.getSourceCall(); + + call.addCallChangeListener(this); + + /* + * If there were any CallPeers in the Call prior to our realization that + * it has begun, pretend that they are added afterwards. + */ + Iterator<? extends CallPeer> callPeerIter = call.getCallPeers(); + + while (callPeerIter.hasNext()) + callPeerAdded( + new CallPeerEvent( + callPeerIter.next(), + call, + CallPeerEvent.CALL_PEER_ADDED)); + } + + /** + * Notifies this <tt>CallChangeListener</tt> that a specific <tt>Call</tt> + * has changed its state. Does nothing. + * + * @param event a <tt>CallChangeEvent</tt> which specifies the <tt>Call</tt> + * which has changed its state, the very state which has been changed and + * the values of the state before and after the change + */ + public void callStateChanged(CallChangeEvent event) + { + } + + /** + * Notifies all CallPeer associated with and established in a + * specific call for conference information. + * + * @param call the <tt>Call</tt> + */ + protected abstract void notifyAll(Call call); } |