Package rtpi.demoRtpi

Source Code of rtpi.demoRtpi.Application

/* The demo application for the RTP/I lib, version 0.1 alpha.
* Copyright (C) 2000 Juergen Vogel, Martin Mauve
* University of Mannheim / Germany
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
*
* Juergen Vogel
* Martin Mauve
*
* e-mail:
* {vogel,mauve}@informatik.uni-mannheim.de
*
* paper mail:
*
* Juergen Vogel
* Martin Mauve
* University of Mannheim
* Lehrstuhl Praktische Informatik IV
* L15, 16
* 68131 Mannheim
* Germany
*/

package rtpi.demoRtpi;

import rtpi.util.SyncQueue;

import rtpi.Rtpi;
import rtpi.RtpiEvent;
import rtpi.RtpiState;
import rtpi.RtpiDeltaState;
import rtpi.RtpiStateQuery;
import rtpi.RtpiSourceInfo;
import rtpi.RtpiRecipient;

import rtpi.reliability.Reliable;
import rtpi.reliability.unreliableUdpMulticast.UnreliableUdpMulticast;

import rtpi.transport.Transport;
import rtpi.transport.ipmc.IPMCTransport;

import java.net.InetAddress;
import java.net.UnknownHostException;

import java.io.InputStream;
import java.io.DataInputStream;
import java.io.OutputStream;
import java.io.DataOutputStream;
import java.io.IOException;

import java.util.Hashtable;
import java.util.Enumeration;

/**
* This is a demo application that shows how RTP/I can be used.
* The demo can be used to see how the API works.
* It is important to realize that it is missing
* several pieces of functionality which are vital for a real application.
* In particular it does not ensure consistency. There are two things that
* could destroy the consistency for this application. (1) When an event
* gets lost. (2) When an event overtakes the state transmission.
* Furthermore the allocation of participant IDs and subcomponent IDs is
* rather simplistic. The IP address is used as participant ID and as base
* value for subcomponent IDs. For each created subcomponent the subcomponent
* ID counter is increase.
* In short please use this to see how the API works but don't take it as a
* working example for a distributed interactive medium.
*/

public class Application implements RtpiRecipient {

    private static final int BYTE_MASK = 0x000000FF;

    static final boolean debug = true;

    private Rtpi rtpi; // The main RTP/I session

    private RtpiSourceInfo localParticipant; // The source information that is to be used for the main RTP/I session
    private long subIDBase; // The lower 32 bits for sub componenets that are created by this participant
    private long subcomponentNumber; // The number of the last subcomponent that has been created by this participant;

    private Reliable reliabilityService; // The reliability service for the main RTP/I session
   
    private SyncQueue messages = new SyncQueue(); // The message queue for message passing

    private ApplicationView view; // The gui
    private Hashtable subcomponents = new Hashtable(); // The subcomponents

    /**
     * This creates a new application.
     *
     * @param appmcAddress The multicast address for the main RTP/I session.
     * @param port The port for RTP/I in the main RTP/I session. port+1 is used for RTCP/I in the
     *             main RTCP/I session.
     * @param ttl The time to live.
     */

    public Application(String appmcAddress, int port, int ttl) {

  String cname="";
  InetAddress myIPAddress=null;

  try {
      myIPAddress = InetAddress.getLocalHost();
  } catch(UnknownHostException e) {
      System.out.println("Application::Application - Could not get local InetAddress - exiting!");
      System.exit(0);
  }

  try {
      if ((cname=System.getProperty("user.name"))==null) {
    cname="unknown";
      }
     
      cname += "@"+myIPAddress.getHostName(); // construct the cname for the local participant
     
  } catch (Exception ex) {
      System.err.println("Controler: Unable to construct RTP cname for local participant - exiting! "+ex);
      System.exit(0);
  }

  byte[] baseBytes = myIPAddress.getAddress();
  subIDBase=(baseBytes[3]&BYTE_MASK) |
      ((baseBytes[2]&BYTE_MASK) << 8) |
      ((baseBytes[1]&BYTE_MASK) << 16) |
      ((baseBytes[0]&BYTE_MASK) << 24);
  subIDBase=subIDBase & 0xFFFFFFFFl; /* subIDBase == the IP address. We use this also as Participant ID
              * it would be better to get the participant ID from somewhere else.
              * However, for this simple example it should suffice.
              */
  try {
      localParticipant = new RtpiSourceInfo((int)subIDBase, cname);
  } catch (Exception ex) {
      System.err.println("Controler: Could not create local participant - exiting!");
      System.exit(0);
  }

  InetAddress group=null;

  try {
      group = InetAddress.getByName(appmcAddress);
      if (!group.isMulticastAddress()) {
    System.out.println("Usage: java rtpi.demoRtpi.Application " +
           "<multicast address> <port number> <ttl>");
    System.exit(0);
      }

  } catch (Exception ex) {
      System.err.println("Invalid multicast address - exiting!");
      System.exit(0);
  }

  UnreliableUdpMulticast reliabilityService=null;
  Transport rtcpTransport=null;
 
  try {
      reliabilityService=new UnreliableUdpMulticast(group, port, ttl, 5000000, 10000);
      rtcpTransport = new IPMCTransport(group, port+1, ttl, 5000000);
  } catch (Exception ex) {
      System.out.println("Could not create Transport and reliability service instances - exiting!");
      System.exit(0);
  }

  System.out.println("reliablitiyService " + reliabilityService);

  rtpi = new Rtpi(reliabilityService, // The reliability service used for the RTP/I session
      localParticipant,   // The source info of the local source
      rtcpTransport,      // The transport instnce for RTCP/I
      2000,               // The maximum available bandwidth for RTCP/I
      true);              // We will use application level names

  rtpi.setRtpiRecipient(this);

  try {
      rtpi.joinGroup(); // We are responsible for joining and leaving the main RTP/I session
  } catch (Exception ex) {
      System.err.println("Controler: could not join session - exiting!");
      System.exit(0);
  }

  view = new ApplicationView(this, cname); // Init the GUI
    }

    /**
     * This creates a new subcomponent. The state of the subcomponent is immediately transmitted.
     *
     * @return The new subcomponent.
     */

    Subcomponent createSubcomponent() {
  long id =  subIDBase | ((subcomponentNumber++)<<32); // create a 'unique' subcomponent ID
  String name = "Sub"+id;                              // the application level name
  Subcomponent comp = new Subcomponent(this, name, id);
  comp.setStateReceived();
  subcomponents.put(new Long(id), comp);

  // register new SubComponent and transmit its state
  try {
      System.out.println("trying to add new subcomponent to RTPI");
      rtpi.addSubcomponent(id, comp.getNameBytes(), true); // this tells RTP/I that we are tracking the state of this subcomponent
                                                           // and that it is active. This is used for RTCP/I subreps
  } catch (Exception ex) {
      System.err.println("Application: Unable to add subcomponent to RTP/I - exiting!");
      System.exit(0);
  }
  RtpiState state=null;

  try {
      state = new RtpiState(localParticipant.getParticipantID(), // The participant ID of the local source
          id, // The subcomponent ID
          comp.getNextStateSequenceNumber(), // The sequence number of this state ADU
          10, // The payload type
          3, // The priority (3=max priority, this should force everyone to reset the state of the subcomponent)
          System.currentTimeMillis(), // The timestamp of the ADU
          rtpi.getCombinedHeaderSize()); // The headersize of RTP/I and the reliability service.
  } catch (Exception ex) {
      System.err.println("Application: Could not create rtpi state for transmission - exiting!");
      System.exit(0);
  }
  try {
      OutputStream os = state.getOutputStream(); // Get the output stream for this state
      os.write(comp.getNameBytes()); // this is already an UTF encoded string - see constructor of Subcomponent!
                                     // The recipient of the state should be able to derive the application level name of
                                     // the subcomponent.
      os.write(comp.getState());
  } catch(Exception e) {
      System.out.println("Application::createComponent - exception while writing packet "+e);
      System.exit(0);
  }
  state.outputComplete(); // Finish the output
  rtpi.transmitState(state); // Let RTP/I do the rest.
  return comp;
    }

    Subcomponent getSubcomponent(long id) {
  return (Subcomponent)subcomponents.get(new Long(id));
    }


    /**
     * This transmits an increment event for a subcomponent.
     *
     * @param id The subcomponent ID of the affected subcomponent.
     */

    void sendIncrEvent(long id) {
  Subcomponent sub = (Subcomponent) subcomponents.get(new Long(id));
  if (sub==null) {
      System.err.println("Received event for non existing subcomponent - ignoring event!");
      return;
  }

  RtpiEvent event=null;

  try {
      event = new RtpiEvent(localParticipant.getParticipantID(), // The participant ID of the local source
          id, // The subcomponent ID
          sub.getNextEventSequenceNumber(), // The sequence number of this event ADU
          10, // The payload type
          System.currentTimeMillis(), // The timestamp of this event
          rtpi.getCombinedHeaderSize()); // The combined header size of the RTP/I and the relibaility service headers
  } catch (Exception ex) {
      System.err.println("Could not create rtpi event for transmission - exiting!");
      System.exit(0);
  }

  try {
      event.getOutputStream().write(1); // Write the event data
  } catch(IOException e) {
      System.out.println("Application::SendIncrEvent - exception while writing packet "+e);
      System.exit(0);
  }

  event.outputComplete(); // Finish the output to the event
  rtpi.transmitEvent(event); // Use RTP/I to transmit the event.
    }

    /**
     * This is called by the GUI when the user activates a formerly deactivated subcomponent.
     *
     * @param id The subcomponent ID of the affected subcomponent.
     */

    void activateSubcomponent(long id) {
  System.out.println("Activating subid: "+id);
  rtpi.activateSubcomponent(id); // Tell RTP/I that this subcomponent is now active for this participant
    }

    /**
     * This is called by the GUI when the user deactivates a formerly activated subcomponent.
     *
     * @param id The subcomponent ID of the affected subcomponent.
     */

    void deactivateSubcomponent(long id) {
  System.out.println("Deactivating subid: "+id);
  rtpi.deactivateSubcomponent(id); // Tell RTP/I that this subcomponent is no longer active for this participant
    }

    /**
     * This function is used for message passing between the application and other threads. It should prevent
     * race conditions and deadlocks. Does anyone have a better solution for this? Other threads place messages
     * into the message queue. The application simply gets those messages.
     */

    public void work() {
  ApplicationMessage message = null;
  while (true) {
      try {
    message = (ApplicationMessage)messages.get();
      } catch (Exception ex) {
    System.err.println("Application::work - could not get next message - exiting!");
    System.exit(0);
      }
      switch(message.opCode) {
      case ApplicationMessage.RECEIVE_EVENT: {
    ApplicationMessageArgs args = (ApplicationMessageArgs)message.args;
    execReceiveEvent(args.rtpi, (RtpiEvent)args.data);
    break;
      }
      case ApplicationMessage.RECEIVE_STATE: {
    ApplicationMessageArgs args = (ApplicationMessageArgs)message.args;
    execReceiveState(args.rtpi, (RtpiState)args.data);
    break;
      }
      case ApplicationMessage.RECEIVE_DELTA_STATE: {
    ApplicationMessageArgs args = (ApplicationMessageArgs)message.args;
    execReceiveDeltaState(args.rtpi, (RtpiDeltaState)args.data);
    break;
      }
      case ApplicationMessage.RECEIVE_STATE_QUERY: {
    ApplicationMessageArgs args = (ApplicationMessageArgs)message.args;
    execReceiveStateQuery(args.rtpi, (RtpiStateQuery)args.data);
    break;
      }
      }
  }
    }


    /**
     * This is called by RTP/I when an event has been received. We put this message in the message
     * queue and execute the event in the application thread.
     *
     * @param r The RTP/I instance from which the event has been received.
     * @param event The RTP/I event.
     */

    public void receiveEvent(Rtpi r, RtpiEvent event) { // this is called by the RTP/I thread
  messages.put(new ApplicationMessage(ApplicationMessage.RECEIVE_EVENT,
              new ApplicationMessageArgs(r, event)));
    }

    private void execReceiveEvent(Rtpi r, RtpiEvent event) { // this is called in the application thread
  Subcomponent comp = getSubcomponent(event.getSubcomponentID());
  if (comp == null) { // If we have no state yet we ignore the event.
      System.out.println("Application::receiveEvent - unknown subcomponent !");
      return;
  }

  comp.setState((byte)(comp.getState() + 1)); // set the new state. We don't need to examine the event more closely since we have only
                                              // one possible event.
    }


    public void receiveState(Rtpi r, RtpiState state) {
  messages.put(new ApplicationMessage(ApplicationMessage.RECEIVE_STATE,
              new ApplicationMessageArgs(r, state)));
    }

    private void execReceiveState(Rtpi r, RtpiState state) {
  System.out.println("Application: State received!");
 
  long id = state.getSubcomponentID();
  Subcomponent comp = getSubcomponent(id);
 
  byte stateValue=0;
  String subcomponentName=null;

  DataInputStream din = new DataInputStream (state.getInputStream()); // Get the data input stream of the state
 
  try {
      subcomponentName = din.readUTF(); // Read the application level name
      stateValue = (byte) din.read(); // Read the state
  catch (Exception ex) {
      System.out.println("Application: Error while reading data from received state - exiting!");
      System.exit(0);
  }

  if (comp == null) { // new Component
      comp = new Subcomponent(this, subcomponentName, id);
      subcomponents.put(new Long(id), comp);
      comp.setState(stateValue);
      comp.setStateReceived();
      try {
    rtpi.addSubcomponent(id, comp.getNameBytes(), true); // Tell RTP/I that the new subcomponent is now tracked by this participant.
      } catch (Exception ex) {
    System.err.println("Application could not add subcomponent to rtpi: "+ex+" - exiting!");
    System.exit(0);
      }
      view.addSubcomponent(comp);

      if (debug) {
    System.out.println("Application::receiveState - " +
           "received State for new Component with ID " + id);
      }
      return;
  }

  if (comp.getStateReceived()) { // We have received a state that we do not need (since we already have it)
      if (debug)
    System.out.println("Application::receiveState - " +
           "Component with ID " + id + " already exists "
           + System.currentTimeMillis());
      return;
  }

  comp.setState(stateValue);
  comp.setStateReceived();
  try {
      rtpi.addSubcomponent(id, comp.getNameBytes(), true);
  } catch (Exception ex) {
      System.err.println("Application could not add subcomponent to rtpi: "+ex);
      System.exit(0);
  }
  view.addSubcomponent(comp);
 
  if (debug) {
      System.out.println("Application::receiveState - received State for Component with ID " + id);
  }
    }

    public void receiveDeltaState(Rtpi r, RtpiDeltaState state) { // We don't use these!
  messages.put(new ApplicationMessage(ApplicationMessage.RECEIVE_DELTA_STATE,
              new ApplicationMessageArgs(r, state)));
    }

    private void execReceiveDeltaState(Rtpi r, RtpiDeltaState state) {
    }


    public void receiveStateQuery(Rtpi r, RtpiStateQuery query) { // We do not answer state queries, since we are not
                                                            // concerned with consistency for this demo application.
  messages.put(new ApplicationMessage(ApplicationMessage.RECEIVE_STATE_QUERY,
              new ApplicationMessageArgs(r, query)));
    }

    private void execReceiveStateQuery(Rtpi r, RtpiStateQuery query) {
    }

    public void close() {
  rtpi.leaveGroup();
  System.exit(0);
    }

    public static void main(String[] args){
  if (args.length!=3) {
      System.out.println("Usage: java rtpi.demoRtpi.Application " +
             "<multicast address> <port number> <ttl>");
      System.exit(0);
  }

  String address1 = args[0];
  int port = 0;
  int ttl=0;

  try {
      port = Integer.parseInt(args[1]);
  } catch (Exception ex) {
      System.out.println("Usage: java rtpi.demoRtpi.Application " +
             "<multicast address> <port number> <ttl>");
      System.exit(0);
  }

  try {
      ttl = Integer.parseInt(args[2]);
  } catch (Exception ex) {
      System.out.println("Usage: java rtpi.demoRtpi.Application " +
             "<multicast address> <port number> <ttl>");
      System.exit(0);
  }

  new Application(address1, port, ttl).work();
    }

    public void rtpiAduLost(Rtpi rtpi, int participantID, long subID, int type, int sequenceNumber, int timestamp) {
  System.out.println("Application: rtpiAduLost called!");
    }

    public void rtpiCouldNotRecover(Rtpi rtpi, int participantID, long subID, int type, int sequenceNumber, int timestamp) {
  System.out.println("Application: rtpiCouldNotRecover called!");
    }

    public void connectionClosed(Rtpi rtpi) {
  System.out.println("Application: connectionClosed called - exiting!");
  System.exit(0);
    }

    public void changeSourceInfo(Rtpi rtpi, RtpiSourceInfo participant) {
  System.out.println("Application: changeSourceInfo called!");
    }

    public void removeSource(Rtpi rtpi, RtpiSourceInfo participant) {
  System.out.println("Application: removeSource called!");
    }

    public void addSubcomponent(Rtpi rtpi, long subcomponentID, boolean active, byte[] name) {
  System.out.println("Application: addSubcomponent called!");
    }

    public void removeSubcomponent(Rtpi rtpi, long subcomponentID) {
  System.out.println("Application: removeSubcomponent called!");
    }

    public void activateSubcomponent(Rtpi rtpi, long subcomponentID) {
  System.out.println("Application: activateSubcomponent called!");
    }

    public void deactivateSubcomponent(Rtpi rtpi, long subcomponentID) {
  System.out.println("Application: deactivateSubcomponent called!");
    }
}







TOP

Related Classes of rtpi.demoRtpi.Application

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.