/* * To change this template, choose Tools | Templates * and open the template in the editor. */ package org.mobicents.media.server.testsuite.general; import jain.protocol.ip.mgcp.message.parms.CallIdentifier; import jain.protocol.ip.mgcp.message.parms.EndpointIdentifier; import java.io.BufferedReader; import java.io.ByteArrayOutputStream; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStreamReader; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.io.OutputStreamWriter; import java.io.Serializable; import java.util.ArrayList; import java.util.List; import java.util.Vector; import java.util.concurrent.ScheduledFuture; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicLong; import javax.sdp.Attribute; import javax.sdp.MediaDescription; import javax.sdp.SdpException; import javax.sdp.SdpFactory; import javax.sdp.SessionDescription; import org.apache.log4j.Logger; import org.mobicents.media.server.testsuite.general.rtp.RtpPacket; import org.mobicents.media.server.testsuite.general.rtp.RtpSocket; import org.mobicents.media.server.testsuite.general.rtp.RtpSocketFactory; import org.mobicents.media.server.testsuite.general.rtp.RtpSocketListener; import org.mobicents.mgcp.stack.JainMgcpExtendedListener; import org.mobicents.mgcp.stack.JainMgcpStackProviderImpl; /** * * @author baranowb */ public abstract class AbstractCall implements JainMgcpExtendedListener, Serializable, RtpSocketListener { protected transient Logger logger = Logger.getLogger(AbstractCall.class); // Some static vals: protected transient static final AtomicLong _GLOBAL_SEQ = new AtomicLong(-1); protected transient static final long _DATA_DUMP_DELAY = 2500; protected transient static final long _DATA_DUMP_RATE = 2500; protected final long sequence; protected CallState state = CallState.INITIAL; protected int avgJitter; protected int peakJitter; protected long lastDeliverTimeStamp; // Data dump // protected transient java.io.File dataFileName; // protected transient java.io.File graphDataFileName; // protected transient java.io.File pureRtpDataFileName; // protected transient FileOutputStream fos; // protected transient ObjectOutputStream dataDumpChannel; // protected transient FileOutputStream graphDataDumpChannel; protected transient List<RtpPacket> rtpTraffic = new ArrayList<RtpPacket>(); // Media part protected String endpointName = ""; // endpoint name with wildcard - used to // send to mms to get actual EI protected EndpointIdentifier endpointIdentifier; protected CallIdentifier callIdentifier; // Below is part we dont want to propagate to other side :) protected transient AbstractTestCase testCase; // RTP part protected transient RtpSocket socket; // MGCP part protected transient JainMgcpStackProviderImpl provider; protected transient ScheduledFuture<?> timeoutHandle; protected transient ScheduledFuture<?> dataDumpFuture; public static void resetSequence() { _GLOBAL_SEQ.set(-1); } public AbstractCall(AbstractTestCase testCase) throws IOException { this.testCase = testCase; this.callIdentifier = testCase.getProvider().getUniqueCallIdentifier(); try { this.sequence = _GLOBAL_SEQ.incrementAndGet(); setTestCase(testCase); } finally { } } void setTestCase(AbstractTestCase testCase) { this.testCase = testCase; this.setDumpDir(this.testCase.getTestDumpDirectory()); this.provider = testCase.getProvider(); } void setDumpDir(File testDumpDirectory) { // this.dataFileName = new File(testDumpDirectory, this.sequence + // ".mrtp"); // this.pureRtpDataFileName = new File(testDumpDirectory, this.sequence // + ".rtp"); // this.graphDataFileName = new File(testDumpDirectory, this.sequence + // "_graph.txt"); } // public java.io.File getGraphDataFileName() { // return graphDataFileName; // } protected void initSocket() throws IOException { if (this.testCase != null && this.testCase.getSocketFactory() != null) { RtpSocketFactory factory = this.testCase.getSocketFactory(); this.socket = factory.createSocket(); socket.addListener(this); } } protected void releaseSocket() { try { if (this.socket != null) { this.socket.release(); this.socket = null; } } catch (Exception e) { e.printStackTrace(); } } public List<RtpPacket> getRtp() throws IOException { List<RtpPacket> ll = this.loadRtp(); return ll; } private List<RtpPacket> loadRtp() throws IOException { ArrayList<RtpPacket> list = new ArrayList(); String startString = this.sequence + ":"; InputStreamReader isw = this.testCase.getRtpISR(); BufferedReader br = new BufferedReader(isw); String line = null; while ((line = br.readLine()) != null) { if (!line.startsWith(startString)) continue; line = line.trim(); RtpPacket p = new RtpPacket(); p.deserializeFromString(line); list.add(p); } br.close(); return list; } public CallState getState() { return state; } public int getAvgJitter() { return this.avgJitter; } public int getPeakJitter() { return this.peakJitter; } public EndpointIdentifier getEndpoint() { return this.endpointIdentifier; } public CallIdentifier getCallID() { return this.callIdentifier; } public long getSequence() { return this.sequence; } protected void setState(CallState state) { if (logger.isDebugEnabled()) { logger.debug("Dumping data to file. State = " + state); } if (state == this.state) { return; } this.state = state; switch (this.state) { case ENDED: case IN_ERROR: case TIMED_OUT: this.releaseSocket(); performDataDumps(true); break; default: break; } this.testCase.callStateChanged(this); } void performDataDumps(boolean isFinal) { try { if (rtpTraffic == null) return; int currentSize = rtpTraffic.size() - 1; OutputStreamWriter osw = testCase.getRtpOSW(); for (int i = 0; i < currentSize; i++) { RtpPacket p1 = rtpTraffic.remove(0); RtpPacket p2 = rtpTraffic.get(0); int localJitter = (int) (p2.getTime().getTime() - p1.getTime().getTime()); if (localJitter > this.peakJitter) this.peakJitter = localJitter; // Aprox this.avgJitter += localJitter; this.avgJitter /= 2; try { osw.write(p1.serializeToString()); osw.write("\n"); } catch (Exception e) { e.printStackTrace(); } } if (isFinal) { this.rtpTraffic.clear(); this.rtpTraffic = null; } } catch (Exception e) { //e.printStackTrace(); // we dont sync, this is penalty :) } } protected String getLocalDescriptor(int port) { SessionDescription localSDP = null; String userName = "Mobicents-Call-Generator"; long sessionID = System.currentTimeMillis() & 0xffffff; long sessionVersion = sessionID; String networkType = javax.sdp.Connection.IN; String addressType = javax.sdp.Connection.IP4; SdpFactory sdpFactory = testCase.getSdpFactory(); try { localSDP = sdpFactory.createSessionDescription(); localSDP.setVersion(sdpFactory.createVersion(0)); localSDP.setOrigin(sdpFactory.createOrigin(userName, sessionID, sessionVersion, networkType, addressType, this.testCase.getClientTestNodeAddress().getHostAddress())); localSDP.setSessionName(sdpFactory.createSessionName("session")); localSDP.setConnection(sdpFactory.createConnection(networkType, addressType, this.testCase.getClientTestNodeAddress().getHostAddress())); Vector<Attribute> attributes = testCase.getSDPAttributes(); int[] audioMap = new int[attributes.size()]; for (int index = 0; index < audioMap.length; index++) { String m = attributes.get(index).getValue().split(" ")[0]; audioMap[index] = Integer.valueOf(m); } // generate media descriptor MediaDescription md = sdpFactory.createMediaDescription("audio", port, 1, "RTP/AVP", audioMap); // set attributes for formats md.setAttributes(attributes); Vector descriptions = new Vector(); descriptions.add(md); localSDP.setMediaDescriptions(descriptions); } catch (SdpException e) { e.printStackTrace(); } return localSDP.toString(); } public abstract void start(); public abstract void timeOut(); public abstract void stop(); protected void onStart() { this.dataDumpFuture = this.testCase.getExecutors().scheduleAtFixedRate(new Runnable() { public void run() { performDataDumps(false); } }, _DATA_DUMP_DELAY, _DATA_DUMP_RATE, TimeUnit.MILLISECONDS); } protected void onStop() { if (this.dataDumpFuture != null) { this.dataDumpFuture.cancel(false); this.dataDumpFuture = null; } } public ScheduledFuture<?> getTimeoutHandle() { return timeoutHandle; } public void setTimeoutHandle(ScheduledFuture<?> timeoutHandle) { this.timeoutHandle = timeoutHandle; } // ////////////////// // SOCKET METHODS // // ////////////////// public void error(Exception e) { // FIXME? } public void receive(RtpPacket packet) { if (this.rtpTraffic != null) { this.rtpTraffic.add(packet); packet.minimize(); packet.setCallSequence(this.sequence); } } /** * @return */ public String getCallSpecificData() { StringBuffer sb = new StringBuffer(); sb.append(AbstractTestCase._LINE_SEPARATOR); //sb.append((sequence + AbstractTestCase._LINE_SEPARATOR)); //sb.append((avgJitter + AbstractTestCase._LINE_SEPARATOR)); //sb.append((peakJitter + AbstractTestCase._LINE_SEPARATOR)); try { this.rtpTraffic = loadRtp(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } for (int i = 0; i < rtpTraffic.size() - 1; i++) { RtpPacket p1 = rtpTraffic.get(i); RtpPacket p2 = rtpTraffic.get(i + 1); int localJitter = (int) (p2.getTime().getTime() - p1.getTime().getTime()); sb.append((localJitter + AbstractTestCase._LINE_SEPARATOR)); } this.rtpTraffic.clear(); this.rtpTraffic = null; return sb.toString(); } }