Mercurial > hg > accesspd
view java/src/uk/ac/qmul/eecs/ccmi/network/OscProtocol.java @ 1:e3935c01cde2 tip
moved license of PdPersistenceManager to the beginning of the file
author | Fiore Martin <f.martin@qmul.ac.uk> |
---|---|
date | Tue, 08 Jul 2014 19:52:03 +0100 |
parents | 78b7fc5391a2 |
children |
line wrap: on
line source
/* CCmI Editor - A Collaborative Cross-Modal Diagram Editing Tool Copyright (C) 2011 Queen Mary University of London (http://ccmi.eecs.qmul.ac.uk/) This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program 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 General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses/>. */ package uk.ac.qmul.eecs.ccmi.network; import java.io.IOException; import java.net.SocketException; import java.nio.ByteBuffer; import java.nio.channels.SocketChannel; import java.util.ResourceBundle; import uk.ac.qmul.eecs.ccmi.gui.DiagramEventSource; import de.sciss.net.OSCBundle; import de.sciss.net.OSCMessage; /* * An implementation of the Protocol interface which uses OSC messages * streamed on a TCP connection. * */ class OscProtocol implements Protocol { OscProtocol(){ buffer = ByteBuffer.allocate(DEFAULT_CAPACITY); codec = new CCmIOSCPacketCodec(); } @Override public void send(SocketChannel channel, Command cmd) throws IOException { /* OSC message args = [diagram, cmd.arg1, cmd.arg2, amd.arg2, ... , cmd.argN ] */ bundle = new CCmIOSCBundle(cmd.getTimestamp()); Object[] args = new Object[2+cmd.getArgNum()]; args[0] = cmd.getDiagram(); args[1] = cmd.getSource().toString(); for(int i=0; i<cmd.getArgNum();i++) args[i+2] = cmd.getArgAt(i); bundle.addPacket(new OSCMessage(OSC_NAME_PREFIX+cmd.getName().toString(),args)); try{ writeBundle(channel); }catch(IOException u){ throw new IOException( /* give a more user friendly message */ ResourceBundle.getBundle(Server.class.getName()).getString("dialog.error.no_send"),u); } } @Override public void send(SocketChannel channel, Reply reply) throws IOException { /* OSC message args = [messageLen, diagram, message ] */ bundle = new CCmIOSCBundle(reply.getTimestamp()); bundle.addPacket(new OSCMessage( OSC_NAME_PREFIX+reply.getName().toString(), new Object[] {reply.getMessageLen(), reply.getDiagram() ,reply.getMessage(),reply.getSource().toString()} )); try{ writeBundle(channel); }catch(IOException u){ throw new IOException( /* give a more user friendly message */ ResourceBundle.getBundle(Server.class.getName()).getString("dialog.error.no_send"),u); } } @Override public void send(SocketChannel channel, LockMessage lockMessage) throws IOException { /* OSC message args = [diagram, source, lock.arg1, lock.arg2, lock.arg2, ... , lock.argN ] */ bundle = new CCmIOSCBundle(lockMessage.getTimestamp()); Object[] args = new Object[2+lockMessage.getArgNum()]; args[0] = lockMessage.getDiagram(); args[1] = lockMessage.getSource().toString(); for(int i=0; i<lockMessage.getArgNum();i++) args[i+2] = lockMessage.getArgAt(i); bundle.addPacket(new OSCMessage( OSC_NAME_PREFIX+lockMessage.getName().toString(), args)); try{ writeBundle(channel); }catch(IOException u){ throw new IOException( /* give a more user friendly message */ ResourceBundle.getBundle(Server.class.getName()).getString("dialog.error.no_send"),u); } } @Override public void send(SocketChannel channel, AwarenessMessage awareMsg) throws IOException { /* OSC message args = [diagram name, siagram event action source]*/ bundle = new CCmIOSCBundle(awareMsg.getTimestamp()); Object[] args = new Object[2]; args[0] = awareMsg.getDiagram(); args[1] = awareMsg.getSource().toString(); bundle.addPacket(new OSCMessage( OSC_NAME_PREFIX+awareMsg.getName().toString(), args)); try{ writeBundle(channel); }catch(IOException u){ throw new IOException( /* give a more user friendly message */ ResourceBundle.getBundle(Server.class.getName()).getString("dialog.error.no_send"),u); } } // @Override // public Command receiveCommand(SocketChannel channel) throws IOException { // OSCBundle bundle = readBundle(channel); // OSCMessage oscMessage = (OSCMessage)bundle.getPacket(0); // String name = oscMessage.getName(); // assert(name.startsWith(""+OSC_NAME_PREFIX)); // name = name.substring(1); // chop off the trailing '/' // Object args[] = new Object[oscMessage.getArgCount()-CMD_OFFSET]; // for(int i=0; i< args.length;i++) // args[i] = oscMessage.getArg(i+CMD_OFFSET); // return new Command( // Command.valueOf(name), // (String)oscMessage.getArg(CMD_DIAGRAM_INDEX), // args, // bundle.getTimeTag(), // DiagramEventSource.valueOf((String)oscMessage.getArg(CMD_SOURCE_INDEX)) // ); // } @Override public Reply receiveReply(SocketChannel channel) throws IOException { OSCBundle bundle = readBundle(channel); OSCMessage oscMessage = (OSCMessage)bundle.getPacket(0); String name = oscMessage.getName(); assert(name.startsWith(""+OSC_NAME_PREFIX)); name = name.substring(1); // chop off the trailing '/' @SuppressWarnings("unused") Integer len = (Integer)oscMessage.getArg(REPLY_LEN_INDEX); // of no use at the moment return new Reply( Reply.valueOf(name), (String)oscMessage.getArg(REPLY_DIAGRAM_INDEX), (String)oscMessage.getArg(REPLY_MESSAGE_INDEX), bundle.getTimeTag(), DiagramEventSource.valueOf((String)oscMessage.getArg(REPLY_SOURCE_INDEX))); } @Override public LockMessage receiveLockMessage(SocketChannel channel) throws IOException { OSCBundle bundle = readBundle(channel); OSCMessage oscMessage = (OSCMessage)bundle.getPacket(0); String name = oscMessage.getName(); name = name.substring(1); // chop off the trailing '/' Object args[] = new Object[oscMessage.getArgCount()-LOCK_OFFSET]; for(int i=0; i< args.length;i++) args[i] = oscMessage.getArg(i+LOCK_OFFSET); return new LockMessage( LockMessage.valueOf(name), bundle.getTimeTag(), (String)oscMessage.getArg(LOCK_DIAGRAM_INDEX), args, DiagramEventActionSource.valueOf((String)oscMessage.getArg(LOCK_SOURCE_INDEX)) ); } public Message receiveMessage(SocketChannel channel) throws IOException { OSCBundle bundle = readBundle(channel); OSCMessage oscMessage = (OSCMessage)bundle.getPacket(0); String name = oscMessage.getName(); assert(name.startsWith(""+OSC_NAME_PREFIX)); name = name.substring(1); // chop off the trailing '/' if(name.endsWith(Reply.NAME_POSTFIX)){ // it's a reply @SuppressWarnings("unused") Integer len = (Integer)oscMessage.getArg(REPLY_LEN_INDEX); // of no use at the moment Reply reply = new Reply( Reply.valueOf(name), (String)oscMessage.getArg(REPLY_DIAGRAM_INDEX), (String)oscMessage.getArg(REPLY_MESSAGE_INDEX), bundle.getTimeTag(), DiagramEventSource.valueOf((String)oscMessage.getArg(REPLY_SOURCE_INDEX))); return reply; }else if (name.endsWith(LockMessage.NAME_POSTFIX)){ Object args[] = new Object[oscMessage.getArgCount()-LOCK_OFFSET]; for(int i=0; i< args.length;i++) args[i] = oscMessage.getArg(i+LOCK_OFFSET); return new LockMessage( LockMessage.valueOf(name), bundle.getTimeTag(), (String)oscMessage.getArg(LOCK_DIAGRAM_INDEX), args, DiagramEventActionSource.valueOf((String)oscMessage.getArg(LOCK_SOURCE_INDEX)) ); }else if(name.endsWith(AwarenessMessage.NAME_POSTFIX)){ // it's an awareness message AwarenessMessage.Name awName = AwarenessMessage.valueOf(name); if(awName == AwarenessMessage.Name.USERNAME_A || awName == AwarenessMessage.Name.ERROR_A){ return new AwarenessMessage(awName, (String)oscMessage.getArg(AWAR_DIAGRAM_INDEX), (String)oscMessage.getArg(AWAR_SOURCE_INDEX) ); }else { return new AwarenessMessage(awName, (String)oscMessage.getArg(AWAR_DIAGRAM_INDEX), DiagramEventActionSource.valueOf((String)oscMessage.getArg(AWAR_SOURCE_INDEX)) ); } }else{ // it's a command Object args[] = new Object[oscMessage.getArgCount()-CMD_OFFSET]; for(int i=0; i< args.length;i++) args[i] = oscMessage.getArg(i+CMD_OFFSET); return new Command( Command.valueOf(name), (String)oscMessage.getArg(CMD_DIAGRAM_INDEX), args, bundle.getTimeTag(), DiagramEventSource.valueOf((String)oscMessage.getArg(CMD_SOURCE_INDEX)) ); } } private OSCBundle readBundle(SocketChannel channel) throws IOException{ /* read the size of the OSC packet, first 4 bytes according to OSC specs */ buffer.rewind().limit(4); while( buffer.hasRemaining() ) if( channel.read( buffer ) == -1 ) throw new SocketException(ResourceBundle.getBundle(Server.class.getName()).getString("error.connection_close")); buffer.rewind(); int packetSize = buffer.getInt(); assert(packetSize > 0 ); ByteBuffer b = buffer; /* if the packet is very big we must allocate an ad hoc temporary big big buffer */ if(packetSize <= DEFAULT_CAPACITY) b.rewind().limit(packetSize); else b = ByteBuffer.allocate(packetSize); /* read the packet, it must be a bundle containing only one message */ while( b.hasRemaining() ) if( channel.read( b ) == -1 ) throw new SocketException(ResourceBundle.getBundle(Server.class.getName()).getString("error.connection_close")); b.rewind(); return (OSCBundle)codec.decode(b); } private void writeBundle(SocketChannel channel) throws IOException{ ByteBuffer b = buffer; buffer.clear(); if(bundle.getSize() + 4 > DEFAULT_CAPACITY){ b = ByteBuffer.allocate(bundle.getSize() + 4); } b.position(4); bundle.encode(codec,b); int len = b.position() - 4; b.putInt(0, len); b.flip(); channel.write(b); } ByteBuffer buffer; CCmIOSCBundle bundle; CCmIOSCPacketCodec codec; private static final int DEFAULT_CAPACITY = 1024; private static final char OSC_NAME_PREFIX = '/'; private static final int REPLY_LEN_INDEX = 0; /* position of the diagram Name in the OSC message */ private static final int REPLY_DIAGRAM_INDEX = 1; private static final int REPLY_SOURCE_INDEX = 3; private static final int CMD_DIAGRAM_INDEX = 0; private static final int CMD_SOURCE_INDEX = 1; private static final int CMD_OFFSET = 2; private static final int LOCK_DIAGRAM_INDEX = 0; private static final int LOCK_SOURCE_INDEX = 1; private static final int LOCK_OFFSET = 2; private static final int AWAR_DIAGRAM_INDEX = 0; private static final int AWAR_SOURCE_INDEX = 1; /* ------------------------------------------------*/ private static final int REPLY_MESSAGE_INDEX = 2; }