From cb468c1429287b9267b41b092fa583e5adf4697d Mon Sep 17 00:00:00 2001 From: Boris Grozev Date: Thu, 13 Mar 2014 11:38:46 +0100 Subject: [PATCH] Adds a property to allow setting the direction of a session with a session-level attribute in SDP. --- .../sip/CallPeerMediaHandlerSipImpl.java | 27 ++++-- .../sip/ProtocolProviderServiceSipImpl.java | 9 ++ .../impl/protocol/sip/sdp/SdpUtils.java | 90 ++++++++++++++++++- 3 files changed, 117 insertions(+), 9 deletions(-) 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."); + } + } }