2 p2pproxy Copyright (C) 2007 Jehan Monnier ()
4 SdpProcessorImpl.java - .
6 This program is free software; you can redistribute it and/or
7 modify it under the terms of the GNU General Public License
8 as published by the Free Software Foundation; either version 2
9 of the License, or (at your option) any later version.
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
20 package org.linphone.p2pproxy.core.media.rtprelay;
22 import java.net.InetSocketAddress;
24 import java.util.StringTokenizer;
26 import net.jxta.pipe.OutputPipe;
28 import org.apache.log4j.Logger;
29 import org.linphone.p2pproxy.api.P2pProxyException;
30 import org.linphone.p2pproxy.api.P2pProxyRtpRelayManagement;
31 import org.linphone.p2pproxy.core.sipproxy.SdpProcessor;
32 import org.linphone.p2pproxy.core.sipproxy.SipProxyRegistrar.Registration;
33 import org.zoolu.sdp.AttributeField;
34 import org.zoolu.sdp.ConnectionField;
35 import org.zoolu.sdp.MediaDescriptor;
36 import org.zoolu.sdp.MediaField;
37 import org.zoolu.sdp.SessionDescriptor;
38 import org.zoolu.sip.message.Message;
41 * rewrite SDP to insert an ICE aware rtp relay
45 public class IceSdpProcessorImpl implements SdpProcessor {
46 private final String CANDIDATE_RELAY_NAME="relay";
48 class CandidateAttributeParser {
49 final private String mCandidateAttribute;
51 final private String mfoundation;
52 final private String mComponentId;
53 final private String mTransport;
54 final private String mPriority;
55 final private String mConnectionAddress;
56 final private String mPort;
57 final private String mType;
59 public CandidateAttributeParser(String aCandidateAttribute){
60 mCandidateAttribute = aCandidateAttribute;
61 StringTokenizer st = new StringTokenizer(mCandidateAttribute);
62 mfoundation = st.nextToken();
63 mComponentId = st.nextToken();
64 mTransport = st.nextToken();
65 mPriority = st.nextToken();
66 mConnectionAddress = st.nextToken();
67 mPort = st.nextToken();
68 st.nextToken(); //skip typ
69 mType = st.nextToken();;
71 public CandidateAttributeParser(InetSocketAddress aRelayAddress){
76 mConnectionAddress = aRelayAddress.getAddress().getHostAddress();
77 mPort = String.valueOf(aRelayAddress.getPort());
78 mType = CANDIDATE_RELAY_NAME;
79 mCandidateAttribute = toString();
82 InetSocketAddress getAddress() {
83 return new InetSocketAddress(mConnectionAddress,Integer.parseInt(mPort));
85 public String toString() {
86 return mfoundation +" "+ mComponentId +" "+ mTransport +" "+ mPriority +" "+ mConnectionAddress +" "+ mPort +" typ " +mType;
90 private final static Logger mLog = Logger.getLogger(IceSdpProcessorImpl.class);
91 private final Map<String,Registration> mRegistrationTab;
92 private final P2pProxyRtpRelayManagement mP2pProxyRtpRelayManagement;
93 public IceSdpProcessorImpl(Map<String,Registration> aRegistrationTab,P2pProxyRtpRelayManagement aP2pProxyRtpRelayManagement) {
94 mRegistrationTab = aRegistrationTab;
95 mP2pProxyRtpRelayManagement = aP2pProxyRtpRelayManagement;
98 public void processSdpAfterSentToPipe(Message message, OutputPipe outputPipe)
99 throws P2pProxyException {
104 public void processSdpBeforeSendingToSipUA(Message aMessage) throws P2pProxyException {
106 if (aMessage.isInvite()) {
107 lUserName = aMessage.getToHeader().getNameAddress().getAddress().toString();
108 } else if (aMessage.isResponse()) {
109 lUserName = aMessage.getFromHeader().getNameAddress().getAddress().toString();
110 } else if (aMessage.isAck()) {
111 lUserName = aMessage.getToHeader().getNameAddress().getAddress().toString();
113 mLog.warn("strange, sdp in message ["+aMessage+"]");
115 processSdp(aMessage,lUserName);
118 public void processSdpBeforeSendingToPipe(Message aMessage) throws P2pProxyException {
120 if (aMessage.isInvite()) {
121 lUserName = aMessage.getFromHeader().getNameAddress().getAddress().toString();
122 } else if (aMessage.isResponse()) {
123 lUserName = aMessage.getToHeader().getNameAddress().getAddress().toString();
124 } else if (aMessage.isAck()) {
125 lUserName = aMessage.getFromHeader().getNameAddress().getAddress().toString();
127 mLog.warn("strange, sdp in message ["+aMessage+"]");
129 processSdp(aMessage,lUserName);
132 //check if already have relay candidate
133 //1 search for relay if not available
134 //2 rewrite c line /port
136 //4 if relay was available, clean relay
137 private void processSdp(Message aMessage, String aUserName) throws P2pProxyException {
138 //check if sdp present
139 if (aMessage.hasBody() && "application/sdp".equals(aMessage.getBodyType())) {
140 SessionDescriptor lOrigSessionDescriptor = new SessionDescriptor(aMessage.getBody());
142 SessionDescriptor lNewSessionDescriptor = new SessionDescriptor(aMessage.getBody());
143 lNewSessionDescriptor.removeMediaDescriptors();
144 lNewSessionDescriptor.setConnection(null);
147 Registration lRegistration = mRegistrationTab.get(aUserName);
148 if (lRegistration == null) {
149 throw new P2pProxyException("unknown user ["+aUserName+"]");
151 boolean lrelayCandidateDetected = false;
152 //check if already have relay candidate
153 for (Object lMediaDescriptorObject :lOrigSessionDescriptor.getMediaDescriptors()) {
154 MediaDescriptor lMediaDescriptor = (MediaDescriptor)lMediaDescriptorObject;
155 MediaType lMediaType = MediaType.parseString(lMediaDescriptor.getMedia().getMedia());
156 String lRelayCandidateValue = getRelayCandidate(lMediaDescriptor);
158 if (lRelayCandidateValue != null) {
159 if (lRegistration.RtpRelays.containsKey(lMediaType) == false) {// get relay address from from candidate
160 CandidateAttributeParser lCandidateAttributeParser = new CandidateAttributeParser(lRelayCandidateValue);
161 lRegistration.RtpRelays.put(lMediaType, lCandidateAttributeParser.getAddress());
162 mLog.info("relay candidate detected, adding relay ["+lCandidateAttributeParser.getAddress()+" for ["+lMediaDescriptor.getMedia().getMedia()+"]");
164 lRegistration.RtpRelays.remove(lMediaType);
165 mLog.info("relay candidate removing address ");
167 lrelayCandidateDetected = true;
169 InetSocketAddress lInetSocketAddress=null;
170 if (lRegistration.RtpRelays.containsKey(lMediaType) == false) {
171 //put relay candidate from network
172 lRegistration.RtpRelays = mP2pProxyRtpRelayManagement.getAddresses();
173 lInetSocketAddress = lRegistration.RtpRelays.get(lMediaType);
175 lInetSocketAddress = lRegistration.RtpRelays.get(lMediaType);
176 lRegistration.RtpRelays.remove(lMediaType);
177 mLog.info("no relay candidate relay removing address ");
180 // build candidate attribute
181 CandidateAttributeParser lCandidateAttributeParser = new CandidateAttributeParser(lInetSocketAddress );
182 // create new media desc
183 ConnectionField lConnectionField = new ConnectionField("IP4",lInetSocketAddress.getAddress().getHostAddress());
184 MediaField lOrigMediaField = lMediaDescriptor.getMedia();
185 MediaField lNewMediaField = new MediaField(lOrigMediaField.getMedia()
186 , lInetSocketAddress.getPort() //new port
188 , lOrigMediaField.getTransport()
189 , lOrigMediaField.getFormatList());
190 MediaDescriptor lNewMediaDescriptor = new MediaDescriptor(lNewMediaField,lConnectionField);
191 for (Object lAttributeField:lMediaDescriptor.getAttributes()) {
192 lNewMediaDescriptor.addAttribute((AttributeField) lAttributeField);
194 // add relay candidate
195 AttributeField lAttributeField = new AttributeField("candidate", lCandidateAttributeParser.toString());
196 lNewMediaDescriptor.addAttribute(lAttributeField);
197 lNewSessionDescriptor.addMediaDescriptor(lNewMediaDescriptor);
201 if (lrelayCandidateDetected == false) {
202 //to work-around mjsip bug
203 lNewSessionDescriptor.setConnection(((MediaDescriptor)lNewSessionDescriptor.getMediaDescriptors().elementAt(0)).getConnection());
204 aMessage.setBody(lNewSessionDescriptor.toString());
205 mLog.debug("new sdp:" +aMessage.getBody());
211 private String getRelayCandidate(MediaDescriptor aMediaDescriptor) {
213 for (Object lField:aMediaDescriptor.getAttributes()) {
214 AttributeField lAttributeField = (AttributeField)lField;
215 if (lAttributeField.getAttributeName().equalsIgnoreCase("candidate") && lAttributeField.getAttributeValue().contains(CANDIDATE_RELAY_NAME)) {
216 return lAttributeField.getAttributeValue();