diff --git a/src/net/java/sip/communicator/impl/protocol/sip/CallPeerMediaHandlerSipImpl.java b/src/net/java/sip/communicator/impl/protocol/sip/CallPeerMediaHandlerSipImpl.java
index d7d347702..c3a3df27f 100644
--- a/src/net/java/sip/communicator/impl/protocol/sip/CallPeerMediaHandlerSipImpl.java
+++ b/src/net/java/sip/communicator/impl/protocol/sip/CallPeerMediaHandlerSipImpl.java
@@ -105,7 +105,7 @@ public CallPeerMediaHandlerSipImpl(CallPeerSipImpl peer)
/**
* Creates a session description String representing the
- * MediaStreams that this MediaHandler is prepare to
+ * MediaStreams that this MediaHandler is prepared to
* exchange. The offer takes into account user preferences such as whether
* or not local user would be transmitting video, whether any or all streams
* are put on hold, etc. The method is also taking into account any previous
@@ -127,6 +127,14 @@ public String createOffer()
? createFirstOffer()
: createUpdateOffer(localSess);
+ if (getConfigurationService().getBoolean(
+ ProtocolProviderServiceSipImpl
+ .USE_SESSION_LEVEL_DIRECTION_IN_SDP,
+ false))
+ {
+ SdpUtils.setSessionDirection(offer);
+ }
+
return offer.toString();
}
@@ -378,10 +386,19 @@ public String processOffer(String offerString)
synchronized (offerAnswerLock)
{
- if (localSess == null)
- return processFirstOffer(offer).toString();
- else
- return processUpdateOffer(offer, localSess).toString();
+ SessionDescription answer = (localSess == null)
+ ? processFirstOffer(offer)
+ : processUpdateOffer(offer, localSess);
+
+ if (getConfigurationService().getBoolean(
+ ProtocolProviderServiceSipImpl
+ .USE_SESSION_LEVEL_DIRECTION_IN_SDP,
+ false))
+ {
+ SdpUtils.setSessionDirection(answer);
+ }
+
+ return answer.toString();
}
}
diff --git a/src/net/java/sip/communicator/impl/protocol/sip/ProtocolProviderServiceSipImpl.java b/src/net/java/sip/communicator/impl/protocol/sip/ProtocolProviderServiceSipImpl.java
index 44673b2b4..a63333e01 100644
--- a/src/net/java/sip/communicator/impl/protocol/sip/ProtocolProviderServiceSipImpl.java
+++ b/src/net/java/sip/communicator/impl/protocol/sip/ProtocolProviderServiceSipImpl.java
@@ -127,6 +127,15 @@ public class ProtocolProviderServiceSipImpl
private static final String IS_MESSAGING_DISABLED
= "net.java.sip.communicator.impl.protocol.sip.MESSAGING_DISABLED";
+ /**
+ * The name of the property which, if enabled, will cause a session-level
+ * attribute for the session direction (e.g. a=sendonly, a=recvonly) to be
+ * added to SDP offers/answers which we send.
+ */
+ public static final String USE_SESSION_LEVEL_DIRECTION_IN_SDP
+ = "net.java.sip.communicator.impl.protocol.sip."
+ + "USE_SESSION_LEVEL_DIRECTION_IN_SDP";
+
/**
* Default number of times that our requests can be forwarded.
*/
diff --git a/src/net/java/sip/communicator/impl/protocol/sip/sdp/SdpUtils.java b/src/net/java/sip/communicator/impl/protocol/sip/sdp/SdpUtils.java
index 42f1fd4d1..34e6168f8 100644
--- a/src/net/java/sip/communicator/impl/protocol/sip/sdp/SdpUtils.java
+++ b/src/net/java/sip/communicator/impl/protocol/sip/sdp/SdpUtils.java
@@ -1581,11 +1581,10 @@ public static MediaType getMediaType(MediaDescription description)
}
/**
- * Returns the media type (e.g. audio or video) for the specified media
- * whether it contains the specified attributeName.
+ * Returns whether description contains the specified
+ * attributeName.
*
- * @param description the MediaDescription whose media type we'd
- * like to extract.
+ * @param description the MediaDescription
* @param attributeName name of the attribute to check
* @return the media type (e.g. audio or video) for the specified media
* description.
@@ -1769,4 +1768,87 @@ public static void setIceCredentials(SessionDescription sDes,
{
IceSdpUtils.setIceCredentials(sDes, uFrag, pwd);
}
+
+ /**
+ * Adds an inactive|sendonly|recvonly|sendrecv session-level attribute to
+ * sdp, according to the directions of the media descriptions in
+ * sdp.
+ *
+ * @param sdp the SessionDescription to which to add an attribute.
+ */
+ public static void setSessionDirection(SessionDescription sdp)
+ {
+ MediaDirection direction = MediaDirection.INACTIVE;
+
+ //find out what direction we should use for the session
+ try
+ {
+ Vector medias = sdp.getMediaDescriptions(false);
+ if (medias != null)
+ {
+ for (Object o : medias)
+ {
+ if (o instanceof MediaDescription)
+ {
+ MediaDescription md = (MediaDescription) o;
+
+ // consider medias with port 0 inactive
+ if (md.getMedia().getMediaPort() != 0)
+ {
+ direction = direction.or(
+ getDirection((MediaDescription) o));
+ }
+ }
+ }
+ }
+ }
+ catch (SdpException se)
+ {
+ logger.warn("Failed to get media descriptions.");
+ }
+
+
+ // now set the session-level attribute
+ Vector attributes = sdp.getAttributes(true);
+ Iterator iter = attributes.iterator();
+
+ // first clear previous direction attributes
+ while (iter.hasNext())
+ {
+ Object o = iter.next();
+ if (o instanceof Attribute)
+ {
+ try
+ {
+ String name = ((Attribute) o).getName();
+ if ("inactive".equals(name)
+ || "sendonly".equals(name)
+ || "recvonly".equals(name)
+ || "sendrecv".equals(name))
+ {
+ iter.remove();
+ }
+ }
+ catch (SdpException se)
+ {
+ if (logger.isDebugEnabled())
+ logger.debug("Failed to get attribute name: ", se);
+
+ }
+ }
+ }
+
+ // By RFC4566 section 6, if we skip "sendrecv", it SHOULD be assumed.
+ if (!MediaDirection.SENDRECV.equals(direction))
+ attributes.add(createDirectionAttribute(direction));
+
+ try
+ {
+ sdp.setAttributes(attributes);
+ }
+ catch (SdpException se)
+ {
+ logger.warn("Failed to set session direction attribute.");
+ }
+ }
}