]> sjero.net Git - linphone/blob - p2pproxy/src/org/linphone/p2pproxy/core/media/rtprelay/IceSdpProcessorImpl.java
remove mediastreamer2 and add it as a submodule instead.
[linphone] / p2pproxy / src / org / linphone / p2pproxy / core / media / rtprelay / IceSdpProcessorImpl.java
1 /*
2 p2pproxy Copyright (C) 2007  Jehan Monnier ()
3
4 SdpProcessorImpl.java - .
5
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.
10
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.
15
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.
19 */
20 package org.linphone.p2pproxy.core.media.rtprelay;
21
22 import java.net.InetSocketAddress;
23 import java.util.Map;
24 import java.util.StringTokenizer;
25
26 import net.jxta.pipe.OutputPipe;
27
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;
39
40 /**
41  * rewrite SDP to insert an ICE aware rtp relay 
42  *
43  * 
44  */
45 public class IceSdpProcessorImpl implements SdpProcessor {
46    private final String CANDIDATE_RELAY_NAME="relay";
47
48    class CandidateAttributeParser {
49       final private  String mCandidateAttribute;
50
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;    
58
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();;
70       }
71       public CandidateAttributeParser(InetSocketAddress aRelayAddress){
72          mfoundation = "3";
73          mComponentId = "1";
74          mTransport = "UDP";
75          mPriority = "0"; 
76          mConnectionAddress =  aRelayAddress.getAddress().getHostAddress();
77          mPort =  String.valueOf(aRelayAddress.getPort());    
78          mType = CANDIDATE_RELAY_NAME; 
79          mCandidateAttribute = toString();
80       }
81
82       InetSocketAddress getAddress() {
83          return new InetSocketAddress(mConnectionAddress,Integer.parseInt(mPort));
84       }
85       public String toString() {
86          return mfoundation +" "+ mComponentId +" "+ mTransport +" "+ mPriority +" "+ mConnectionAddress +" "+ mPort +" typ " +mType;
87       }
88    }
89
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;
96
97    }
98    public void processSdpAfterSentToPipe(Message message, OutputPipe outputPipe)
99    throws P2pProxyException {
100       //nop
101
102    }
103
104    public void processSdpBeforeSendingToSipUA(Message aMessage) throws P2pProxyException {
105       String lUserName="";
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();
112       } else {
113          mLog.warn("strange, sdp in message ["+aMessage+"]");
114       }
115       processSdp(aMessage,lUserName);
116    }
117
118    public void processSdpBeforeSendingToPipe(Message aMessage) throws P2pProxyException {
119       String lUserName="";
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();
126       } else {
127          mLog.warn("strange, sdp in message ["+aMessage+"]");
128       }
129       processSdp(aMessage,lUserName);
130    }
131
132    //check if already have relay candidate
133    //1 search for relay if not available
134    //2 rewrite c line /port
135    //3 add candidate
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());
141
142          SessionDescriptor lNewSessionDescriptor = new SessionDescriptor(aMessage.getBody());
143          lNewSessionDescriptor.removeMediaDescriptors();
144          lNewSessionDescriptor.setConnection(null);
145
146          // get Registration 
147          Registration lRegistration = mRegistrationTab.get(aUserName);
148          if (lRegistration == null) {
149             throw new P2pProxyException("unknown user ["+aUserName+"]");
150          }
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); 
157
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()+"]");
163                } else {
164                   lRegistration.RtpRelays.remove(lMediaType);
165                   mLog.info("relay candidate  removing address ");
166                }
167                lrelayCandidateDetected = true;
168             } else {
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);
174                } else {
175                   lInetSocketAddress = lRegistration.RtpRelays.get(lMediaType);
176                   lRegistration.RtpRelays.remove(lMediaType);
177                   mLog.info("no relay candidate relay removing address ");
178                }
179
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
187                      , 0
188                      , lOrigMediaField.getTransport()
189                      , lOrigMediaField.getFormatList());
190                MediaDescriptor lNewMediaDescriptor = new MediaDescriptor(lNewMediaField,lConnectionField);
191                for (Object lAttributeField:lMediaDescriptor.getAttributes()) {
192                   lNewMediaDescriptor.addAttribute((AttributeField) lAttributeField);
193                }
194                // add relay candidate
195                AttributeField lAttributeField = new AttributeField("candidate", lCandidateAttributeParser.toString());
196                lNewMediaDescriptor.addAttribute(lAttributeField);
197                lNewSessionDescriptor.addMediaDescriptor(lNewMediaDescriptor);
198             } 
199
200          }
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());
206          }
207
208       }
209    }
210
211    private String getRelayCandidate(MediaDescriptor aMediaDescriptor) {
212       //1 get candidate
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();
217          }
218       }
219       return null;
220    }
221
222 }