PageRenderTime 44ms CodeModel.GetById 10ms RepoModel.GetById 1ms app.codeStats 0ms

/src/plugins/ofmeet/src/java/org/ifsoft/sip/RtpRelay.java

https://gitlab.com/javajamesb08/Openfire
Java | 907 lines | 750 code | 116 blank | 41 comment | 117 complexity | e1bc8d563828d7ec17da58712063abae MD5 | raw file
Possible License(s): MIT, GPL-2.0
  1. /**
  2. * Copyright 2012 Voxbone SA/NV
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License");
  5. * you may not use this file except in compliance with the License.
  6. * You may obtain a copy of the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS,
  12. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. * See the License for the specific language governing permissions and
  14. * limitations under the License.
  15. */
  16. package org.ifsoft.sip;
  17. import java.io.IOException;
  18. import java.net.InetSocketAddress;
  19. import java.net.SocketAddress;
  20. import java.net.SocketException;
  21. import java.nio.ByteBuffer;
  22. import java.nio.channels.DatagramChannel;
  23. import java.nio.channels.SelectionKey;
  24. import java.nio.channels.Selector;
  25. import java.nio.channels.spi.SelectorProvider;
  26. import java.util.Arrays;
  27. import java.util.Hashtable;
  28. import java.util.Iterator;
  29. import java.util.Timer;
  30. import java.util.TimerTask;
  31. import java.util.concurrent.BlockingQueue;
  32. import java.util.concurrent.LinkedBlockingQueue;
  33. import java.util.Properties;
  34. import javax.sip.DialogState;
  35. import org.slf4j.*;
  36. import org.slf4j.Logger;
  37. import de.javawi.jstun.attribute.MappedAddress;
  38. import de.javawi.jstun.attribute.MessageAttribute;
  39. import de.javawi.jstun.attribute.MessageAttributeException;
  40. import de.javawi.jstun.attribute.MessageAttributeParsingException;
  41. import de.javawi.jstun.attribute.SourceAddress;
  42. import de.javawi.jstun.attribute.UnknownMessageAttributeException;
  43. import de.javawi.jstun.attribute.Username;
  44. import de.javawi.jstun.attribute.MessageAttributeInterface.MessageAttributeType;
  45. import de.javawi.jstun.header.MessageHeader;
  46. import de.javawi.jstun.header.MessageHeaderParsingException;
  47. import de.javawi.jstun.header.MessageHeaderInterface.MessageHeaderType;
  48. import de.javawi.jstun.util.Address;
  49. import de.javawi.jstun.util.UtilityException;
  50. /**
  51. * This is the RTP Media relay thread, can be for video or audio.
  52. * For the xmpp side it also takes care of the STUN signaling
  53. *
  54. */
  55. public class RtpRelay extends Thread
  56. {
  57. private static final Logger Log = LoggerFactory.getLogger(RtpRelay.class);
  58. private static int RTP_MIN_PORT;
  59. private static int RTP_MAX_PORT;
  60. private static int nextPort = RTP_MIN_PORT;
  61. private static boolean NAT_ENABLE = false;
  62. private static boolean FIR_ENABLE = false;
  63. private static boolean RTP_DEBUG = false;
  64. private static boolean VUP_ENABLE = false;
  65. private static int VUP_TIMER = 5000;
  66. Timer retransTimer = new Timer("Stun Retransmit Thread");
  67. private class StunTransmitter extends TimerTask
  68. {
  69. byte [] message;
  70. SocketAddress dest;
  71. DatagramChannel socket;
  72. String remoteUser;
  73. String localUser;
  74. public StunTransmitter(byte [] message, String remoteUser, String localUser, SocketAddress dest, DatagramChannel socket)
  75. {
  76. this.message = message;
  77. this.dest = dest;
  78. this.socket = socket;
  79. this.remoteUser = remoteUser;
  80. this.localUser = localUser;
  81. }
  82. public void run()
  83. {
  84. if (RTP_DEBUG) {
  85. Log.debug("[[" + cs.internalCallId + "]] Running RtpRelay::StunTransmitter ... : " + dest + " -- " + socket.socket().getLocalPort());
  86. }
  87. try
  88. {
  89. if (socket.isOpen())
  90. {
  91. socket.send(ByteBuffer.wrap(message), dest);
  92. }
  93. }
  94. catch (IOException e)
  95. {
  96. Log.error("[[" + cs.internalCallId + "]] RtpRelay::StunTransmitter sending failed ==> " + dest + " -- " + socket.socket().getLocalPort());
  97. }
  98. }
  99. public boolean cancel()
  100. {
  101. Log.debug("[[" + cs.internalCallId + "]] Cancelling RtpRelay::StunTransmitter ... : " + dest + " -- " + socket.socket().getLocalPort());
  102. return super.cancel();
  103. }
  104. }
  105. BlockingQueue<Character> dtmfQueue = new LinkedBlockingQueue<Character>();
  106. private boolean video = false;
  107. private class DtmfGenerator extends Thread
  108. {
  109. @Override
  110. public void run()
  111. {
  112. while (sipSocket.isOpen())
  113. {
  114. char dtmf;
  115. try
  116. {
  117. dtmf = dtmfQueue.take();
  118. if (dtmf == '\0')
  119. {
  120. Log.debug("[[" + cs.internalCallId + "]] End flag detected in dtmf thread");
  121. break;
  122. }
  123. long ts = 0;
  124. synchronized (sipSocket)
  125. {
  126. ts = jabberTimestamp;
  127. }
  128. DtmfEvent de = new DtmfEvent(dtmf, ts, jabberSSRC);
  129. Log.debug("[[" + cs.internalCallId + "]] Preparing to send dtmf " + dtmf);
  130. synchronized (sipSocket)
  131. {
  132. ByteBuffer buffer = ByteBuffer.wrap(de.startPacket());
  133. RtpUtil.setSequenceNumber(buffer.array(), ++jabberSequence);
  134. try
  135. {
  136. sipSocket.send(buffer, sipDest);
  137. }
  138. catch (IOException e)
  139. {
  140. Log.error("Error sending dtmf start packet!", e);
  141. }
  142. }
  143. for (int i = 0; i < 5; i++)
  144. {
  145. Thread.sleep(20);
  146. synchronized (sipSocket)
  147. {
  148. ByteBuffer buffer = ByteBuffer.wrap(de.continuationPacket());
  149. RtpUtil.setSequenceNumber(buffer.array(), ++jabberSequence);
  150. try
  151. {
  152. sipSocket.send(buffer, sipDest);
  153. }
  154. catch (IOException e)
  155. {
  156. Log.error("Error sending dtmf continuation packet!", e);
  157. }
  158. }
  159. }
  160. for (int i = 0; i < 3; i++)
  161. {
  162. synchronized (sipSocket)
  163. {
  164. ByteBuffer buffer = ByteBuffer.wrap(de.endPacket());
  165. RtpUtil.setSequenceNumber(buffer.array(), ++jabberSequence);
  166. try
  167. {
  168. sipSocket.send(buffer, sipDest);
  169. }
  170. catch (IOException e)
  171. {
  172. Log.error("Error sending dtmf end packet!", e);
  173. }
  174. }
  175. }
  176. // Ensure at least 40 ms between dtmfs
  177. Thread.sleep(40);
  178. }
  179. catch (InterruptedException e)
  180. {
  181. // do nothing
  182. }
  183. }
  184. Log.debug("[[" + cs.internalCallId + "]] DtmfGenerator shut down");
  185. }
  186. }
  187. public Hashtable<String, StunTransmitter> transmitters = new Hashtable<String, StunTransmitter>();
  188. private class ID
  189. {
  190. byte [] id;
  191. public ID(byte [] id)
  192. {
  193. this.id = id;
  194. }
  195. @Override
  196. public int hashCode()
  197. {
  198. final int prime = 31;
  199. int result = 1;
  200. result = prime * result + Arrays.hashCode(id);
  201. return result;
  202. }
  203. @Override
  204. public boolean equals(Object obj)
  205. {
  206. if (this == obj)
  207. {
  208. return true;
  209. }
  210. if (obj == null)
  211. {
  212. return false;
  213. }
  214. if (getClass() != obj.getClass())
  215. {
  216. return false;
  217. }
  218. final ID other = (ID) obj;
  219. if (!Arrays.equals(id, other.id))
  220. {
  221. return false;
  222. }
  223. return true;
  224. }
  225. }
  226. private DatagramChannel jabberSocket;
  227. private DatagramChannel sipSocket;
  228. private DatagramChannel jabberSocketRtcp;
  229. private DatagramChannel sipSocketRtcp;
  230. private SocketAddress jabberDest;
  231. private SocketAddress jabberDestRtcp;
  232. private SocketAddress sipDest;
  233. private SocketAddress sipDestRtcp;
  234. byte [] sipSSRC = null;
  235. byte [] jabberSSRC = null;
  236. long jabberTimestamp = 0;
  237. short jabberSequence = 0;
  238. long lastVUpate = 0;
  239. int firSeq = 0;
  240. private CallSession cs = null;
  241. private DatagramChannel makeDatagramChannel(boolean any) throws IOException
  242. {
  243. DatagramChannel socket = DatagramChannel.open();
  244. while (!socket.socket().isBound())
  245. {
  246. nextPort += 1;
  247. if (nextPort > RTP_MAX_PORT)
  248. {
  249. nextPort = RTP_MIN_PORT;
  250. }
  251. Log.debug("[[" + cs.internalCallId + "]] trying to bind to port: " + nextPort);
  252. try
  253. {
  254. if (!any)
  255. {
  256. socket.socket().bind(new InetSocketAddress(SipService.getLocalIP(), nextPort));
  257. }
  258. else
  259. {
  260. socket.socket().bind(new InetSocketAddress(nextPort));
  261. }
  262. }
  263. catch (SocketException e)
  264. {
  265. Log.error("Unable to make RTP socket!", e);
  266. }
  267. }
  268. return socket;
  269. }
  270. public void sendBind(String user, String me, String destIp, int destPort, boolean rtcp)
  271. {
  272. MessageHeader sendMH = new MessageHeader(MessageHeaderType.BindingRequest);
  273. Username name = new Username(user + me);
  274. try
  275. {
  276. sendMH.generateTransactionID();
  277. }
  278. catch (UtilityException e)
  279. {
  280. Log.error("Unable to make stun transaction id", e);
  281. }
  282. if(name.getUsername().length() > 0)
  283. {
  284. sendMH.addMessageAttribute(name);
  285. }
  286. try
  287. {
  288. byte [] data = sendMH.getBytes();
  289. Log.debug("[[" + cs.internalCallId + "]] Sending: " + Arrays.toString(data));
  290. DatagramChannel socket = null;
  291. if (rtcp)
  292. {
  293. socket = jabberSocketRtcp;
  294. }
  295. else
  296. {
  297. socket = jabberSocket;
  298. }
  299. synchronized (transmitters)
  300. {
  301. if (jabberDest == null)
  302. {
  303. Log.debug("[[" + cs.internalCallId + "]] Sending Bind to: " + destIp + ":" + destPort);
  304. StunTransmitter st = new StunTransmitter(data, user, me, new InetSocketAddress(destIp, destPort), socket);
  305. String key = name.getUsername() + "_" + destIp + ":" + destPort;
  306. if (transmitters.containsKey(key))
  307. {
  308. transmitters.get(key).cancel();
  309. transmitters.remove(key);
  310. }
  311. transmitters.put(key, st);
  312. Log.debug("[[" + cs.internalCallId + "]] RtpRelay::StunTransmitter scheduled (fast) [" + jabberSocket.socket().getLocalPort() + "][" + sipSocket.socket().getLocalPort() + "] ==> " + st.socket.socket().getLocalPort());
  313. retransTimer.schedule(st, 50, 50);
  314. }
  315. }
  316. }
  317. catch (UtilityException e)
  318. {
  319. Log.error("Error in stun bind!", e);
  320. }
  321. }
  322. public RtpRelay(CallSession cs, boolean video) throws IOException
  323. {
  324. this.video = video;
  325. this.cs = cs;
  326. jabberSocket = makeDatagramChannel(false);
  327. jabberSocketRtcp = makeDatagramChannel(false);
  328. sipSocket = makeDatagramChannel(false);
  329. sipSocketRtcp = makeDatagramChannel(false);
  330. Log.info("[[" + cs.internalCallId + "]] RtpRelay created [" + jabberSocket.socket().getLocalPort() + "][" + sipSocket.socket().getLocalPort() + "]");
  331. if (!video)
  332. {
  333. (new DtmfGenerator()).start();
  334. }
  335. start();
  336. }
  337. protected void finalize() throws Throwable
  338. {
  339. Log.info("[[" + cs.internalCallId + "]] RtpRelay destroyed [" + jabberSocket.socket().getLocalPort() + "][" + sipSocket.socket().getLocalPort() + "]");
  340. super.finalize(); // not necessary if extending Object.
  341. }
  342. private void processStun(SocketAddress src, byte [] origData, DatagramChannel socket)
  343. {
  344. try
  345. {
  346. MessageHeader receiveMH = MessageHeader.parseHeader(origData);
  347. if (receiveMH.getType() == MessageHeaderType.BindingErrorResponse)
  348. {
  349. return;
  350. }
  351. receiveMH.parseAttributes(origData);
  352. if (receiveMH.getType() == MessageHeaderType.BindingRequest)
  353. {
  354. MessageHeader sendMH = new MessageHeader(MessageHeaderType.BindingResponse);
  355. sendMH.setTransactionID(receiveMH.getTransactionID());
  356. // Mapped address attribute
  357. MappedAddress ma = new MappedAddress();
  358. ma.setAddress(new Address(((InetSocketAddress) src).getAddress().getAddress()));
  359. ma.setPort(((InetSocketAddress) src).getPort());
  360. sendMH.addMessageAttribute(ma);
  361. SourceAddress sa = new SourceAddress();
  362. sa.setAddress(new Address(SipService.getLocalIP()));
  363. sa.setPort(socket.socket().getLocalPort());
  364. sendMH.addMessageAttribute(sa);
  365. MessageAttribute usernameMA = receiveMH.getMessageAttribute(MessageAttributeType.Username);
  366. if (usernameMA != null) {
  367. sendMH.addMessageAttribute(usernameMA);
  368. }
  369. byte [] data = sendMH.getBytes();
  370. socket.send(ByteBuffer.wrap(data), src);
  371. synchronized (transmitters)
  372. {
  373. boolean reflexive = true;
  374. String me = null;
  375. Username user = (Username) receiveMH.getMessageAttribute(MessageAttributeType.Username);
  376. for (String key : transmitters.keySet())
  377. {
  378. if(user == null) break;
  379. StunTransmitter st = transmitters.get(key);
  380. if(user.getUsername().startsWith(st.localUser))
  381. {
  382. me = st.localUser;
  383. if (RTP_DEBUG) {
  384. Log.debug("Local User found " + me);
  385. }
  386. }
  387. if(src.equals(st.dest))
  388. {
  389. reflexive = false;
  390. break;
  391. }
  392. }
  393. if(reflexive && me != null)
  394. {
  395. Log.info("Reflexive detected " + user.getUsername());
  396. String remote = user.getUsername().substring(me.length());
  397. Log.info("Remote = " + remote + " me = " + me);
  398. sendBind(remote, me, ((InetSocketAddress) src).getAddress().getHostAddress(), ((InetSocketAddress) src).getPort(), socket == jabberSocket ? false : true);
  399. }
  400. }
  401. }
  402. else if (receiveMH.getType() == MessageHeaderType.BindingResponse)
  403. {
  404. synchronized (transmitters)
  405. {
  406. if ( (this.jabberDest == null && socket == jabberSocket)
  407. || (this.jabberDestRtcp == null && socket == jabberSocketRtcp))
  408. {
  409. if (socket == jabberSocket)
  410. {
  411. this.jabberDest = src;
  412. }
  413. else
  414. {
  415. this.jabberDestRtcp = src;
  416. }
  417. Username user = (Username) receiveMH.getMessageAttribute(MessageAttributeType.Username);
  418. StunTransmitter newTimer = null;
  419. String newKey = null;
  420. String desired = user.getUsername() + "_" + ((InetSocketAddress)src).getAddress().getHostAddress() + ":" + ((InetSocketAddress)src).getPort();
  421. for (String key : transmitters.keySet())
  422. {
  423. StunTransmitter st = transmitters.get(key);
  424. if (st.socket == socket)
  425. {
  426. try
  427. {
  428. st.cancel();
  429. }
  430. catch (Exception e)
  431. {
  432. }
  433. Log.debug("[[" + cs.internalCallId + "]] Comparing " + key + " to " + desired);
  434. if (key.equals(desired))
  435. {
  436. newKey = key;
  437. newTimer = new StunTransmitter(st.message, st.remoteUser, st.localUser, st.dest, st.socket);
  438. }
  439. }
  440. }
  441. if (newTimer != null && newKey != null)
  442. {
  443. Log.debug("[[" + cs.internalCallId + "]] ++++++++++++++++ slowing retransmission " + newKey + " ++++++++++++++");
  444. transmitters.put(newKey, newTimer);
  445. Log.debug("[[" + cs.internalCallId + "]] RtpRelay::StunTransmitter scheduled (slow) [" + jabberSocket.socket().getLocalPort() + "][" + sipSocket.socket().getLocalPort() + "] ==> " + newTimer.socket.socket().getLocalPort());
  446. retransTimer.schedule(newTimer, 100, 5000);
  447. }
  448. }
  449. }
  450. }
  451. }
  452. catch (MessageHeaderParsingException e)
  453. {
  454. // ignore (problem occurred in stun code)
  455. }
  456. catch (UnknownMessageAttributeException e)
  457. {
  458. // ignore (problem occurred in stun code)
  459. }
  460. catch (MessageAttributeParsingException e)
  461. {
  462. // ignore (problem occurred in stun code)
  463. }
  464. catch (UtilityException e)
  465. {
  466. Log.error("Error in processStun", e);
  467. }
  468. catch (MessageAttributeException e)
  469. {
  470. Log.error("Error in processStun", e);
  471. }
  472. catch (IOException e)
  473. {
  474. Log.error("Error in processStun", e);
  475. }
  476. catch (ArrayIndexOutOfBoundsException e)
  477. {
  478. // ignore (problem occurred in stun code)
  479. }
  480. catch (Exception e)
  481. {
  482. Log.error("Error in processStun", e);
  483. }
  484. }
  485. /*
  486. * Experimental. I believe that google uses special rtcp packets to send fast video updates - this is an unsuccessful
  487. * attempt at implementing this feature.
  488. */
  489. public void sendFIR()
  490. {
  491. if (FIR_ENABLE) {
  492. byte [] buffer = new byte[40];
  493. RtpUtil.buildFIR(buffer, firSeq++, sipSSRC, jabberSSRC);
  494. try
  495. {
  496. jabberSocketRtcp.send(ByteBuffer.wrap(buffer), jabberDestRtcp);
  497. }
  498. catch (Exception e)
  499. {
  500. Log.error("Error sending FIR packet!", e);
  501. }
  502. }
  503. }
  504. public void sendSipDTMF(char dtmf)
  505. {
  506. switch (dtmf)
  507. {
  508. case '0' :
  509. case '1' :
  510. case '2' :
  511. case '3' :
  512. case '4' :
  513. case '5' :
  514. case '6' :
  515. case '7' :
  516. case '8' :
  517. case '9' :
  518. case '*' :
  519. case '#' :
  520. case 'A' :
  521. case 'B' :
  522. case 'C' :
  523. case 'D' :
  524. Log.debug("[[" + cs.internalCallId + "]] Logging dtmf " + dtmf + " for generation");
  525. try
  526. {
  527. dtmfQueue.put(dtmf);
  528. }
  529. catch (InterruptedException e)
  530. {
  531. Log.error("Interrupted why queueing a dtmf", e);
  532. }
  533. break;
  534. default :
  535. Log.warn("[[" + cs.internalCallId + "]] Ignoring invalid dtmf " + dtmf);
  536. }
  537. }
  538. public void run()
  539. {
  540. Log.info("[[" + cs.internalCallId + "]] RtpRelay Thread Started");
  541. Selector sel = null;
  542. try
  543. {
  544. sel = SelectorProvider.provider().openSelector();
  545. sipSocket.configureBlocking(false);
  546. sipSocketRtcp.configureBlocking(false);
  547. jabberSocket.configureBlocking(false);
  548. jabberSocketRtcp.configureBlocking(false);
  549. sipSocket.register(sel, SelectionKey.OP_READ);
  550. jabberSocket.register(sel, SelectionKey.OP_READ);
  551. sipSocketRtcp.register(sel, SelectionKey.OP_READ);
  552. jabberSocketRtcp.register(sel, SelectionKey.OP_READ);
  553. ByteBuffer inputBuffer = ByteBuffer.allocate(20000);
  554. ByteBuffer outputBuffer = ByteBuffer.allocate(20000);
  555. byte [] outputBytes = new byte[20000];
  556. while (sipSocket.isOpen())
  557. {
  558. if (sel.select(1000) >= 0)
  559. {
  560. Iterator<SelectionKey> itr = sel.selectedKeys().iterator();
  561. while (itr.hasNext())
  562. {
  563. SelectionKey key = itr.next();
  564. itr.remove();
  565. if (key.isValid() && key.isReadable())
  566. {
  567. DatagramChannel socket = (DatagramChannel) key.channel();
  568. inputBuffer.clear();
  569. if (!socket.isOpen())
  570. {
  571. Log.error("[[" + cs.internalCallId + "]] Socket is not open ... ignoring");
  572. continue;
  573. }
  574. SocketAddress src = socket.receive(inputBuffer);
  575. if (src == null)
  576. {
  577. Log.error("[[" + cs.internalCallId + "]] Src is null ... ignoring");
  578. continue;
  579. }
  580. if ((inputBuffer.get(0) & 0x80) != 0)
  581. {
  582. DatagramChannel destSocket;
  583. SocketAddress destAddr;
  584. inputBuffer.flip();
  585. if (socket == sipSocket)
  586. {
  587. if(NAT_ENABLE && !src.equals(sipDest))
  588. {
  589. Log.debug("Nat detected, updating sip rtp destination from " + sipDest + " to " + src);
  590. sipDest = src;
  591. }
  592. destSocket = jabberSocket;
  593. destAddr = jabberDest;
  594. if (this.sipSSRC == null)
  595. {
  596. this.sipSSRC = RtpUtil.getSSRC(inputBuffer.array());
  597. }
  598. if (destSocket != null && destAddr != null)
  599. {
  600. destSocket.send(inputBuffer, destAddr);
  601. }
  602. }
  603. else if (socket == sipSocketRtcp)
  604. {
  605. destSocket = jabberSocketRtcp;
  606. destAddr = jabberDestRtcp;
  607. if(NAT_ENABLE && !src.equals(sipDestRtcp))
  608. {
  609. Log.debug("Nat detected, updating sip rtcp destination from " + sipDestRtcp + " to " + src);
  610. sipDestRtcp = src;
  611. }
  612. if (destSocket != null && destAddr != null)
  613. {
  614. destSocket.send(inputBuffer, destAddr);
  615. }
  616. }
  617. else if (socket == jabberSocketRtcp)
  618. {
  619. destSocket = sipSocketRtcp;
  620. destAddr = sipDestRtcp;
  621. if (destSocket != null && destAddr != null)
  622. {
  623. destSocket.send(inputBuffer, destAddr);
  624. }
  625. if (video && VUP_ENABLE && System.currentTimeMillis() - lastVUpate > VUP_TIMER
  626. && (this.cs.sipDialog.getState() != null && this.cs.sipDialog.getState() != DialogState.EARLY) )
  627. {
  628. SipService.sendVideoUpdate(this.cs);
  629. lastVUpate = System.currentTimeMillis();
  630. }
  631. }
  632. else
  633. {
  634. destSocket = sipSocket;
  635. destAddr = sipDest;
  636. if (this.jabberSSRC == null)
  637. {
  638. this.jabberSSRC = RtpUtil.getSSRC(inputBuffer.array());
  639. }
  640. synchronized (destSocket)
  641. {
  642. if (destSocket != null && destAddr != null)
  643. {
  644. if (!video)
  645. {
  646. this.jabberTimestamp = RtpUtil.getTimeStamp(inputBuffer.array());
  647. RtpUtil.setSequenceNumber(inputBuffer.array(), ++this.jabberSequence);
  648. if (destSocket.isOpen())
  649. {
  650. destSocket.send(inputBuffer, destAddr);
  651. }
  652. }
  653. else
  654. {
  655. // TODO: google uses H264 SVC, the rest of the world uses AVC, so convert
  656. // google now supports AVC so we should adapt to that
  657. /*
  658. int length = RtpUtil.filterSVC(inputBuffer.array(), outputBytes, inputBuffer.remaining());
  659. outputBuffer.clear();
  660. outputBuffer.put(outputBytes, 0, length);
  661. outputBuffer.flip();
  662. */
  663. if (destSocket.isOpen())
  664. {
  665. destSocket.send(inputBuffer, destAddr);
  666. }
  667. }
  668. }
  669. }
  670. }
  671. }
  672. else
  673. {
  674. this.processStun(src, inputBuffer.array(), socket);
  675. }
  676. }
  677. }
  678. }
  679. }
  680. }
  681. catch (IOException e)
  682. {
  683. Log.error("Error in RTP relay thread!", e);
  684. }
  685. catch (Exception e)
  686. {
  687. Log.error("Error in RTP relay thread!", e);
  688. }
  689. finally
  690. {
  691. if (sel != null)
  692. {
  693. try
  694. {
  695. sel.close();
  696. }
  697. catch (IOException e)
  698. {
  699. // ignore (we're dead anyhow)
  700. }
  701. }
  702. }
  703. Log.info("[[" + cs.internalCallId + "]] RtpRelay Thread Stopped");
  704. }
  705. public void setSipDest(String host, int port)
  706. {
  707. this.sipDest = new InetSocketAddress(host, port);
  708. this.sipDestRtcp = new InetSocketAddress(host, port + 1);
  709. }
  710. public int getSipPort()
  711. {
  712. return this.sipSocket.socket().getLocalPort();
  713. }
  714. public int getSipRtcpPort()
  715. {
  716. return this.sipSocketRtcp.socket().getLocalPort();
  717. }
  718. public int getJabberPort()
  719. {
  720. return this.jabberSocket.socket().getLocalPort();
  721. }
  722. public int getJabberRtcpPort()
  723. {
  724. return this.jabberSocketRtcp.socket().getLocalPort();
  725. }
  726. public void shutdown()
  727. {
  728. Log.debug("[[" + cs.internalCallId + "]] Shutdown of rtp thread requested");
  729. synchronized (transmitters)
  730. {
  731. Log.debug("[[" + cs.internalCallId + "]] number of transmitters : " + transmitters.size());
  732. for (String key : transmitters.keySet())
  733. {
  734. Log.debug("[[" + cs.internalCallId + "]] cancelling transmitter : " + key);
  735. transmitters.get(key).cancel();
  736. }
  737. }
  738. try
  739. {
  740. dtmfQueue.put('\0');
  741. }
  742. catch (InterruptedException e)
  743. {
  744. Log.error("unable to queue shutdown signal!", e);
  745. }
  746. try
  747. {
  748. sipSocket.close();
  749. }
  750. catch (IOException e)
  751. {
  752. Log.error("unable to close sip-side rtp socket!", e);
  753. }
  754. try
  755. {
  756. jabberSocket.close();
  757. }
  758. catch (IOException e)
  759. {
  760. Log.error("unable to close xmpp-side rtp socket!", e);
  761. }
  762. try
  763. {
  764. sipSocketRtcp.close();
  765. }
  766. catch (IOException e)
  767. {
  768. Log.error("Error in rtcp shutdown", e);
  769. }
  770. try
  771. {
  772. jabberSocketRtcp.close();
  773. }
  774. catch (IOException e)
  775. {
  776. Log.error("Error in rtcp shutdown", e);
  777. }
  778. }
  779. public static void configure(Properties properties)
  780. {
  781. RTP_MIN_PORT = Integer.parseInt(properties.getProperty("com.voxbone.kelpie.rtp.min_port", "8000"));
  782. RTP_MAX_PORT = Integer.parseInt(properties.getProperty("com.voxbone.kelpie.rtp.max_port", "10000"));
  783. NAT_ENABLE = Boolean.parseBoolean(properties.getProperty("com.voxbone.kelpie.rtp.nat_enable", "false"));
  784. FIR_ENABLE = Boolean.parseBoolean(properties.getProperty("com.voxbone.kelpie.rtp.fir_enable", "false"));
  785. RTP_DEBUG = Boolean.parseBoolean(properties.getProperty("com.voxbone.kelpie.rtp.debug", "false"));
  786. VUP_ENABLE = Boolean.parseBoolean(properties.getProperty("com.voxbone.kelpie.rtp.vup_enable", "true"));
  787. VUP_TIMER = Integer.parseInt(properties.getProperty("com.voxbone.kelpie.rtp.vup_timer", "5000"));
  788. nextPort = RTP_MIN_PORT;
  789. }
  790. }