From d8e439eb41dcbc34d4309a16cede7e6138cf76f3 Mon Sep 17 00:00:00 2001 From: Emil Ivov Date: Thu, 5 Nov 2009 20:29:23 +0000 Subject: [PATCH] Migrates SIP over to neomedia. (Work in progress). Parsing remote RTP+RTCP target from SDP --- .../impl/protocol/sip/sdp/SdpUtils.java | 157 +++++++++++++++++- 1 file changed, 150 insertions(+), 7 deletions(-) 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 2dd75e1ee..fe6a45642 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 @@ -36,6 +36,11 @@ public class SdpUtils */ private static final SdpFactory sdpFactory = SdpFactory.getInstance(); + /** + * The name of the SDP attribute that contains RTCP address and port. + */ + private static final String RTCP_ATTR = "rtcp"; + /** * Creates an empty instance of a SessionDescription with * preinitialized s, v, and t parameters. @@ -448,10 +453,11 @@ public static MediaStreamTarget extractDefaultTarget( "Couldn't extract connection address.", exc); } - InetAddress inetAddress = null; + InetAddress rtpAddress = null; + try { - inetAddress = NetworkUtils.getInetAddress(address); + rtpAddress = NetworkUtils.getInetAddress(address); } catch (UnknownHostException exc) { @@ -459,11 +465,148 @@ public static MediaStreamTarget extractDefaultTarget( "Failed to parse address " + address, exc); } - //ip address (media or session level c) - //rtp port - //rtcp port ( and address? ) - return null; + int rtpPort; + try + { + rtpPort = mediaDesc.getMedia().getMediaPort(); + } + catch (SdpParseException exc) + { + throw new IllegalArgumentException( + "Couldn't extract port from a media description.", exc); + } + + InetSocketAddress rtpTarget = new InetSocketAddress( + rtpAddress, rtpPort); + + + //by default RTP and RTCP will be going to the same address (which is + //actually going to be the case 99% of the time. + InetAddress rtcpAddress = rtpAddress; + int rtcpPort = rtpPort + 1; + + String rtcpAttributeValue; + try + { + rtcpAttributeValue = mediaDesc.getAttribute(RTCP_ATTR); + } + catch (SdpParseException exc) + { + //this can't actually happen as there's no parsing here. the + //exception is just inherited from the jain-sdp api. we are + //rethrowing only because there's nothing else we could do. + throw new IllegalArgumentException( + "Couldn't extract attribute value.", exc); + } + + InetSocketAddress rtcpTarget = determineRtcpAddress( + rtcpAttributeValue, rtcpAddress, rtcpPort); + + return new MediaStreamTarget(rtpTarget, rtcpTarget); + } + + /** + * Determines the address and port where our interlocutor would like to + * receive RTCP. The method uses the port, and possibly address, indicated + * in the rtcpAttribute or returns the default + * defaultAddr:defaultPort in case rtcpAttribute is null. + * We also use defaultAddr in case rtcpAttribute only + * contains a port number and no address. + * + * @param rtcpAttrValue the SDP Attribute where we are supposed + * to look for an RTCP address and port (could be null if there + * was no such field in the incoming SDP); + * @param defaultAddr the address that we should use to construct the result + * InetSocketAddress in case rtcpAttribute is + * null or in case rtcpAttribute only contains a port + * number. + * @param defaultPort the port that we should use to construct the result + * InetSocketAddress in case rtcpAttribute is + * null. + * + * @return an InetSocketAddress instance indicating the destination + * where should be sending RTCP. + * + * @throws IllegalArgumentException if an error occurs while parsing the + * rtcpAttribute. + */ + private static InetSocketAddress determineRtcpAddress( + String rtcpAttrValue, + InetAddress defaultAddr, + int defaultPort) + throws IllegalArgumentException + { + if (rtcpAttrValue == null) + { + //no explicit RTCP attribute means RTCP goes to RTP.port + 1 + return new InetSocketAddress(defaultAddr, defaultPort); + } + + if (rtcpAttrValue == null || rtcpAttrValue.trim().length() == 0) + { + //invalid attribute. return default port. + return new InetSocketAddress(defaultAddr, defaultPort); + } + + StringTokenizer rtcpTokenizer + = new StringTokenizer(rtcpAttrValue.trim(), " "); + + // RTCP attribtutes are supposed to look this way: + // rtcp-attribute = "a=rtcp:" port [nettype space addrtype space + // connection-address] CRLF + // which gives us 2 cases: port only (1 token), or port+addr (4 tokens) + + int tokenCount = rtcpTokenizer.countTokens(); + + //a single token means we only have a port number. + int rtcpPort; + try + { + rtcpPort = Integer.parseInt( rtcpTokenizer.nextToken() ); + } + catch (NumberFormatException exc) + { + //rtcp attribute is messed up. + throw new IllegalArgumentException( + "Error while parsing rtcp attribute: " + rtcpAttrValue, exc); + } + + if ( tokenCount == 1 ) + { + //that was all then. ready to return. + return new InetSocketAddress(defaultAddr, rtcpPort); + } + else if ( tokenCount == 4) + { + rtcpTokenizer.nextToken();//nettype + rtcpTokenizer.nextToken();//addrtype + + //address + String rtcpAddrStr = rtcpTokenizer.nextToken(); + + InetAddress rtcpAddress = null; + + try + { + rtcpAddress = NetworkUtils.getInetAddress(rtcpAddrStr); + } + catch (UnknownHostException exc) + { + throw new IllegalArgumentException( + "Failed to parse address " + rtcpAddress, exc); + } + + return new InetSocketAddress(rtcpAddress, rtcpPort); + } + else + { + //rtcp attribute is messed up: too many tokens. + throw new IllegalArgumentException( + "Error while parsing rtcp attribute: " + + rtcpAttrValue + ". Too many tokens! (" + + tokenCount + ")"); + } } public static MediaDirection getDirection( MediaDescription mediaDesc ) @@ -576,7 +719,7 @@ public static MediaDescription createMediaDescription( if ((rtpPort + 1) != rtcpPort) { - Attribute rtcpAttr = sdpFactory.createAttribute("rtcp:", Integer + Attribute rtcpAttr = sdpFactory.createAttribute(RTCP_ATTR, Integer .toString(rtcpPort)); mediaAttributes.add(rtcpAttr); }