/*
* OSCTransmitter.java
* de.sciss.net (NetUtil)
*
* Copyright (c) 2004-2009 Hanns Holger Rutz. All rights reserved.
*
* 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
*
*
* For further information, please contact Hanns Holger Rutz at
* contact@sciss.de
*
*
* Changelog:
* 26-Aug-05 created
* 30-Sep-06 made abstract (unfortunately not backward compatible), finished TCP support
* 02-Jul-07 uses OSCPacketCodec, bugfix in newUsing( String, int )
*/
package de.sciss.net;
import java.io.IOException;
import java.io.PrintStream;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.Socket;
import java.net.SocketAddress;
import java.net.UnknownHostException;
import java.nio.BufferOverflowException;
import java.nio.ByteBuffer;
import java.nio.channels.DatagramChannel;
import java.nio.channels.SelectableChannel;
import java.nio.channels.SocketChannel;
/**
* A class that sends OSC packets (messages
* or bundles) to a target OSC server. Each instance takes
* a network channel, either explictly specified by a
* <code>DatagramChannel</code> (for UDP) or <code>SocketChannel</code> (for TCP),
* or internally opened when a protocol type is specified.
* <P>
* Messages are send by invoking one
* of the <code>send</code> methods. For an example,
* please refer to the <code>OSCReceiver</code> document.
* <P>
* <B>Note that as of v0.3,</B> you will most likely want to use preferably one of <code>OSCClient</code> or <code>OSCServer</code>
* over <code>OSCTransmitter</code>. Also note that as of v0.3, <code>OSCTransmitter</code> is abstract, which
* renders direct instantiation impossible. <B>To update old code,</B> occurences of <code>new OSCTransmitter()</code>
* must be replaced by one of the <code>OSCTransmitter.newUsing</code> methods!
*
* @author Hanns Holger Rutz
* @version 0.33, 05-Mar-09
*
* @see OSCClient
* @see OSCServer
* @see OSCReceiver
*
* @synchronization sending messages is thread safe
* @todo an explicit disconnect method might be useful
* (this is implicitly done when calling dispose)
*/
public abstract class OSCTransmitter
implements OSCChannel
{
protected final Object sync = new Object(); // buffer (re)allocation
protected boolean allocBuf = true;
private int bufSize = DEFAULTBUFSIZE;
protected ByteBuffer byteBuf = null;
protected int dumpMode = kDumpOff;
protected PrintStream printStream = null;
private OSCPacketCodec c;
private final String protocol;
protected SocketAddress target = null;
protected final InetSocketAddress localAddress;
protected final boolean revivable;
protected OSCTransmitter( OSCPacketCodec c, String protocol, InetSocketAddress localAddress, boolean revivable )
{
this.c = c;
this.protocol = protocol;
this.localAddress = localAddress;
this.revivable = revivable;
}
/**
* Creates a new instance of an <code>OSCTransmitter</code>, using
* default codec and a specific transport protocol. It picks an arbitrary free port
* and uses the local machine's IP. To determine the resulting
* port, you can use <code>getLocalAddress</code> afterwards.
*
* @param protocol the protocol to use, currently either <code>UDP</code> or <code>TCP</code>
* @return the newly created transmitter
*
* @throws IOException if a networking error occurs while creating the socket
* @throws IllegalArgumentException if an illegal protocol is used
*
* @see OSCChannel#UDP
* @see OSCChannel#TCP
* @see #getLocalAddress
*/
public static OSCTransmitter newUsing( String protocol )
throws IOException
{
return newUsing( OSCPacketCodec.getDefaultCodec(), protocol );
}
/**
* Creates a new instance of an <code>OSCTransmitter</code>, using
* a specific codec and transport protocol. It picks an arbitrary free port
* and uses the local machine's IP. To determine the resulting
* port, you can use <code>getLocalAddress</code> afterwards.
*
* @param c the codec to use
* @param protocol the protocol to use, currently either <code>UDP</code> or <code>TCP</code>
* @return the newly created transmitter
*
* @throws IOException if a networking error occurs while creating the socket
* @throws IllegalArgumentException if an illegal protocol is used
*
* @see OSCChannel#UDP
* @see OSCChannel#TCP
* @see #getLocalAddress
*
* @since NetUtil 0.33
*/
public static OSCTransmitter newUsing( OSCPacketCodec c, String protocol )
throws IOException
{
return newUsing( c, protocol, 0 );
}
/**
* Creates a new instance of an <code>OSCTransmitter</code>, using
* default codec and a specific transport protocol and port. It
* uses the local machine's IP. Note that the <code>port</code> specifies the
* local socket, not the remote (or target) port. This can be set
* using the <code>setTarget</code> method!
*
* @param protocol the protocol to use, currently either <code>UDP</code> or <code>TCP</code>
* @param port the port number for the OSC socket, or <code>0</code> to use an arbitrary free port
* @return the newly created transmitter
*
* @throws IOException if a networking error occurs while creating the socket
* @throws IllegalArgumentException if an illegal protocol is used
*/
public static OSCTransmitter newUsing( String protocol, int port )
throws IOException
{
return newUsing( OSCPacketCodec.getDefaultCodec(), protocol, port );
}
/**
* Creates a new instance of an <code>OSCTransmitter</code>, using
* a specific codec and transport protocol and port. It
* uses the local machine's IP. Note that the <code>port</code> specifies the
* local socket, not the remote (or target) port. This can be set
* using the <code>setTarget</code> method!
*
* @param c the codec to use
* @param protocol the protocol to use, currently either <code>UDP</code> or <code>TCP</code>
* @param port the port number for the OSC socket, or <code>0</code> to use an arbitrary free port
* @return the newly created transmitter
*
* @throws IOException if a networking error occurs while creating the socket
* @throws IllegalArgumentException if an illegal protocol is used
*
* @since NetUtil 0.33
*/
public static OSCTransmitter newUsing( OSCPacketCodec c, String protocol, int port )
throws IOException
{
return newUsing( c, protocol, port, false );
}
/**
* Creates a new instance of an <code>OSCTransmitter</code>, using
* default codec and a specific transport protocol and port. It
* uses the local machine's IP or the "loopback" address.
* Note that the <code>port</code> specifies the
* local socket, not the remote (or target) port. This can be set
* using the <code>setTarget</code> method!
*
* @param protocol the protocol to use, currently either <code>UDP</code> or <code>TCP</code>
* @param port the port number for the OSC socket, or <code>0</code> to use an arbitrary free port
* @param loopBack if <code>true</code>, the "loopback" address (<code>"127.0.0.1"</code>)
* is used which limits communication to the local machine. If <code>false</code>, the
* special IP <code>"0.0.0.0"</code> is used which means any local host is picked
*
* @return the newly created transmitter
*
* @throws IOException if a networking error occurs while creating the socket
* @throws IllegalArgumentException if an illegal protocol is used
*/
public static OSCTransmitter newUsing( String protocol, int port, boolean loopBack )
throws IOException
{
return newUsing( OSCPacketCodec.getDefaultCodec(), protocol, port, loopBack );
}
/**
* Creates a new instance of an <code>OSCTransmitter</code>, using
* a specific codec and transport protocol and port. It
* uses the local machine's IP or the "loopback" address.
* Note that the <code>port</code> specifies the
* local socket, not the remote (or target) port. This can be set
* using the <code>setTarget</code> method!
*
* @param c the codec to use
* @param protocol the protocol to use, currently either <code>UDP</code> or <code>TCP</code>
* @param port the port number for the OSC socket, or <code>0</code> to use an arbitrary free port
* @param loopBack if <code>true</code>, the "loopback" address (<code>"127.0.0.1"</code>)
* is used which limits communication to the local machine. If <code>false</code>, the
* special IP <code>"0.0.0.0"</code> is used which means any local host is picked
*
* @return the newly created transmitter
*
* @throws IOException if a networking error occurs while creating the socket
* @throws IllegalArgumentException if an illegal protocol is used
*
* @since NetUtil 0.33
*/
public static OSCTransmitter newUsing( OSCPacketCodec c, String protocol, int port, boolean loopBack )
throws IOException
{
// final InetSocketAddress localAddress = loopBack ? new InetSocketAddress( "127.0.0.1", port ) :
// new InetSocketAddress( InetAddress.getLocalHost(), port );
final InetSocketAddress localAddress = new InetSocketAddress( loopBack ? "127.0.0.1" : "0.0.0.0", port );
return newUsing( c, protocol, localAddress );
}
/**
* Creates a new instance of an <code>OSCTransmitter</code>, using
* default codec and a specific transport protocol and local socket address.
* Note that <code>localAddress</code> specifies the
* local socket, not the remote (or target) socket. This can be set
* using the <code>setTarget</code> method!
*
* @param protocol the protocol to use, currently either <code>UDP</code> or <code>TCP</code>
* @param localAddress a valid address to use for the OSC socket. If the port is <code>0</code>,
* an arbitrary free port is picked when the transmitter is connected. (you can find out
* the actual port in this case by calling <code>getLocalAddress()</code> after the
* transmitter was connected).
*
* @return the newly created transmitter
*
* @throws IOException if a networking error occurs while creating the socket
* @throws IllegalArgumentException if an illegal protocol is used
*/
public static OSCTransmitter newUsing( String protocol, InetSocketAddress localAddress )
throws IOException
{
return newUsing( OSCPacketCodec.getDefaultCodec(), protocol, localAddress );
}
/**
* Creates a new instance of an <code>OSCTransmitter</code>, using
* a specific codec and transport protocol and local socket address.
* Note that <code>localAddress</code> specifies the
* local socket, not the remote (or target) socket. This can be set
* using the <code>setTarget</code> method!
*
* @param c the codec to use
* @param protocol the protocol to use, currently either <code>UDP</code> or <code>TCP</code>
* @param localAddress a valid address to use for the OSC socket. If the port is <code>0</code>,
* an arbitrary free port is picked when the transmitter is connected. (you can find out
* the actual port in this case by calling <code>getLocalAddress()</code> after the
* transmitter was connected).
*
* @return the newly created transmitter
*
* @throws IOException if a networking error occurs while creating the socket
* @throws IllegalArgumentException if an illegal protocol is used
*
* @since NetUtil 0.33
*/
public static OSCTransmitter newUsing( OSCPacketCodec c, String protocol, InetSocketAddress localAddress )
throws IOException
{
if( protocol.equals( UDP )) {
return new UDPOSCTransmitter( c, localAddress );
} else if( protocol.equals( TCP )) {
return new TCPOSCTransmitter( c, localAddress );
} else {
throw new IllegalArgumentException( NetUtil.getResourceString( "errUnknownProtocol" ) + protocol );
}
}
/**
* Creates a new instance of an <code>OSCTransmitter</code>, using
* default codec and UDP transport on a given channel. The caller should ensure that
* the provided channel's socket was bound to a valid address
* (using <code>dch.socket().bind( SocketAddress )</code>).
* Note that <code>dch</code> specifies the
* local socket, not the remote (or target) socket. This can be set
* using the <code>setTarget</code> method!
*
* @param dch the <code>DatagramChannel</code> to use as UDP socket.
* @return the newly created transmitter
*
* @throws IOException if a networking error occurs while configuring the socket
*/
public static OSCTransmitter newUsing( DatagramChannel dch )
throws IOException
{
return newUsing( OSCPacketCodec.getDefaultCodec(), dch );
}
/**
* Creates a new instance of an <code>OSCTransmitter</code>, using
* a specific codec and UDP transport on a given channel. The caller should ensure that
* the provided channel's socket was bound to a valid address
* (using <code>dch.socket().bind( SocketAddress )</code>).
* Note that <code>dch</code> specifies the
* local socket, not the remote (or target) socket. This can be set
* using the <code>setTarget</code> method!
*
* @param c the codec to use
* @param dch the <code>DatagramChannel</code> to use as UDP socket.
* @return the newly created transmitter
*
* @throws IOException if a networking error occurs while configuring the socket
*
* @since NetUtil 0.33
*/
public static OSCTransmitter newUsing( OSCPacketCodec c, DatagramChannel dch )
throws IOException
{
return new UDPOSCTransmitter( c, dch );
}
/**
* Creates a new instance of an <code>OSCTransmitter</code>, using
* default codec and TCP transport on a given channel. The caller should ensure that
* the provided channel's socket was bound to a valid address
* (using <code>sch.socket().bind( SocketAddress )</code>). Furthermore,
* the channel must be connected (using <code>connect()</code>) before
* being able to transmit messages.
* Note that <code>sch</code> specifies the
* local socket, not the remote (or target) socket. This can be set
* using the <code>setTarget</code> method!
*
* @param sch the <code>SocketChannel</code> to use as TCP socket.
* @return the newly created transmitter
*
* @throws IOException if a networking error occurs while configuring the socket
*/
public static OSCTransmitter newUsing( SocketChannel sch )
throws IOException
{
return newUsing( OSCPacketCodec.getDefaultCodec(), sch );
}
/**
* Creates a new instance of an <code>OSCTransmitter</code>, using
* a specific codec and TCP transport on a given channel. The caller should ensure that
* the provided channel's socket was bound to a valid address
* (using <code>sch.socket().bind( SocketAddress )</code>). Furthermore,
* the channel must be connected (using <code>connect()</code>) before
* being able to transmit messages.
* Note that <code>sch</code> specifies the
* local socket, not the remote (or target) socket. This can be set
* using the <code>setTarget</code> method!
*
* @param c the codec to use
* @param sch the <code>SocketChannel</code> to use as TCP socket.
* @return the newly created transmitter
*
* @throws IOException if a networking error occurs while configuring the socket
*
* @since NetUtil 0.33
*/
public static OSCTransmitter newUsing( OSCPacketCodec c, SocketChannel sch )
throws IOException
{
return new TCPOSCTransmitter( c, sch );
}
public String getProtocol()
{
return protocol;
}
/**
* Queries the transmitter's local socket address.
* You can determine the host and port from the returned address
* by calling <code>getHostName()</code> (or for the IP <code>getAddress().getHostAddress()</code>)
* and <code>getPort()</code>. This port number may be <code>0</code>
* if the transmitter was called with an unspecified port and has not yet been
* connected. In this case, to determine the port actually used, call this
* method after the transmitter has been connected.
*
* @return the address of the transmitter's local socket.
* @throws IOException if the local host could not be resolved
*
* @see java.net.InetSocketAddress#getHostName()
* @see java.net.InetSocketAddress#getAddress()
* @see java.net.InetSocketAddress#getPort()
*/
public abstract InetSocketAddress getLocalAddress() throws IOException;
/**
* Specifies the transmitter's target address, that is the address of the remote side to talk to.
* You should call this method only once and you must call it before starting to
* send messages using the shortcut call <code>send( OSCPacket )</code>.
*
* @param target the address of the remote target socket. Usually you construct an appropriate <code>InetSocketAddress</code>
*
* @see InetSocketAddress
*/
public void setTarget( SocketAddress target )
{
this.target = target;
}
public void setCodec( OSCPacketCodec c )
{
this.c = c;
}
public OSCPacketCodec getCodec()
{
return c;
}
/**
* Establishes connection for transports requiring
* connectivity (e.g. TCP). For transports that do not require connectivity (e.g. UDP),
* this ensures the communication channel is created and bound.
* <P>
* When a <B>UDP</B> transmitter
* is created without an explicit <code>DatagramChannel</code> – say by
* calling <code>OSCTransmitter.newUsing( "udp" )</code>, you are required
* to call <code>connect()</code> so that an actual <code>DatagramChannel</code> is
* created and bound. For a <B>UDP</B> transmitter which was created with an explicit
* <code>DatagramChannel</code>, this method does noting, so it is always safe
* to call <code>connect()</code>. However, for <B>TCP</B> transmitters,
* this may throw an <code>IOException</code> if the transmitter
* was already connected, therefore be sure to check <code>isConnected()</code> before.
*
* @throws IOException if a networking error occurs. Possible reasons: - the underlying
* network channel had been closed by the server. - the transport
* is TCP and the server is not available. - the transport is TCP
* and an <code>OSCReceiver</code> sharing the same socket was stopped before (unable to revive).
*
* @see #isConnected()
*/
public abstract void connect() throws IOException;
protected InetSocketAddress getLocalAddress( InetAddress addr, int port )
throws UnknownHostException
{
return new InetSocketAddress( addr.getHostName().equals( "0.0.0.0" ) ? InetAddress.getLocalHost() : addr, port );
}
/**
* Queries the connection state of the transmitter.
*
* @return <code>true</code> if the transmitter is connected, <code>false</code> otherwise. For transports that do not use
* connectivity (e.g. UDP) this returns <code>false</code>, if the
* underlying <code>DatagramChannel</code> has not yet been created.
*
* @see #connect()
*/
public abstract boolean isConnected();
/**
* Sends an OSC packet (bundle or message) to the given
* network address, using the current codec.
*
* @param p the packet to send
* @param target the target address to send the packet to
*
* @throws IOException if a write error, OSC encoding error,
* buffer overflow error or network error occurs
*/
public final void send( OSCPacket p, SocketAddress target )
throws IOException
{
send( c, p, target );
}
/**
* Sends an OSC packet (bundle or message) to the given
* network address, using a particular codec.
*
* @param c the codec to use
* @param p the packet to send
* @param target the target address to send the packet to
*
* @throws IOException if a write error, OSC encoding error,
* buffer overflow error or network error occurs
*
* @since NetUtil 0.33
*/
public abstract void send( OSCPacketCodec c, OSCPacket p, SocketAddress target ) throws IOException;
/**
* Sends an OSC packet (bundle or message) to the default
* network address, using the current codec. The default address is the one specified
* using the <code>setTarget</code> method. Therefore
* this will throw a <code>NullPointerException</code> if
* no default address was specified.
*
* @param p the packet to send
*
* @throws IOException if a write error, OSC encoding error,
* buffer overflow error or network error occurs
* @throws NullPointerException if no default address was specified
*
* @see #setTarget( SocketAddress )
*/
public final void send( OSCPacket p )
throws IOException
{
send( p, target );
}
/**
* Sends an OSC packet (bundle or message) to the default
* network address, using a particular codec. The default address is the one specified
* using the <code>setTarget</code> method. Therefore
* this will throw a <code>NullPointerException</code> if
* no default address was specified.
*
* @param c the codec to use
* @param p the packet to send
*
* @throws IOException if a write error, OSC encoding error,
* buffer overflow error or network error occurs
* @throws NullPointerException if no default address was specified
*
* @see #setTarget( SocketAddress )
*
* @since NetUtil 0.33
*/
public abstract void send( OSCPacketCodec c, OSCPacket p ) throws IOException;
public void setBufferSize( int size )
{
synchronized( sync ) {
if( bufSize != size ) {
bufSize = size;
allocBuf = true;
}
}
}
public int getBufferSize()
{
synchronized( sync ) {
return bufSize;
}
}
public void dumpOSC( int mode, PrintStream stream )
{
this.dumpMode = mode;
this.printStream = stream == null ? System.err : stream;
}
public void dispose()
{
byteBuf = null;
}
// @synchronization caller must ensure synchronization
protected void checkBuffer()
{
if( allocBuf ) {
byteBuf = ByteBuffer.allocateDirect( bufSize );
allocBuf = false;
}
}
protected abstract SelectableChannel getChannel();
// protected abstract void setChannel( SelectableChannel ch );
// --------------------- internal classes ---------------------
private static class UDPOSCTransmitter
extends OSCTransmitter
{
private DatagramChannel dch;
protected UDPOSCTransmitter( OSCPacketCodec c, InetSocketAddress localAddress )
{
super( c, UDP, localAddress, true );
}
protected UDPOSCTransmitter( OSCPacketCodec c, DatagramChannel dch )
{
super( c, UDP, new InetSocketAddress( dch.socket().getLocalAddress(), dch.socket().getLocalPort() ), false );
this.dch = dch;
}
// protected void setChannel( SelectableChannel ch )
// {
// dch = (DatagramChannel) ch;
// }
protected SelectableChannel getChannel()
{
synchronized( sync ) {
return dch;
}
}
public InetSocketAddress getLocalAddress()
throws UnknownHostException
{
synchronized( sync ) {
if( dch != null ) {
final DatagramSocket ds = dch.socket();
return new InetSocketAddress( ds.getLocalAddress(), ds.getLocalPort() );
} else {
return getLocalAddress( localAddress.getAddress(), localAddress.getPort() );
}
}
}
public void connect()
throws IOException
{
synchronized( sync ) {
if( (dch != null) && !dch.isOpen() ) {
if( !revivable ) throw new IOException( NetUtil.getResourceString( "errCannotRevive" ));
dch = null;
}
if( dch == null ) {
final DatagramChannel newCh = DatagramChannel.open();
newCh.socket().bind( localAddress );
dch = newCh;
}
}
}
public boolean isConnected()
{
synchronized( sync ) {
return( (dch != null) && dch.isOpen() );
}
}
public void dispose()
{
super.dispose();
if( dch != null ) {
try {
dch.close();
}
catch( IOException e1 ) { /* ignored */ }
dch = null;
}
}
public void send( OSCPacketCodec c, OSCPacket p )
throws IOException
{
send( c, p, target );
}
public void send( OSCPacketCodec c, OSCPacket p, SocketAddress target )
throws IOException
{
try {
synchronized( sync ) {
// if( dch == null ) throw new NotYetConnectedException();
if( dch == null ) throw new IOException( NetUtil.getResourceString( "errChannelNotConnected" ));
checkBuffer();
byteBuf.clear();
c.encode( p, byteBuf );
byteBuf.flip();
if( dumpMode != kDumpOff ) {
printStream.print( "s: " );
if( (dumpMode & kDumpText) != 0 ) OSCPacket.printTextOn( printStream, p );
if( (dumpMode & kDumpHex) != 0 ) {
OSCPacket.printHexOn( printStream, byteBuf );
byteBuf.flip();
}
}
dch.send( byteBuf, target );
}
}
catch( BufferOverflowException e1 ) {
throw new OSCException( OSCException.BUFFER,
p instanceof OSCMessage ? ((OSCMessage) p).getName() : p.getClass().getName() );
}
}
}
private static class TCPOSCTransmitter
extends OSCTransmitter
{
private SocketChannel sch;
protected TCPOSCTransmitter( OSCPacketCodec c, InetSocketAddress localAddress )
{
super( c, TCP, localAddress, true );
}
protected TCPOSCTransmitter( OSCPacketCodec c, SocketChannel sch )
{
super( c, TCP, new InetSocketAddress( sch.socket().getLocalAddress(), sch.socket().getLocalPort() ), false );
this.sch = sch;
if( sch.isConnected() ) setTarget( sch.socket().getRemoteSocketAddress() );
}
public InetSocketAddress getLocalAddress()
throws UnknownHostException
{
synchronized( sync ) {
if( sch != null ) {
final Socket s = sch.socket();
return new InetSocketAddress( s.getLocalAddress(), s.getLocalPort() );
} else {
return getLocalAddress( localAddress.getAddress(), localAddress.getPort() );
}
}
}
// protected void setChannel( SelectableChannel ch )
// {
// sch = (SocketChannel) ch;
// }
protected SelectableChannel getChannel()
{
synchronized( sync ) {
return sch;
}
}
public void connect()
throws IOException
{
synchronized( sync ) {
if( (sch != null) && !sch.isOpen() ) {
if( !revivable ) throw new IOException( NetUtil.getResourceString( "errCannotRevive" ));
sch = null;
}
if( sch == null ) {
final SocketChannel newCh = SocketChannel.open();
newCh.socket().bind( localAddress );
sch = newCh;
}
if( !sch.isConnected() ) {
sch.connect( target );
}
}
}
// protected void disconnect()
// throws IOException
// {
//
// }
public boolean isConnected()
{
synchronized( sync ) {
return( (sch != null) && sch.isConnected() );
}
}
public void dispose()
{
super.dispose();
if( sch != null ) {
try {
//System.err.println( "TCPOSCTransmitter.closeChannel()" );
//new IOException( "TCPOSCTransmitter.closeChannel()" ).printStackTrace();
sch.close();
//System.err.println( "... ok " );
}
catch( IOException e1 ) {
e1.printStackTrace();
}
sch = null;
}
}
public void send( OSCPacketCodec c, OSCPacket p, SocketAddress target )
throws IOException
{
synchronized( sync ) {
if( (target != null) && !target.equals( this.target )) throw new IllegalStateException( NetUtil.getResourceString( "errNotBoundToAddress" ) + target );
send( c, p );
}
}
public void send( OSCPacketCodec c, OSCPacket p )
throws IOException
{
final int len;
try {
synchronized( sync ) {
// if( sch == null ) throw new NotYetConnectedException();
if( sch == null ) throw new IOException( NetUtil.getResourceString( "errChannelNotConnected" ));
checkBuffer();
byteBuf.clear();
byteBuf.position( 4 );
c.encode( p, byteBuf );
len = byteBuf.position() - 4;
byteBuf.flip();
byteBuf.putInt( 0, len );
if( dumpMode != kDumpOff ) {
printStream.print( "s: " );
if( (dumpMode & kDumpText) != 0 ) OSCPacket.printTextOn( printStream, p );
if( (dumpMode & kDumpHex) != 0 ) {
OSCPacket.printHexOn( printStream, byteBuf );
byteBuf.flip();
}
}
sch.write( byteBuf );
}
}
catch( BufferOverflowException e1 ) {
throw new OSCException( OSCException.BUFFER,
p instanceof OSCMessage ? ((OSCMessage) p).getName() : p.getClass().getName() );
}
}
}
}