PageRenderTime 59ms CodeModel.GetById 24ms RepoModel.GetById 1ms app.codeStats 0ms

/servers/media/test-suite/core/src/main/java/org/mobicents/media/server/testsuite/general/AbstractTestCase.java

http://mobicents.googlecode.com/
Java | 845 lines | 589 code | 176 blank | 80 comment | 104 complexity | 1d2fb21af5fe6ca717655d4035a41a2c MD5 | raw file
Possible License(s): LGPL-3.0, GPL-3.0, LGPL-2.1, GPL-2.0, CC-BY-SA-3.0, CC0-1.0, Apache-2.0, BSD-3-Clause
  1. /*
  2. * To change this template, choose Tools | Templates
  3. * and open the template in the editor.
  4. */
  5. package org.mobicents.media.server.testsuite.general;
  6. import jain.protocol.ip.mgcp.CreateProviderException;
  7. import jain.protocol.ip.mgcp.JainMgcpCommandEvent;
  8. import jain.protocol.ip.mgcp.JainMgcpEvent;
  9. import jain.protocol.ip.mgcp.JainMgcpResponseEvent;
  10. import jain.protocol.ip.mgcp.message.Notify;
  11. import java.io.File;
  12. import java.io.FileInputStream;
  13. import java.io.FileNotFoundException;
  14. import java.io.FileOutputStream;
  15. import java.io.IOException;
  16. import java.io.InputStreamReader;
  17. import java.io.ObjectInputStream;
  18. import java.io.ObjectOutputStream;
  19. import java.io.OutputStreamWriter;
  20. import java.io.Serializable;
  21. import java.net.InetAddress;
  22. import java.net.SocketException;
  23. import java.net.UnknownHostException;
  24. import java.util.Comparator;
  25. import java.util.HashMap;
  26. import java.util.Iterator;
  27. import java.util.List;
  28. import java.util.Map;
  29. import java.util.TooManyListenersException;
  30. import java.util.TreeSet;
  31. import java.util.Vector;
  32. import java.util.concurrent.Executors;
  33. import java.util.concurrent.ScheduledExecutorService;
  34. import java.util.concurrent.ScheduledFuture;
  35. import java.util.concurrent.TimeUnit;
  36. import java.util.logging.Level;
  37. import java.util.logging.Logger;
  38. import javax.sdp.Attribute;
  39. import javax.sdp.SdpFactory;
  40. import org.mobicents.media.server.testsuite.general.file.FileUtils;
  41. import org.mobicents.media.server.testsuite.general.rtp.RtpPacket;
  42. import org.mobicents.media.server.testsuite.general.rtp.RtpSocketFactory;
  43. import org.mobicents.media.server.testsuite.general.rtp.RtpSocketFactoryImpl;
  44. import org.mobicents.media.server.testsuite.gui.ext.CallStateTableModel;
  45. import org.mobicents.mgcp.stack.JainMgcpExtendedListener;
  46. import org.mobicents.mgcp.stack.JainMgcpStackImpl;
  47. import org.mobicents.mgcp.stack.JainMgcpStackProviderImpl;
  48. /**
  49. *
  50. * @author baranowb
  51. */
  52. public abstract class AbstractTestCase implements JainMgcpExtendedListener,
  53. Runnable, Serializable {
  54. protected transient Logger logger = Logger.getLogger(this.getClass()
  55. .getName());
  56. private TestState testState = TestState.Stoped;
  57. public transient final static String _CASE_FILE = "testcase.bin";
  58. public transient final static String _COLLECTIVE_RTP_FILE = "rtp.txt";
  59. public static final String _LINE_SEPARATOR;
  60. static {
  61. String lineSeparator = System.getProperty("line.separator");
  62. _LINE_SEPARATOR = lineSeparator;
  63. }
  64. // Dump section
  65. private transient File _RTP_TXT_DUMP_FILE;
  66. private transient FileOutputStream _RTP_TXT_DUMP_FOS;
  67. private transient OutputStreamWriter _RTP_TXT_DUMP_OSW;
  68. // private transient FileInputStream _RTP_TXT_DUMP_FIS;
  69. // private transient InputStreamReader _RTP_TXT_DUMP_ISR;
  70. public static final int _TURN_OFF_BOUNDRY = -1;
  71. // Yes, it would be good thing to ser
  72. protected transient SdpFactory sdpFactory;
  73. protected transient CallDisplayInterface callDisplay;
  74. protected Map<Long, AbstractCall> callSequenceToCall;
  75. // We mix view, but this is easier to achieve perf with that.
  76. protected transient CallStateTableModel model;
  77. // protected part - some variables that we might use.
  78. protected InetAddress clientTestNodeAddress;
  79. protected InetAddress serverJbossBindAddress;
  80. // timestamp :), its used for files
  81. protected long testTimesTamp = System.currentTimeMillis();
  82. protected transient File testDumpDirectory;
  83. protected transient ScheduledFuture callCreatorTask;
  84. protected transient ScheduledFuture gracefulStopTask;
  85. // Timer guard:
  86. protected transient final ScheduledExecutorService timeGuard;
  87. //
  88. protected transient final ScheduledExecutorService executors;
  89. // Some getters
  90. // Some stats
  91. protected long ongoingCallNumber;
  92. protected long errorCallNumber;
  93. protected long completedCallNumber;
  94. protected long totalCalls;
  95. protected long maxErrorCallNumber;
  96. protected transient RtpSocketFactory socketFactory;
  97. // FIXME: this will go into MGCP test case, will be removed from here
  98. // some mgcp magic
  99. protected transient JainMgcpStackImpl stack;
  100. protected transient JainMgcpStackProviderImpl provider;
  101. // We need this to map TXID to Call :)
  102. protected transient Map<Integer, AbstractCall> mgcpTransactionToProxy = new HashMap<Integer, AbstractCall>();
  103. protected transient Map<String, AbstractCall> requestIdIdToProxy = new HashMap<String, AbstractCall>();
  104. public AbstractTestCase() {
  105. this.callSequenceToCall = new HashMap<Long, AbstractCall>();
  106. // model = new CallStateTableModel(this.callSequenceToCall);
  107. AbstractCall.resetSequence();
  108. NamedThreadFactory executorsThreadFactory = new NamedThreadFactory(
  109. "ExecutorsTestCaseFactory");
  110. NamedThreadFactory timeGuardThreadFactory = new NamedThreadFactory(
  111. "GuardThreadFactoryTestCaseFactory");
  112. executors = Executors.newScheduledThreadPool(2, executorsThreadFactory);
  113. timeGuard = Executors.newScheduledThreadPool(1, timeGuardThreadFactory);
  114. }
  115. private void init() throws SocketException, IOException {
  116. // init streams
  117. boolean finished = false;
  118. try {
  119. _RTP_TXT_DUMP_FOS = new FileOutputStream(_RTP_TXT_DUMP_FILE);
  120. _RTP_TXT_DUMP_OSW = new OutputStreamWriter(_RTP_TXT_DUMP_FOS);
  121. // _RTP_TXT_DUMP_FIS = new FileInputStream(_RTP_TXT_DUMP_FILE);
  122. // _RTP_TXT_DUMP_ISR = new InputStreamReader(_RTP_TXT_DUMP_FIS);
  123. finished = true;
  124. } catch (Exception e) {
  125. e.printStackTrace();
  126. } finally {
  127. if (!finished) {
  128. if (_RTP_TXT_DUMP_OSW != null) {
  129. _RTP_TXT_DUMP_OSW.close();
  130. _RTP_TXT_DUMP_OSW = null;
  131. _RTP_TXT_DUMP_FOS = null;
  132. }
  133. }
  134. }
  135. if (this.socketFactory == null) {
  136. this.socketFactory = new RtpSocketFactoryImpl();
  137. // this.socketFactory.setPortRange("5000-10000");
  138. }
  139. if (this.socketFactory != null) {
  140. this.socketFactory.setBindAddress(this.callDisplay
  141. .getLocalAddress());
  142. this.socketFactory.setFormatMap(this.callDisplay.getCodecs());
  143. this.socketFactory.start();
  144. }
  145. }
  146. public OutputStreamWriter getRtpOSW() {
  147. return _RTP_TXT_DUMP_OSW;
  148. }
  149. public InputStreamReader getRtpISR() {
  150. FileInputStream _RTP_TXT_DUMP_FIS;
  151. try {
  152. _RTP_TXT_DUMP_FIS = new FileInputStream(_RTP_TXT_DUMP_FILE);
  153. InputStreamReader _RTP_TXT_DUMP_ISR = new InputStreamReader(
  154. _RTP_TXT_DUMP_FIS);
  155. return _RTP_TXT_DUMP_ISR;
  156. } catch (FileNotFoundException e) {
  157. // TODO Auto-generated catch block
  158. e.printStackTrace();
  159. }
  160. return null;
  161. }
  162. public ScheduledExecutorService getExecutors() {
  163. return executors;
  164. }
  165. protected void incrementOngoignCall() {
  166. this.ongoingCallNumber++;
  167. this.totalCalls++;
  168. }
  169. protected void decrementOngoingCall() {
  170. this.ongoingCallNumber--;
  171. }
  172. protected void incrementErrorCall() {
  173. this.errorCallNumber++;
  174. }
  175. protected void incrementCompletedCall() {
  176. this.completedCallNumber++;
  177. }
  178. public long getTestTimeStamp() {
  179. return this.testTimesTamp;
  180. }
  181. public InetAddress getClientTestNodeAddress() {
  182. return this.clientTestNodeAddress;
  183. }
  184. public InetAddress getServerJbossBindAddress() {
  185. return this.serverJbossBindAddress;
  186. }
  187. public CallDisplayInterface getCallDisplayInterface() {
  188. return this.callDisplay;
  189. }
  190. public AbstractCall getCallBySequence(Long seq) {
  191. AbstractCall ac = this.callSequenceToCall.get(seq);
  192. if (ac != null)
  193. ac.setTestCase(this);
  194. return ac;
  195. }
  196. public void callStateChanged(AbstractCall c) {
  197. CallState callState = c.getState();
  198. if (callState == CallState.INITIAL) {
  199. this.incrementOngoignCall();
  200. } else if (callState == CallState.ENDED) {
  201. this.decrementOngoingCall();
  202. this.incrementCompletedCall();
  203. // as soon as we end one call, we should try to start another.
  204. this.checkForCallInit();
  205. } else if (callState == CallState.IN_ERROR) {
  206. this.decrementOngoingCall();
  207. this.incrementErrorCall();
  208. // as soon as we end one call, we should try to start another.
  209. this.checkForCallInit();
  210. }
  211. // System.err.println("updateCallView:"+this.ongoingCallNumber);
  212. this.callDisplay.updateCallView();
  213. // this is forterm;
  214. if (this.testState == TestState.Terminating) {
  215. if (getOngoingCallNumber() == 0) {
  216. this.stop(false);
  217. }
  218. }
  219. }
  220. public CallStateTableModel getTableModel() {
  221. return this.model;
  222. }
  223. public long getCompletedCallNumber() {
  224. return this.completedCallNumber;
  225. }
  226. public long getErrorCallNumber() {
  227. return this.errorCallNumber;
  228. }
  229. public long getOngoingCallNumber() {
  230. return this.ongoingCallNumber;
  231. }
  232. public void setMaxErrorCallNumber(long v) {
  233. this.maxErrorCallNumber = v;
  234. }
  235. public long getTotalCallNumber() {
  236. return this.totalCalls;
  237. }
  238. public void stop(boolean onGracefull) {
  239. synchronized (this.testState) {
  240. switch (this.testState) {
  241. case Terminating:
  242. if (!onGracefull) {
  243. return;
  244. }
  245. try {
  246. if (this.provider != null) {
  247. try {
  248. this.provider.removeJainMgcpListener(this);
  249. this.stack.deleteProvider(this.provider);
  250. } catch (Exception e) {
  251. e.printStackTrace();
  252. }
  253. }
  254. if (this.stack != null) {
  255. try {
  256. this.stack.close();
  257. } catch (Exception e) {
  258. e.printStackTrace();
  259. }
  260. }
  261. if (callCreatorTask != null) {
  262. callCreatorTask.cancel(true);
  263. }
  264. // FIXME: add more?
  265. try {
  266. for (AbstractCall call : this.callSequenceToCall
  267. .values()) {
  268. if (call.getState() == CallState.ESTABILISHED
  269. || call.getState() == CallState.INITIAL) {
  270. call.stop();
  271. }
  272. }
  273. } catch (Exception e) {
  274. e.printStackTrace();
  275. }
  276. if (_RTP_TXT_DUMP_OSW != null) {
  277. try {
  278. _RTP_TXT_DUMP_OSW.flush();
  279. _RTP_TXT_DUMP_OSW.close();
  280. _RTP_TXT_DUMP_OSW = null;
  281. _RTP_TXT_DUMP_FOS = null;
  282. } catch (Exception e) {
  283. e.printStackTrace();
  284. }
  285. }
  286. if (this.socketFactory != null)
  287. try {
  288. this.socketFactory.stop();
  289. } catch (Exception e) {
  290. e.printStackTrace();
  291. }
  292. // Now lets serialize.
  293. serialize();
  294. // dumpSampleTraffic();
  295. } finally {
  296. this.testState = TestState.Stoped;
  297. this.gracefulStopTask = null;
  298. if (this.timeGuard != null) {
  299. this.timeGuard.shutdownNow();
  300. }
  301. if (this.executors != null) {
  302. this.executors.shutdownNow();
  303. }
  304. }
  305. this.testState = TestState.Stoped;
  306. break;
  307. case Running:
  308. this.testState = TestState.Terminating;
  309. // this.gracefulStopTask = this.
  310. // so we dont have to press stop twice, this is stupid.
  311. if (this.gracefulStopTask == null) {
  312. this.gracefulStopTask = this.executors.schedule(
  313. new GracefulStopTask(this), this.callDisplay
  314. .getCallDuration() + 1000,
  315. TimeUnit.MILLISECONDS);
  316. }
  317. break;
  318. default:
  319. break;
  320. }
  321. }
  322. }
  323. public void start() throws CreateProviderException,
  324. TooManyListenersException {
  325. try {
  326. stop(false);
  327. this.clientTestNodeAddress = InetAddress.getByName(this.callDisplay
  328. .getLocalAddress());
  329. this.serverJbossBindAddress = InetAddress
  330. .getByName(this.callDisplay.getRemoteAddress());
  331. this.stack = new JainMgcpStackImpl(this.clientTestNodeAddress,
  332. this.callDisplay.getLocalPort());
  333. this.provider = (JainMgcpStackProviderImpl) this.stack
  334. .createProvider();
  335. this.provider.addJainMgcpListener(this);
  336. testState = TestState.Running;
  337. onCPSChange();
  338. } catch (UnknownHostException ex) {
  339. Logger.getLogger(AbstractTestCase.class.getName()).log(
  340. Level.SEVERE, null, ex);
  341. }
  342. }
  343. public TestState getTestState() {
  344. return this.testState;
  345. }
  346. public RtpSocketFactory getSocketFactory() {
  347. return socketFactory;
  348. }
  349. public void setCallDisplay(CallDisplayInterface cdi)
  350. throws IllegalStateException, SocketException, IOException {
  351. this.callDisplay = cdi;
  352. this.clientTestNodeAddress = InetAddress.getByName(this.callDisplay
  353. .getRemoteAddress());
  354. this.serverJbossBindAddress = InetAddress.getByName(this.callDisplay
  355. .getRemoteAddress());
  356. this.sdpFactory = SdpFactory.getInstance();
  357. this.testDumpDirectory = new File(cdi.getDefaultDataDumpDirectory(), ""
  358. + this.testTimesTamp);
  359. if (!this.testDumpDirectory.exists()) {
  360. if (!this.testDumpDirectory.mkdirs()) {
  361. throw new IllegalStateException("Failed to create dirs: "
  362. + this.testDumpDirectory);
  363. }
  364. } else {
  365. // This shoudl not happen, but just in case.
  366. if (this.testDumpDirectory.isDirectory()
  367. && this.testDumpDirectory.canWrite()) {
  368. } else {
  369. throw new IllegalStateException(
  370. "Failed to validate dump dir, its either not writeable or is not a directory: "
  371. + this.testDumpDirectory);
  372. }
  373. }
  374. _RTP_TXT_DUMP_FILE = new File(this.testDumpDirectory,
  375. _COLLECTIVE_RTP_FILE);
  376. this.init();
  377. }
  378. // This method is used on loaded test case
  379. public void setCallDisplay(CallDisplayInterface cdi, File testDumpDirectory)
  380. throws UnknownHostException, IllegalStateException {
  381. this.callDisplay = cdi;
  382. this.sdpFactory = SdpFactory.getInstance();
  383. // this.testDumpDirectory = new
  384. // File(testDumpDirectory,""+this.testTimesTamp);
  385. this.testDumpDirectory = testDumpDirectory;
  386. _RTP_TXT_DUMP_FILE = new File(this.testDumpDirectory,
  387. _COLLECTIVE_RTP_FILE);
  388. model = new CallStateTableModel(this.callSequenceToCall);
  389. for (AbstractCall call : this.callSequenceToCall.values()) {
  390. call.setDumpDir(testDumpDirectory);
  391. }
  392. }
  393. public void onCPSChange() {
  394. if (testState == TestState.Stoped) {
  395. return;
  396. }
  397. // we changed CPS.
  398. if (this.callCreatorTask != null) {
  399. this.callCreatorTask.cancel(true);
  400. }
  401. int cps = this.getCallDisplayInterface().getCPS();
  402. if (cps == 0) {
  403. return;
  404. }
  405. int delta = 1000 / this.getCallDisplayInterface().getCPS();
  406. // we use delta,delta, cause we dont want sudden rush in CPS
  407. this.callCreatorTask = this.executors.scheduleAtFixedRate(this, delta,
  408. delta, TimeUnit.MILLISECONDS);
  409. // this.run();
  410. }
  411. public void onCallLengthChange() {
  412. }
  413. public abstract AbstractCall getNewCall();
  414. Vector<Attribute> getSDPAttributes() {
  415. return this.callDisplay.getCodecs();
  416. }
  417. public SdpFactory getSdpFactory() {
  418. return this.sdpFactory;
  419. }
  420. public File getTestDumpDirectory() {
  421. return this.testDumpDirectory;
  422. }
  423. // run in which we create more calls :)
  424. public void run() {
  425. // For some twisted reason constructo does not work...
  426. // model.setCallData(this.callSequenceToCall);
  427. if (this.testState == TestState.Running) {
  428. if (this.maxErrorCallNumber != _TURN_OFF_BOUNDRY
  429. && this.errorCallNumber >= this.maxErrorCallNumber) {
  430. }
  431. if (this.callDisplay.getMaxConcurrentCalls() != _TURN_OFF_BOUNDRY
  432. && this.ongoingCallNumber >= this.callDisplay
  433. .getMaxConcurrentCalls()) {
  434. return;
  435. }
  436. if (this.callDisplay.getMaxCalls() != _TURN_OFF_BOUNDRY
  437. && this.totalCalls == this.callDisplay.getMaxCalls()) {
  438. this.stop(false);
  439. return;
  440. }
  441. try {
  442. // This creates call, which knows how to estabilish itself and
  443. // how long it should linger on as active.
  444. AbstractCall c = this.getNewCall();
  445. this.callSequenceToCall.put(c.getSequence(), c);
  446. callStateChanged(c);
  447. c.start();
  448. } catch (Exception e) {
  449. e.printStackTrace();
  450. }
  451. }
  452. }
  453. private void checkForCallInit() {
  454. if (this.callDisplay.getMaxConcurrentCalls() != -1
  455. && this.callDisplay.getCPS() > 0) {
  456. try {
  457. run();
  458. } catch (Exception e) {
  459. e.printStackTrace();
  460. }
  461. }
  462. }
  463. // some handy methods
  464. public JainMgcpStackProviderImpl getProvider() {
  465. return this.provider;
  466. }
  467. // Event handlers
  468. public void processMgcpCommandEvent(JainMgcpCommandEvent command) {
  469. // For now we dont care for reqeust sent from MMS
  470. if (command instanceof Notify) {
  471. Notify notify = (Notify) command;
  472. AbstractCall cp = getCall(notify.getRequestIdentifier().toString());
  473. if (cp != null) {
  474. cp.processMgcpCommandEvent(command);
  475. }
  476. }
  477. }
  478. public void processMgcpResponseEvent(JainMgcpResponseEvent response) {
  479. // System.out.println("Recived response "+ response);
  480. try {
  481. AbstractCall cp = getCall(response);
  482. if (cp != null) {
  483. cp.processMgcpResponseEvent(response);
  484. } else {
  485. System.err.println("NO CALL");
  486. }
  487. } catch (RuntimeException re) {
  488. re.printStackTrace();
  489. }
  490. }
  491. public void transactionEnded(int arg0) {
  492. AbstractCall cp = getCall(arg0);
  493. if (cp != null) {
  494. cp.transactionEnded(arg0);
  495. } else {
  496. logger.severe("No call proxy for txid: " + arg0);
  497. }
  498. }
  499. public void transactionRxTimedOut(JainMgcpCommandEvent commandTimedOut) {
  500. AbstractCall cp = getCall(commandTimedOut);
  501. if (cp != null) {
  502. cp.transactionRxTimedOut(commandTimedOut);
  503. } else {
  504. logger.severe("No call proxy for txid: "
  505. + commandTimedOut.getTransactionHandle()
  506. + " for timed out event");
  507. }
  508. }
  509. public void transactionTxTimedOut(JainMgcpCommandEvent commandTimeOut) {
  510. AbstractCall cp = getCall(commandTimeOut);
  511. if (cp != null) {
  512. cp.transactionTxTimedOut(commandTimeOut);
  513. } else {
  514. logger.severe("No call proxy for txid: "
  515. + commandTimeOut.getTransactionHandle()
  516. + " for timed out event2");
  517. }
  518. }
  519. // CALL MGMT
  520. protected AbstractCall getCall(JainMgcpEvent mgcpEvent) {
  521. return this.mgcpTransactionToProxy
  522. .get(mgcpEvent.getTransactionHandle());
  523. }
  524. protected AbstractCall getCall(int txID) {
  525. return this.mgcpTransactionToProxy.get(txID);
  526. }
  527. public void removeCall(JainMgcpEvent mgcpEvent) {
  528. this.removeCall(mgcpEvent.getTransactionHandle());
  529. }
  530. public void removeCall(int txID) {
  531. this.mgcpTransactionToProxy.remove(txID);
  532. }
  533. public void addCall(String ri, AbstractCall cp) {
  534. this.requestIdIdToProxy.put(ri, cp);
  535. }
  536. public void removeCall(String ri) {
  537. this.requestIdIdToProxy.remove(ri);
  538. }
  539. public AbstractCall getCall(String ri) {
  540. return this.requestIdIdToProxy.get(ri);
  541. }
  542. public void addCall(JainMgcpEvent mgcpEvent, AbstractCall cp) {
  543. this.mgcpTransactionToProxy.put(mgcpEvent.getTransactionHandle(), cp);
  544. }
  545. /**
  546. * Custom deserialization is needed.
  547. */
  548. private void readObject(ObjectInputStream aStream) throws IOException,
  549. ClassNotFoundException {
  550. aStream.defaultReadObject();
  551. }
  552. /**
  553. * Perofrms all serialization actions
  554. */
  555. protected void serialize() {
  556. this.localAddress = this.callDisplay.getLocalAddress();
  557. this.localPort = this.callDisplay.getLocalPort();
  558. this.remoteAddress = this.callDisplay.getRemoteAddress();
  559. this.remotePort = this.callDisplay.getRemotePort();
  560. this.cps = this.callDisplay.getCPS();
  561. this.callDuration = this.callDisplay.getCallDuration();
  562. this.maxCalls = this.callDisplay.getMaxCalls();
  563. this.maxConcurrentCalls = this.callDisplay.getMaxConcurrentCalls();
  564. this.maxFailCalls = this.callDisplay.getMaxFailCalls();
  565. FileUtils.serializeTestCase(this);
  566. }
  567. /**
  568. * Custom serialization is needed.
  569. */
  570. private void writeObject(ObjectOutputStream aStream) throws IOException {
  571. aStream.defaultWriteObject();
  572. }
  573. /**
  574. * This method is called after stop, to dump case data.
  575. */
  576. private class GracefulStopTask implements Runnable {
  577. private AbstractTestCase atc;
  578. public GracefulStopTask(AbstractTestCase atc) {
  579. super();
  580. this.atc = atc;
  581. }
  582. /*
  583. * (non-Javadoc)
  584. *
  585. * @see java.lang.Runnable#run()
  586. */
  587. public void run() {
  588. atc.stop(true);
  589. }
  590. }
  591. // Those are only for dump purposes
  592. private String localAddress = "127.0.0.1", remoteAddress = "127.0.0.1";
  593. private int localPort = 2428, remotePort = 2427;
  594. private int cps = 1;
  595. private long callDuration = 2500;
  596. private long maxCalls = AbstractTestCase._TURN_OFF_BOUNDRY;
  597. private int maxConcurrentCalls = AbstractTestCase._TURN_OFF_BOUNDRY;
  598. private int maxFailCalls = AbstractTestCase._TURN_OFF_BOUNDRY;
  599. private transient String[] textDump;
  600. public void createGraphicDumps(long sequence) {
  601. AbstractCall call = null;
  602. if (sequence != -1) {
  603. call = this.callSequenceToCall.get(sequence);
  604. } else {
  605. int index0 = this.callSequenceToCall.size() / 2;
  606. Iterator<Long> seqIterator = this.callSequenceToCall.keySet()
  607. .iterator();
  608. while (index0 > 0) {
  609. // seqIterator.next();
  610. index0--;
  611. }
  612. while (call == null && seqIterator.hasNext()) {
  613. Long seq = seqIterator.next();
  614. call = this.callSequenceToCall.get(seq);
  615. if (call.getState() == CallState.IN_ERROR
  616. || call.getState() == CallState.TIMED_OUT) {
  617. call = null;
  618. continue;
  619. } else {
  620. break;
  621. }
  622. }
  623. }
  624. if (call == null) {
  625. throw new RuntimeException("No call found. "+this.callSequenceToCall);
  626. }
  627. try {
  628. call.setTestCase(this);
  629. call.resetReader();
  630. String[] connectionIds = call.getCallLegs();
  631. textDump = new String[connectionIds.length];
  632. for(int i = 0;i<connectionIds.length;i++) {
  633. String connectionId = connectionIds[i];
  634. Deviation devCalculator = new Deviation();
  635. call.resetReader();
  636. List<RtpPacket> workingTraffic = call
  637. .getCallLegRtpData(connectionId);
  638. List<RtpPacket> loadedTraffic = workingTraffic;
  639. do {
  640. // we must do this like that cause collection can store up
  641. // to INteger.MAX_INT entries, and calls can easly have more
  642. // packets....
  643. //now see http://www.ietf.org/rfc/rfc1889.txt section 6.3.1
  644. int currentSize = workingTraffic.size() - 1;
  645. for (int index = 0; index < currentSize; index++) {
  646. RtpPacket p1 = workingTraffic.remove(0);
  647. RtpPacket p2 = workingTraffic.get(0);
  648. double D = p2.getTime().getTime()-p1.getTime().getTime()-p2.getTimestamp()+p1.getTimestamp();
  649. devCalculator.update(D);
  650. }
  651. //load possibly rest of data.
  652. loadedTraffic = call
  653. .getCallLegRtpData(connectionId);
  654. workingTraffic.addAll(loadedTraffic);
  655. } while (loadedTraffic.size() > 0);
  656. textDump[i] = connectionId+" interarrival jitter - mean: "+devCalculator.getMean()+" variance: "+devCalculator.getVariance()+" deviation: "+(Math.sqrt(devCalculator.getVariance()));
  657. //now reset streams reader
  658. call.resetReader();
  659. }
  660. //lets kill streams
  661. call.stopReader();
  662. } catch (IOException e) {
  663. throw new RuntimeException("Failed to create log data.", e);
  664. }
  665. }
  666. public String[] getTextDump() {
  667. return this.textDump;
  668. }
  669. }