001/** 002 * 003 * Copyright 2003-2006 Jive Software. 004 * 005 * Licensed under the Apache License, Version 2.0 (the "License"); 006 * you may not use this file except in compliance with the License. 007 * You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the License for the specific language governing permissions and 015 * limitations under the License. 016 */ 017package org.jivesoftware.smackx.jingle.mediaimpl.sshare; 018 019import java.awt.Rectangle; 020import java.awt.event.WindowAdapter; 021import java.awt.event.WindowEvent; 022import java.io.IOException; 023import java.net.DatagramSocket; 024import java.net.InetAddress; 025import java.net.ServerSocket; 026import java.net.UnknownHostException; 027import java.util.logging.Logger; 028 029import javax.swing.JFrame; 030import javax.swing.JPanel; 031 032import org.jivesoftware.smackx.jingle.JingleSession; 033import org.jivesoftware.smackx.jingle.media.JingleMediaSession; 034import org.jivesoftware.smackx.jingle.media.PayloadType; 035import org.jivesoftware.smackx.jingle.mediaimpl.sshare.api.ImageDecoder; 036import org.jivesoftware.smackx.jingle.mediaimpl.sshare.api.ImageEncoder; 037import org.jivesoftware.smackx.jingle.mediaimpl.sshare.api.ImageReceiver; 038import org.jivesoftware.smackx.jingle.mediaimpl.sshare.api.ImageTransmitter; 039import org.jivesoftware.smackx.jingle.nat.TransportCandidate; 040 041/** 042 * This Class implements a complete JingleMediaSession. 043 * It sould be used to transmit and receive captured images from the Display. 044 * This Class should be automaticly controlled by JingleSession. 045 * For better NAT Traversal support this implementation don't support only receive or only transmit. 046 * To receive you MUST transmit. So the only implemented and functionally methods are startTransmit() and stopTransmit() 047 * 048 * @author Thiago Camargo 049 */ 050public class ScreenShareSession extends JingleMediaSession { 051 052 private static final Logger LOGGER = Logger.getLogger(ScreenShareSession.class.getName()); 053 054 private ImageTransmitter transmitter = null; 055 private ImageReceiver receiver = null; 056 private int width = 600; 057 private int height = 600; 058 059 /** 060 * Creates a org.jivesoftware.jingleaudio.jmf.AudioMediaSession with defined payload type, remote and local candidates 061 * 062 * @param payloadType Payload of the jmf 063 * @param remote the remote information. The candidate that the jmf will be sent to. 064 * @param local the local information. The candidate that will receive the jmf 065 * @param locator media locator 066 */ 067 public ScreenShareSession(final PayloadType payloadType, final TransportCandidate remote, final TransportCandidate local, 068 final String locator, JingleSession jingleSession) { 069 super(payloadType, remote, local, "Screen", jingleSession); 070 initialize(); 071 } 072 073 /** 074 * Initialize the screen share channels. 075 */ 076 public void initialize() { 077 078 JingleSession session = getJingleSession(); 079 if ((session != null) && (session.getInitiator().equals(session.getConnection().getUser()))) { 080 // If the initiator of the jingle session is us then we transmit a screen share. 081 try { 082 InetAddress remote = InetAddress.getByName(getRemote().getIp()); 083 transmitter = new ImageTransmitter(new DatagramSocket(getLocal().getPort()), remote, getRemote().getPort(), 084 new Rectangle(0, 0, width, height)); 085 } catch (Exception e) { 086 e.printStackTrace(); 087 } 088 089 } else { 090 // Otherwise we receive a screen share. 091 JFrame window = new JFrame(); 092 JPanel jp = new JPanel(); 093 window.add(jp); 094 095 window.setLocation(0, 0); 096 window.setSize(600, 600); 097 098 window.addWindowListener(new WindowAdapter() { 099 public void windowClosed(WindowEvent e) { 100 receiver.stop(); 101 } 102 }); 103 104 try { 105 receiver = new ImageReceiver(InetAddress.getByName("0.0.0.0"), getRemote().getPort(), getLocal().getPort(), width, 106 height); 107 LOGGER.fine("Receiving on:" + receiver.getLocalPort()); 108 } catch (UnknownHostException e) { 109 e.printStackTrace(); 110 } 111 112 jp.add(receiver); 113 receiver.setVisible(true); 114 window.setAlwaysOnTop(true); 115 window.setVisible(true); 116 } 117 } 118 119 /** 120 * Starts transmission and for NAT Traversal reasons start receiving also. 121 */ 122 public void startTrasmit() { 123 new Thread(transmitter).start(); 124 } 125 126 /** 127 * Set transmit activity. If the active is true, the instance should trasmit. 128 * If it is set to false, the instance should pause transmit. 129 * 130 * @param active active state 131 */ 132 public void setTrasmit(boolean active) { 133 transmitter.setTransmit(true); 134 } 135 136 /** 137 * For NAT Reasons this method does nothing. Use startTransmit() to start transmit and receive jmf 138 */ 139 public void startReceive() { 140 // Do nothing 141 } 142 143 /** 144 * Stops transmission and for NAT Traversal reasons stop receiving also. 145 */ 146 public void stopTrasmit() { 147 if (transmitter != null) { 148 transmitter.stop(); 149 } 150 } 151 152 /** 153 * For NAT Reasons this method does nothing. Use startTransmit() to start transmit and receive jmf 154 */ 155 public void stopReceive() { 156 if (receiver != null) { 157 receiver.stop(); 158 } 159 } 160 161 /** 162 * Obtain a free port we can use. 163 * 164 * @return A free port number. 165 */ 166 protected int getFreePort() { 167 ServerSocket ss; 168 int freePort = 0; 169 170 for (int i = 0; i < 10; i++) { 171 freePort = (int) (10000 + Math.round(Math.random() * 10000)); 172 freePort = freePort % 2 == 0 ? freePort : freePort + 1; 173 try { 174 ss = new ServerSocket(freePort); 175 freePort = ss.getLocalPort(); 176 ss.close(); 177 return freePort; 178 } catch (IOException e) { 179 e.printStackTrace(); 180 } 181 } 182 try { 183 ss = new ServerSocket(0); 184 freePort = ss.getLocalPort(); 185 ss.close(); 186 } catch (IOException e) { 187 e.printStackTrace(); 188 } 189 return freePort; 190 } 191 192 public void setEncoder(ImageEncoder encoder) { 193 if (encoder != null) { 194 this.transmitter.setEncoder(encoder); 195 } 196 } 197 198 public void setDecoder(ImageDecoder decoder) { 199 if (decoder != null) { 200 this.receiver.setDecoder(decoder); 201 } 202 } 203}