root/as3/OSCemote/branches/saqoosha/server/flosc-0.3.1/OscServer.java

リビジョン 1048, 9.6 kB (コミッタ: uranodai, コミット時期: 4 年 前)

--

Line 
1 import java.awt.event.*;
2 import java.util.*;
3 import java.awt.*;
4 import java.io.*;
5 import java.net.*;
6
7 /**
8  *
9  * OscServer
10  * <BR><BR>
11  * OpenSoundControl UDP Server for Gateway.
12  *
13  * Based on CommServer by Derek Clayton and dumpOSC by Matt Wright.
14  *
15  * Thanks to Jesse Gilbert (j@resistantstrain.net) for helping me with
16  * the static socket.
17  *
18  * @author  Ben Chun        ben@benchun.net
19  * @version 1.0
20  */
21
22 public class OscServer extends Thread {
23     private DatagramSocket oscSocket;       // incoming UDP socket
24     private int port;                       // incoming UDP port
25     private Gateway gateway;                // Gateway for this server
26     private static OscSocket outSocket;     // outgoing UDP socket
27     static
28     {
29         try
30             {
31                 outSocket = new OscSocket();
32             }
33         catch( SocketException se )
34             {
35                 se.printStackTrace();
36             }
37     }
38    
39     /**
40      * Constructor for the OscServer.
41      *
42      * @param   port     UDP port for OSC communication.
43      * @param   gateway  parent Gateway.
44     */
45     public OscServer(int port, Gateway gateway) {
46         this.port = port;
47         this.gateway = gateway;
48         System.out.println("OscServer created...");
49     }
50
51     /**
52      * Thread run method.  Monitors incoming messages.
53     */ 
54     public void run() {
55         try{
56             // --- create a new UDP OSC socket
57             oscSocket = new DatagramSocket(port);
58             Debug.writeActivity("UDP OSC server started on port: " + port);
59             while(true) {
60                 byte[] datagram  = new byte[1024];
61                 DatagramPacket packet = new DatagramPacket(datagram, datagram.length);
62
63                 // block until a datagram is received
64                 oscSocket.receive(packet);
65
66                 // parse the packet
67                 Debug.writeActivity("Received UDP packet, parsing OSC...");
68                 OscPacket oscp = new OscPacket();
69                 oscp.address = packet.getAddress();
70                 oscp.port = packet.getPort();
71                 parseOscPacket(datagram, packet.getLength(), oscp);
72                
73                 // then send it as XML to all the flash clients
74                 gateway.broadcastMessage( oscp.getXml() );
75
76                 // DEBUG
77                 //System.out.println("** raw packet **");
78                 //OscPacket.printBytes( datagram );
79                 //System.out.println("** constructed packet **");
80                 //OscPacket.printBytes( oscp.getByteArray() );
81
82             }
83         } catch(IOException ioe) {
84             Debug.writeActivity("Server error...Stopping UDP OSC server");
85             // kill this server
86             killServer();
87         }
88     }
89
90     /**
91      * This method is based on dumpOSC::ParseOSCPacket.  It verifies
92      * that the packet is well-formed and puts the data into an
93      * OscPacket object, or else prints useful error messages about
94      * what went wrong.
95      *
96      * @param   datagram  a byte array containing the OSC packet
97      * @param   n         size of the byte array
98      * @param   packet    the OscPacket object to put data into
99      */
100     public void parseOscPacket(byte[] datagram, int n, OscPacket packet) {
101         int size, i;
102
103         if ( (n % 4) != 0 ) {
104             Debug.writeActivity("SynthControl packet size (" + n +
105                           ") not a multiple of 4 bytes, dropped it.");
106             return;
107         }
108
109         String dataString = new String(datagram);
110         if ( ( n >= 8 ) && dataString.startsWith( "#bundle" ) ) {
111             /* This is a bundle message. */
112            
113             if ( n < 16 ) {
114                 Debug.writeActivity("Bundle message too small (" + n +
115                               " bytes) for time tag, dropped it.");
116                 return;
117             }
118
119             /* Get the time tag */
120             Long time = new Long( Bytes.toLong( Bytes.copy(datagram, 8, 8) ) );
121             packet.setTime(time.longValue());
122
123             i = 16; /* Skip "#bundle\0" and time tags */
124             while( i<n ) {
125                 size = ( Bytes.toInt( Bytes.copy(datagram, i, i+4 ) ) );
126                 if ((size % 4) != 0) {
127                     Debug.writeActivity("Bad size count" + size +
128                                   "in bundle (not a multiple of 4)");
129                     return;
130                 }
131                 if ( (size + i + 4) > n ) {
132                     Debug.writeActivity("Bad size count" + size + "in bundle" +
133                                   "(only" + (n-i-4) + "bytes left in entire bundle)");
134                     return;
135                 }
136                
137                 /* Recursively handle element of bundle */
138                 byte[] remaining =  Bytes.copy(datagram, i+4);
139                 parseOscPacket(remaining, size, packet);
140                 i += (4 + size);
141             }
142         } else {
143             /* This is not a bundle message */     
144             Vector nameAndData = getStringAndData(datagram, n);
145
146             String name = (String) nameAndData.firstElement();
147             OscMessage message = new OscMessage(name);
148
149             byte[] data = (byte[]) nameAndData.lastElement();
150             Vector[] typesAndArgs = getTypesAndArgs(data);
151             message.setTypesAndArgs(typesAndArgs[0], typesAndArgs[1]);
152
153             packet.addMessage(message);
154         }
155     }
156
157     /**
158      * Takes a byte array starting with a string padded with null
159      * characters so that the length of the entire block is a multiple
160      * of 4, and seperates it into a String and a byte array of the
161      * remaining data.  These are then returned in a Vector.
162      *
163      * @param   block           block of data beginning with a string
164      * @param   stringLength    number of characters in the string
165     */ 
166     public Vector getStringAndData(byte[] block, int stringLength) {
167         Vector v = new Vector();
168         int i;
169        
170         if ( stringLength %4 != 0) {
171             Debug.writeActivity("printNameAndArgs: bad boundary");
172             return v;
173         }
174
175         for (i = 0; block[i] != '\0'; i++) {
176             if (i >= stringLength) {
177                 Debug.writeActivity("printNameAndArgs: Unreasonably long string");
178                 return v;
179             }
180         }
181         // v.firstElement() is the String
182         v.addElement( new String(Bytes.copy(block, 0, i)) );
183
184         i++;
185         for (; (i % 4) != 0; i++) {
186             if (i >= stringLength) {
187                 Debug.writeActivity("printNameAndArgs: Unreasonably long string");
188                 return v;
189             }
190             if (block[i] != '\0') {
191                 Debug.writeActivity("printNameAndArgs: Incorrectly padded string.");
192                 return v;
193             }
194         }
195         // v.elementAt(1) is the position in the orginal byte[] where the data starts
196         v.addElement( new Integer(i) );
197         // v.lastElement() is the byte[] of data
198         v.addElement( Bytes.copy( block, i ) );
199         return v;
200     }
201
202     /**
203      * Returns an array of Vectors containing types and arguments.
204      *
205      * @param   block   byte array containing types and arguments
206     */
207     public Vector[] getTypesAndArgs( byte[] block ) {
208         // TBD : throw exceptions or something when there are no type tags
209         int n = block.length;
210         Vector[] va = new Vector[2];
211         if (n != 0) {
212             if (block[0] == ',') {
213                 if (block[1] != ',') {
214                     /* This message begins with a type-tag string */
215                     va = getTypeTaggedArgs( block );
216                 } else {
217                     /* Double comma means an escaped real comma, not a
218                      * type string */
219                     va = getHeuristicallyTypeGuessedArgs( block );
220                 }
221             } else {
222                 va = getHeuristicallyTypeGuessedArgs( block );
223             }
224         }
225         return va;
226     }
227
228     /**
229      * Returns Vectors containing the types and arguments from a
230      * type-tagged byte array
231      *
232      * @param   block   a byte array with type-tagged data
233     */
234     public Vector[] getTypeTaggedArgs( byte[] block ) {
235         Vector typeVector = new Vector();
236         Vector argVector = new Vector();
237         int p = 0;
238
239         /* seperate the block into the types byte array and the
240          * argument byte array*/
241         Vector typesAndArgs = getStringAndData(block, block.length);
242         byte[] args = (byte[]) typesAndArgs.lastElement();
243        
244         for (int thisType=1; block[thisType] != 0; thisType++) {
245             switch (block[thisType]) {
246
247             case '[' :
248                 typeVector.addElement(new Character('['));
249                 break;
250
251             case ']' :
252                 typeVector.addElement(new Character(']'));
253                 break;
254
255             case 'i': case 'r': case 'm': case 'c':
256                 typeVector.addElement(new Character('i'));
257                 argVector.addElement( new Integer( Bytes.toInt( Bytes.copy(args, p, p+4) )) );
258                 p += 4;
259                 break;
260                
261             case 'f':
262                 typeVector.addElement(new Character('f'));
263                 argVector.addElement( new Float( Bytes.toFloat( Bytes.copy(args, p, p+4) )) );
264                 p += 4;
265                 break;
266                
267             case 'h': case 't':
268                 typeVector.addElement(new Character('h'));
269                 argVector.addElement( new Long( Bytes.toLong( Bytes.copy(args, p, p+8) )) );
270                 p += 8;
271                 break;
272                
273             case 'd':
274                 typeVector.addElement(new Character('d'));
275                 argVector.addElement( new Double( Bytes.toDouble( Bytes.copy(args, p, p+8) )) );
276                 p += 8;
277                 break;
278                
279             case 's': case 'S':
280                 typeVector.addElement(new Character('s'));
281                 byte[] remaining = Bytes.copy(args, p);
282                 Vector v = getStringAndData( remaining, remaining.length );
283                 argVector.addElement( (String)v.firstElement() );
284                 p += ((Integer)v.elementAt(1)).intValue();
285                 break;
286                
287             case 'T':
288                 typeVector.addElement(new Character('T'));
289                 break;
290             case 'F':
291                 typeVector.addElement(new Character('F'));
292                 break;
293             case 'N':
294                 typeVector.addElement(new Character('N'));
295                 break;
296             case 'I':
297                 typeVector.addElement(new Character('I'));
298                 break;
299
300             default:
301                 Debug.writeActivity( "[Unrecognized type tag " +
302                                block[thisType] + "]" );
303             }
304         }
305
306         Vector[] returnValue = new Vector[2];
307         returnValue[0] = typeVector;
308         returnValue[1] = argVector;
309         return returnValue;
310     }
311        
312
313     /**
314      * Returns the arguments from a non-type-tagged byte array
315      *
316      * @param   block   a byte array containing data
317     */
318     public Vector[] getHeuristicallyTypeGuessedArgs( byte[] block ) {
319         // TBD : handle packets without type tags
320         Debug.writeActivity("Bad OSC packet: No type tags");
321         return new Vector[2];
322     }
323
324
325    /**
326      * Sends an OscPacket via an OscSocket.  the packet contains the
327      * address and port information.
328      *
329      * @param packet  the OscPacket to send
330      */
331     public void sendPacket(OscPacket packet) {
332
333         try {
334             Debug.writeActivity("OscServer sending UDP packet...");
335             outSocket.send(packet);
336         } catch(IOException ioe) {
337             Debug.writeActivity("sendPacket error...Stopping UDP OSC server");
338             // kill this server
339             killServer();
340         }
341     }
342
343
344     /**
345      * Stops the UDP server.
346     */
347     public void killServer() {
348         // --- close the socket
349         oscSocket.close();
350         Debug.writeActivity("UDP OSC server stopped");
351     }
352 }
Note: リポジトリブラウザについてのヘルプは TracBrowser を参照してください。