aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSebastien Vincent <seb@jitsi.org>2011-04-01 09:50:31 +0000
committerSebastien Vincent <seb@jitsi.org>2011-04-01 09:50:31 +0000
commit95788da2d130b6498719a325849b8ed318f9fdfc (patch)
tree461a8948ffa4f143563051245f3275099ceed6e8
parentf81ff286431c2965f705a7bdcacd22596d09b618 (diff)
downloadjitsi-95788da2d130b6498719a325849b8ed318f9fdfc.zip
jitsi-95788da2d130b6498719a325849b8ed318f9fdfc.tar.gz
jitsi-95788da2d130b6498719a325849b8ed318f9fdfc.tar.bz2
Add Coin (Conference Information) support and audio levels in XMPP conference.
-rw-r--r--src/net/java/sip/communicator/impl/gui/main/call/CallPanel.java6
-rw-r--r--src/net/java/sip/communicator/impl/gui/main/call/conference/ConferencePeerPanel.java5
-rw-r--r--src/net/java/sip/communicator/impl/neomedia/MediaUtils.java4
-rw-r--r--src/net/java/sip/communicator/impl/neomedia/device/VideoMediaDeviceSession.java2
-rw-r--r--src/net/java/sip/communicator/impl/protocol/jabber/CallJabberImpl.java13
-rw-r--r--src/net/java/sip/communicator/impl/protocol/jabber/CallPeerJabberImpl.java41
-rw-r--r--src/net/java/sip/communicator/impl/protocol/jabber/ConferenceMemberJabberImpl.java133
-rw-r--r--src/net/java/sip/communicator/impl/protocol/jabber/OperationSetBasicTelephonyJabberImpl.java14
-rw-r--r--src/net/java/sip/communicator/impl/protocol/jabber/OperationSetTelephonyConferencingJabberImpl.java603
-rw-r--r--src/net/java/sip/communicator/impl/protocol/jabber/ProtocolProviderServiceJabberImpl.java23
-rw-r--r--src/net/java/sip/communicator/impl/protocol/jabber/extensions/AbstractPacketExtension.java4
-rw-r--r--src/net/java/sip/communicator/impl/protocol/jabber/extensions/coin/CoinIQ.java190
-rw-r--r--src/net/java/sip/communicator/impl/protocol/jabber/extensions/coin/CoinIQProvider.java154
-rw-r--r--src/net/java/sip/communicator/impl/protocol/jabber/extensions/coin/DescriptionPacketExtension.java190
-rw-r--r--src/net/java/sip/communicator/impl/protocol/jabber/extensions/coin/DescriptionProvider.java79
-rw-r--r--src/net/java/sip/communicator/impl/protocol/jabber/extensions/coin/DisconnectionType.java82
-rw-r--r--src/net/java/sip/communicator/impl/protocol/jabber/extensions/coin/EndpointPacketExtension.java227
-rw-r--r--src/net/java/sip/communicator/impl/protocol/jabber/extensions/coin/EndpointProvider.java108
-rw-r--r--src/net/java/sip/communicator/impl/protocol/jabber/extensions/coin/EndpointStatusType.java107
-rw-r--r--src/net/java/sip/communicator/impl/protocol/jabber/extensions/coin/ExecutionPacketExtension.java192
-rw-r--r--src/net/java/sip/communicator/impl/protocol/jabber/extensions/coin/HostInfoPacketExtension.java137
-rw-r--r--src/net/java/sip/communicator/impl/protocol/jabber/extensions/coin/JoiningType.java77
-rw-r--r--src/net/java/sip/communicator/impl/protocol/jabber/extensions/coin/MediaPacketExtension.java251
-rw-r--r--src/net/java/sip/communicator/impl/protocol/jabber/extensions/coin/MediaProvider.java97
-rw-r--r--src/net/java/sip/communicator/impl/protocol/jabber/extensions/coin/MediaStatusType.java35
-rw-r--r--src/net/java/sip/communicator/impl/protocol/jabber/extensions/coin/StatePacketExtension.java174
-rw-r--r--src/net/java/sip/communicator/impl/protocol/jabber/extensions/coin/StateProvider.java78
-rw-r--r--src/net/java/sip/communicator/impl/protocol/jabber/extensions/coin/StateType.java51
-rw-r--r--src/net/java/sip/communicator/impl/protocol/jabber/extensions/coin/UserPacketExtension.java123
-rw-r--r--src/net/java/sip/communicator/impl/protocol/jabber/extensions/coin/UserProvider.java94
-rw-r--r--src/net/java/sip/communicator/impl/protocol/jabber/extensions/coin/UsersPacketExtension.java41
-rw-r--r--src/net/java/sip/communicator/impl/protocol/jabber/extensions/coin/UsersProvider.java83
-rw-r--r--src/net/java/sip/communicator/impl/protocol/jabber/extensions/jingle/CoinPacketExtension.java53
-rw-r--r--src/net/java/sip/communicator/impl/protocol/jabber/extensions/jingle/ExtmapPacketExtension.java136
-rw-r--r--src/net/java/sip/communicator/impl/protocol/jabber/extensions/jingle/JingleIQProvider.java22
-rw-r--r--src/net/java/sip/communicator/impl/protocol/jabber/extensions/jingle/JinglePacketFactory.java37
-rw-r--r--src/net/java/sip/communicator/impl/protocol/jabber/extensions/jingle/RTPHdrExtPacketExtension.java164
-rw-r--r--src/net/java/sip/communicator/impl/protocol/jabber/extensions/jingle/RtpDescriptionPacketExtension.java12
-rw-r--r--src/net/java/sip/communicator/impl/protocol/jabber/jinglesdp/JingleUtils.java56
-rw-r--r--src/net/java/sip/communicator/impl/protocol/sip/OperationSetTelephonyConferencingSipImpl.java188
-rw-r--r--src/net/java/sip/communicator/service/protocol/ActiveCallsRepository.java2
-rw-r--r--src/net/java/sip/communicator/service/protocol/media/AbstractOperationSetTelephonyConferencing.java226
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);
}