Package com.xonami.javaBellsSample

Source Code of com.xonami.javaBellsSample.JavaBellsSample

/**
*
*/
package com.xonami.javaBellsSample;

import java.io.IOException;
import java.lang.Thread.UncaughtExceptionHandler;
import java.util.List;
import java.util.logging.Level;

import net.java.sip.communicator.impl.protocol.jabber.extensions.jingle.ContentPacketExtension;
import net.java.sip.communicator.impl.protocol.jabber.extensions.jingle.ContentPacketExtension.SendersEnum;
import net.java.sip.communicator.impl.protocol.jabber.extensions.jingle.JingleIQ;
import net.java.sip.communicator.impl.protocol.jabber.extensions.jingle.JinglePacketFactory;
import net.java.sip.communicator.impl.protocol.jabber.extensions.jingle.ContentPacketExtension.CreatorEnum;

import org.jitsi.service.libjitsi.LibJitsi;
import org.jitsi.service.neomedia.MediaType;
import org.jivesoftware.smack.ConnectionConfiguration;
import org.jivesoftware.smack.PacketListener;
import org.jivesoftware.smack.XMPPConnection;
import org.jivesoftware.smack.filter.PacketFilter;
import org.jivesoftware.smack.packet.Packet;

import org.jivesoftware.smackx.ServiceDiscoveryManager;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.xonami.javaBells.IceAgent;
import com.xonami.javaBells.JingleManager;
import com.xonami.javaBells.JinglePacketHandler;
import com.xonami.javaBells.JingleSession;
import com.xonami.javaBells.JingleStreamManager;
import com.xonami.javaBells.StunTurnAddress;

import org.jivesoftware.smackx.entitycaps.EntityCapsManager;

/**
*
* This is the main class for demonstrating jingle bells.
* Compile and run without arguments for usage.
*
* @author bjorn
*
*/
public class JavaBellsSample {
  enum Action {
    CALL,
    ANSWER,
    CALL_AND_ANSWER
  }
  protected final static Logger logger = LoggerFactory.getLogger(Logger.class);
 
  private static final String CALLER = "Caller";
  private static final String RECEIVER = "Receiver";
 
  private final String username, password, host;
 
  private final String callerJid, receiverJid;
 
  private boolean running = true;
  private Thread answerThread, callThread;
 
  /** prints usage and exits. */
  public static void usage(String name) {
    System.out.println( "Usage: " + name + " action username password host" );
    System.out.println( "\t action: may be CALL, ANSWER or CALL_AND_ANSWER" );
    System.out.println( "\t best to run twice with CALL and ANSWER than CALL_AND_ANSWER" );
    System.out.println( "\t because there is a race condition with CALL_AND_ANSWER." );
    System.exit(1);
  }

  public static void main(String[] args) {
    if( args.length != 5 )
      usage(args[0]);
   
    Thread.setDefaultUncaughtExceptionHandler( new UncaughtExceptionHandler() {
      @Override
      public void uncaughtException(Thread t, Throwable e) {
        logger.error("In thread: ", t);
        logger.error("Uncaught Exception: ", e);
      }
    }) ;
   
    // reduce the insane, unreadable amount of chattiness from libjitsi and ice4j:
    java.util.logging.Logger l = java.util.logging.Logger.getLogger("");
    l.setLevel(Level.WARNING);
   
    // -- libjitsi needs to be started
    LibJitsi.start();
   
    // -- we need to initialize jingle
    JingleManager.enableJingle();

    // parse commandline args:
    String cmd      = args[0];
    System.out.println( "cmd: " + cmd );
    Action action   = Action.valueOf(args[1]);
    System.out.println( "action: " + action );
    String username = args[2];
    String password = args[3];
    String host     = args[4];
   
    System.out.println( "u/p @ h: " + username + " / " + password + " @ " + host);
   
    // start threads to actually do the work of calling/answering:
    JavaBellsSample m = new JavaBellsSample( username, password, host );
    if( action == Action.ANSWER || action == Action.CALL_AND_ANSWER ) {
      m.startAnswer();
    }
    if( action == Action.CALL || action == Action.CALL_AND_ANSWER ) {
      m.startCall();
    }
   
    // stop threads when the user hits enter, cleanup and exit.
    System.out.println( "Hit enter to stop: " );
    while( true )
      try {
        System.in.read();
        break;
      } catch (IOException e) {}
    m.joinAll();
    LibJitsi.stop();
    System.exit(0);
  }
 
  /** creates a new object with the given username and password on the given host. */
  public JavaBellsSample( String username, String password, String host ) {
    this.username = username;
    this.password = password;
    this.host     = host;
   
    callerJid = username + "@" + host + "/" + CALLER ;
    receiverJid = username + "@" + host + "/" + RECEIVER ;
  }
 
  /** waits for both calling and answering thread to return. */
  public void joinAll() {
    running = false;
    if( answerThread != null )
      while( true )
        try {
          synchronized( answerThread ) {
            answerThread.notify();
          }
          answerThread.join();
          break;
        } catch (InterruptedException e) {}
    if( callThread != null )
      while( true )
        try {
          synchronized( callThread ) {
            callThread.notify();
          }
          callThread.join();
          break;
        } catch (InterruptedException e) {}
  }
 
  /** starts a "receiver" in another thread. The receiver connects to the XMPP server,
   * and waits for a jingle session initiation request from the caller.
   */
  public void startAnswer() {
    answerThread = new Thread() {
      @Override
      public void run() {
        try {
          log( RECEIVER, "connecting to " + host );
         
          // connect to host (don't log in yet)
          ConnectionConfiguration config = new ConnectionConfiguration(host);
          XMPPConnection connection = new XMPPConnection( config );
          connection.connect();
          // setup service discovery and entity capabilities.
          // this ensures that other software, such as Jitsi, knows that we support
          // ice and so on
          //ServiceDiscoveryManager.setIdentityName("Java Bells");
          ServiceDiscoveryManager disco = ServiceDiscoveryManager.getInstanceFor(connection);
          EntityCapsManager ecm = EntityCapsManager.getInstanceFor(connection);
         
          ecm.enableEntityCaps();

          disco.addFeature("http://jabber.org/protocol/disco#info");
          disco.addFeature("urn:xmpp:jingle:1");
          disco.addFeature("urn:xmpp:jingle:transports:ice-udp:1");
          disco.addFeature("urn:xmpp:jingle:apps:rtp:1");
          disco.addFeature("urn:xmpp:jingle:apps:rtp:audio");
          disco.addFeature("urn:xmpp:jingle:apps:rtp:video");
         
          // Handle all incoming Jingle packets with a Jingle Packet Handler.
          // The main thing we need to do is ensure that created Jingle sessions
          // are of our ReceiverJingleSession type.
          new JinglePacketHandler(connection) {
            @Override
            public JingleSession createJingleSession( String sid, JingleIQ jiq ) {
              return new ReceiverJingleSession(this, callerJid, sid, this.connection );
            }
          } ;
         
          // display out all packets that get sent:
          connection.addPacketSendingListener(
            new PacketListener() {
              @Override
              public void processPacket(Packet packet) {
                System.out.println( RECEIVER + " SENDING : " + packet.toXML() );
              }
            },
            new PacketFilter() {
              @Override
              public boolean accept(Packet packet) {
                return true;
              }
            } ) ;
         
          // display incoming jingle packets
          connection.addPacketListener( new PacketListener() {
            @Override
            public void processPacket(Packet packet) {
              JingleIQ j = (JingleIQ) packet;
              System.out.println( RECEIVER + "[jingle packet]: " + j.getSID() + " : " + j.getAction() );
            }},
            new PacketFilter() {
            @Override
            public boolean accept(Packet packet) {
              return packet.getClass() == JingleIQ.class;
            }} );
          //display all incoming packets
          connection.addPacketListener( new PacketListener() {
            @Override
            public void processPacket(Packet packet) {
              System.out.println( RECEIVER + ": " + packet.toXML() );
            }},
            new PacketFilter() {
            @Override
            public boolean accept(Packet packet) {
              return true;
            }} );

          // -- log in
          log( RECEIVER, "logging on as " + username + "/" + RECEIVER );
          connection.login(username, password, RECEIVER);
         
          // -- just hang out until we are asked to exit.
          // the work will be done by the ReceiverJingleSession
          // we created and applied earlier.
          log( RECEIVER, "Waiting..." );
          while( running ) {
            synchronized ( this ) {
              try {
                wait(1000);
              } catch (InterruptedException e) {}
            }
          }
          connection.disconnect();
          log( RECEIVER, "Done. Exiting thread." );
        } catch ( Exception e ) {
          System.out.println( RECEIVER + ": " + e );
          e.printStackTrace();
          System.exit(1);
        }
      }
    };
    answerThread.start();
  }
 
  /** starts a "caller" in another thread. The caller connects to the XMPP server,
   *  sends the "receiver" a jingle request.
   */
  public void startCall() {
    callThread = new Thread() {
      @Override
      public void run() {
        try {
          log( CALLER, "connecting to " + host );

          // connect to the XMPP server. Don't log in yet.
          XMPPConnection connection = new XMPPConnection( host );
          connection.connect();

          // derive stun and turn server addresses from the connection:
          StunTurnAddress sta = StunTurnAddress.getAddress( connection );
          // create an ice agent using the stun/turn address. We will need this to figure out
          // how to connect our clients:
          final IceAgent iceAgent = new IceAgent(true, sta);
          // setup our jingle stream manager using the default audio and video devices:
          final JingleStreamManager jsm = new JingleStreamManager(CreatorEnum.initiator);
          jsm.addDefaultMedia(MediaType.VIDEO, "video");
          jsm.addDefaultMedia(MediaType.AUDIO, "audio");
          // create ice streams that correspond to the jingle streams that we want
          iceAgent.createStreams(jsm.getMediaNames());
         
          // Handle all incoming Jingle packets with a Jingle Packet Handler.
          // The main thing we need to do is ensure that created Jingle sessions
          // are of our ReceiverJingleSession type.
          new JinglePacketHandler(connection) {
            @Override
            public JingleSession createJingleSession( String sid, JingleIQ jiq ) {
              return new CallerJingleSession(iceAgent, jsm, this, receiverJid, sid, this.connection);
            }
          } ;
         
          // display all incoming packets:
          connection.addPacketListener( new PacketListener() {
              @Override
              public void processPacket(Packet packet) {
                System.out.println( CALLER + ": " + packet.toXML() );
              }
            },
            new PacketFilter() {
              @Override
              public boolean accept(Packet packet) {
                return packet.getClass() == JingleIQ.class;
              }
            } );
         
//          PacketCollector collector = connection.createPacketCollector( new PacketFilter() {
//            @Override
//            public boolean accept(Packet packet) {
//              return true;
//            }} );
         
          // log in:
          log( CALLER, "logging on as " + username + "/" + CALLER );
          connection.login(username, password, CALLER);
         
          //this only works if they are in our roster
//          log( CALLER, "Waiting for Receiver to become available." );
//          while( running && !connection.getRoster().contains(receiverJid) ) {
//            collector.nextResult(100);
//          }
         
          // Use Ice and JingleSessionManager to initiate session:
          log( CALLER, "Ringing" );
          List<ContentPacketExtension> contentList = jsm.createContentList(SendersEnum.both);
          iceAgent.addLocalCandidateToContents(contentList);
         
                JingleIQ sessionInitIQ = JinglePacketFactory.createSessionInitiate(
                    connection.getUser(),
                    receiverJid,
                    JingleIQ.generateSID(),
                    contentList );
               
                System.out.println( "CALLER: sending jingle request: " + sessionInitIQ.toXML() );
               
                connection.sendPacket(sessionInitIQ);
         
                // now hang out until the user requests that we exit.
                // The rest of the call will be handled by the CallerJingleSession we created above.
          log( CALLER, "Waiting..." );
          while( running ) {
            synchronized ( this ) {
              try {
                wait(1000);
              } catch (InterruptedException e) {}
            }
          }
          connection.disconnect();
          log( CALLER, "Done. Exiting thread." );
        } catch ( Exception e ) {
          System.out.println( CALLER + ": " + e );
          e.printStackTrace();
          System.exit(1);
        }
      }
    };
    callThread.start();
  }
 
 
  private void log( String tag, String message ) {
    logger.info( "[{}]: {}", tag, message );
  }
}
TOP

Related Classes of com.xonami.javaBellsSample.JavaBellsSample

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.