README FOR SIMPLE OSC CLIENT/SERVER (SOCS) INTERFACE ======================================================= version 0.3 Contact: osc@davidreeder.info Table of Contents-- GOALS OF SOCS INTRODUCTION QUICK SETUP FOR MAX SOCS PROTOCOL ADDRESS TUPLES SYSTEM REQUIREMENTS MAX CLIENT SETUP Enabling SOCS Objects Defining Commands Operational Guidance SERVER CONFIG FILE CONCRETE EXAMPLE OF MESSAGE EXCHANGE #----------------------------------------- -o- GOALS OF SOCS The primary goals of SOCS are to: . Allow groups to focus on logical messaging, ignorning details of OSC; it facilitates social connectivity at the UDP layer . Provide an optional single point of message distribution, limiting the organizational explosion of interconnections to a star network vs. a many-to-many mesh . Provide the optional feature of message expansion, allowing clients to represent complex sets of messages as single messages, further simplifying the interface for endusers or bystanderswith little or no knowledge about the system . Structure the OSC namespace so multiple groups can share the same bandwith without risk of signalling between networks. These goals intend to simplify OSC network communications for bystanders (such as gallery visitors) and most active endusers, while adding minimal complexity to the setup for clients which already have well developed interfaces. #----------------------------------------- -o- INTRODUCTION SOCS defines a simple protocol standard for routing OSC messages between clients and defines a server interface that routes and expands OSC messages on behalf of clients. Clients may talk with one another directly or via the server. The primary role of the server is to amplify client communications, but it could be customized to perform any function based on timers or driven by messaging activity. SOCS does not represent a new protocol, but rather builds a simple standard on top of Open Sound Control (OSC). SOCS also represents a growing set of ready-made programs interfaces (such as Max) that provide tools for defining client endpoints. These interfaces may be copied and configured, or the protocol may be engaged directly via any OSC implementation. OSC messages to clients are called commands. OSC messages to the server are called requests. Clients may function as senders and/or receivers and may have more than one address. A SOCS network consists of two or more clients optionally in combination with a single server. Multiple networks may coexist, though each must operate in a separate domain where each exising server must operate in a unique domain with a dedicated config file. The current list of ready-made interfaces includes a Max mxj object that provides a single configurable point defining the address of a node and its relationship as a sender or receiver to other nodes in the network. Programs for SuperCollider are available upon request. Forthcoming interfaces are projected for Chuck and Pd. The SOCS server expands requests into a set of commands issued to one or more channels at one or more clients. Strings are the standard linking client command input to server command output. Commands and their arguments are expressed and sent as strings separated by spaces, even when they logically represent other data types such as integers or floats. The server will output whatever is defined in the config file with the expectation that the client designer has only placed commands into the config file recognized by the targetted client. Request and command messages may arbitrarilly generated by clients and sent to the server or other clients. #----------------------------------------- -o- QUICK SETUP FOR MAX 1 Incorporate elements from osc-example.maxpat. 2 Decide which COMMANDS to receive. Capture them in the route object egress from OSCReceive. 3 Construct a REQUEST interface for others clients. Register this by entering it in the server config (AESL) file. 3 Decide which REQUESTS to send to others. Send them via OSCSend to the server; or send COMMANDs directly to the target client if you know their parameters. #----------------------------------------- -o- SOCS PROTOCOL OSC messages consist of a pathname followed by zero or more data items. [ ... ] SOCS provides a standard definition to and implements these details in client and server code. The goal of which is to simplify OSC by reducing setup to the configuration of an address tuple and local message signatures, and to reduce usage to a set of well-defined messages and parameters. SOCS distinguishes between clients and servers that exist in a named OSC domain. Messages on the wire take the following form: message to server (requests): /domain/S/ [] message to client (commands): /domain/C// [] Messages to the server are called requests; messages to a client are called a commands. In order to extend the OSC path to a longer list of slash ("/") separated tokens, simply write slashes into the or tokens in the above message schema. Eg, to send "/domain/S/touchosc/1/fader" to the server, define as "touchosc/1/fader". In the case of the SOCS Max objects, OSCSend and OSCReceive define the address, port and domain of the client or server, and messages are used to complete the message by defining the + or ++. Clients may optionally register their clientIDs with the server, or they may send commands directly to one another. To communicate with a client via the server, one sends a request to the server which is transformed into one or more commands to the client named by that request message. Each client is at liberty to define its own namespace of commands. Each client may also define requests in the server config file which, in turn, represent or bundle commands interpreted by the client. The server converts requests to sequences of commands, as registered by the client. In this manner requests provide an opportunity to further simplify the interface to a given client. #----------------------------------------- -o- ADDRESS TUPLES The server can exist on any IP in the network, but it must be assigned an well-known port. (Default: 10500) Clients may also exist on any IP in the network, but each must have a unique clientID and port number, where the port number is unique in the namespace of the machine upon which the client is implemented. A given machine, or program on a given machine, may host multiple clients. Both clients and servers must define the same SOCS domain in order to see messages sent between them. For example, the Max objects define the address tuples as follows: OSCReceive OSCSend OSCSend server Using OSCSend to send to "server" indicates the outgoing message should be formatted as a server request and sent to the server. Otherwise it is formatted as a client command and sent to the named clientID. #----------------------------------------- -o- SYSTEM REQUIREMENTS The Max client and server code leverage the Java programming language and were written under Java version "1.6.0_26". Specifically: Java(TM) SE Runtime Environment (build 1.6.0_26-b03-384-10M3425) Java HotSpot(TM) Client VM (build 20.1-b02-384, mixed mode) However, the Java is likely to run on older versions of the Java runtime environment. (TBD -- More specific details regarding compatibility will be documented going forward.) #----------------------------------------- -o- MAX CLIENT SETUP == Enabling SOCS Objects The Max objects rely on Java via the mxj object. This requires that the Java classes are in the same directory as the Max patch, or in any child subdirectory. For quick setup: Place the "java" directory at the same level (or lower) as any patch using mxj objects in "osc-example.maxpat." Be sure there is only one copy of the java directory in the entire patch directory. In this distribution the Java classes live under java/class. java/lib contains the versions of max.jar (copied from /Applications/Max5/Cycling'74/java/lib) and NetUtil.jar (acquired from http://sciss.de/netutil). These are provided to allow the OSCSend and OSCReceive classes to be easily rebuilt if they are changed. == Defining Commands The designer of the client is at liberty to define the set of commands recognized by the client. Each command may take any number of arguments in any format. The limit of the complexity of the set of commands and arguments is bounded only by the programming skill of the designer. As documented above (SOCS PROTOCOL), incoming OSC messages have the following format: /domain/C// [] The OSCReceive object drops improperly formatted messages and returns only the meaningful suffix of this message, namely: [] The route object following OSCReceive is intended to separate messages according to their channel targets, though this step may be skipped. This leaves a set of optional arguments which stand as parameters to the final step of message processing. Parameters may control anything imaginable, including the generation of sounds, images or additional messages. If is made of a set of tokens separated by slashes ("/"), OSCReceive drops the slashes and replaces them with spaces. Arguments, on the other hand, are delivered without edits. == Operational Guidance Keep posted to the Max window as the objects report errs and confirmation intended to simplify configuration and use. These messages may be bypassed by setting "verbose = 0" in the Java code then rebuilding the classes. OSCReceive must be told to relinquish its assigned port once its running else it will generate error messages that may persist until Max is restarted. In particular, always "close" OSCReceive before editing its address tuple. It will automatically "open" itself with the new set of object arguments. OSCSend, on the other hand, is stateless and may be changed at any time without risk of jamming up ports. The "osc-example.maxpat" provides one example of OSCReceive and two examples of OSCSend. OSCReceive captures commands directed to the client on the given machine at the port, clientID and domain named in the object definition. Note that OSCReceive returns the IP address of its host machine -- this must match the IP address used by any OSCSend wishing to communicate directly with the client via SOCS commands. OSCSend sends reqeusts or commands depending upon how it is configured. If defined with a target of "server", OSCSend delivers requests to the server at the given host and port number on the given domain. Otherwise OSCSend delivers commands directly to the client defined by an address tuple in the same format. Requests and commands may be sent to clients or the server whether they are co-located on the same host or on some other host in the OSC domain. #----------------------------------------- -o- SERVER CONFIG FILE An example server config file is provided in example-server-config.aesl. Comments within the file describe its use, and coordinate with the naming scheme used in osc-example.maxpat. The format of this file is intended to be reasonable intuitive; also, the server is chatty and unforgiving with mistakes of syntax. Thus, it should be possible to setup new configs by copying examples and attending to the error responses from the server. To see a complete specification of the SOCS server syntax, please consider the file named README-aesl.txt. All clients within a given SOCS domain share the same config file which is read by a single shared server. Invoke the server with the following UNIX command: % aeserver Use the following command to obtain the IP address of the server: % aeserver -i Most of the directives in the AESL file may remain static. The only directives that must be configured for SOCS are oscdomain, client and globalrequests. The "oscdomain" directive defines the SOCS domain of the network. All clients who wish to share a given network must set their domain to agree with each other and with the server. "client" directives are used to associate client IP address and port numbers with clientIDs. Use one client directive per client in the network. "globalrequests" contains a list of requests directives. Request directives are the means by which SOCS server associates incoming client requests with a set of outgoing commands. Each request directive may contain one or more command directives, where each command is associated with a single client and one or more channels at that client. The basic format of a request directive is as follows: pingA { clientOne:main { ping; }; }; where "pingA" is the public name of the request, "clientOne:main" identifies the command target as channel "main" at clientID "clientOne" and where "ping" is the outgoing command. "main" may be replaced with a comma separated list of channels. Channel names are defined by the client. "ping;" may be replaced with a list of commands ending with semicolons. In addition, the combination of ": { ; };" may be repeated any number of times for any number of clientIDs, channels and command sets. If the client wants an extended OSC path, the channel can be extended to a series of tokens separated by slashes ("/"). Eg, "clientOne:long/osc/path". If a given command takes arguments, those can be exposed at the head of the request directive: noise { clientTwo:audio { oscillator noise ; }; }; Requests with the wrong number of arguments will be dropped by the server. However, this is the only check performed by the server. Arguments are simply placeholders and may represent any data type. The server does not test whether arguments make sense in the context of the commands that use them, nor does the server comprehend the meaning of commands. Instead, the server simply copies arguments into place and sends one copy of the resulting command to each designated client, once per each designated channel. The format of the command directive is defined by the designer of the client. The command directive should be derived from the set of available strings parsed and operated upon by the client. Other details of the syntax may be found in README-aesl.txt. For example, there are two reserved request directives -- "begin" and "end" -- which are automatically executed whenever the server starts and stops, respectively. All additional AESL features like this are optional. They are not required for basic operation. #----------------------------------------- -o- CONCRETE EXAMPLE OF MESSAGE EXCHANGE Follows is a simple example. A truly expressive network is likely to generate more messages with greater complexity or more varied combinations. Assume the following network of three entities that we care about, two clients and a server, as well as some other clients that we know exist but that we don't talk to directly, perhaps because they are ephermeral. +----+ -->>------->> +----+ | C1 | | C2 | +----+ <<---\ /--->> +----+ \ | \ | \ +---+ -->> | S | -->>----->> (other clients) +---+ Here we see that client #1 (C1) sends commands to client #2 (C2) and requests to the server (S). S sends commands to C1 and C2. C2 doesn't send anything, but receives commands from both C1 and S. We assume that all three targets are on three individual machines with three individual IP addresses. Using the Max mxj objects as examples, C1 and C2 will be instrumented with the following objects: C1 :: OSCSend serverhost 10500 server testdomain OSCSend c2host 10502 c2 testdomain OSCReceive c1host 10501 c1 testdomain C2 :: OSCReceive c2host 10502 c2 testdomain For this example, the server is given the following config file: serverport 10500; oscdomain testdomain; setscene everything; scene everything { }; start; client c1 c1host 10501; client c2 c2host 10502; client c3 c3host 10503; globalrequests { pingC1 { c1:chan1 { ping; }; }; pokeC2 { c2:chan2,chan3 { poke; }; }; ringyding { c2:chan3 { bellsound ; }; c3:strangedevice { hornsound ; wheel spin; }; }; }; This network, instrumentations and config file enable the following possibilities -- C1 can send three requests to the server. It is unlikely to send pingC1 as this request instructs the S to send the "ping" command back to itself. But other clients in the network might use it to signal C1 on channel #1. C1 can also send a "poke" command to C2 simultaneously on channels #2 and #3. Finally, C1 can send the "ringyding " request which also sends multiple commands, to C2 and C3 on the given channels where each receives a different command(s), though both the same argument is used at both clients. C3 is also instrumented to respond to the command "wheel" with argument "spin" (here hardwired into the config file) which might do anything from creating a sound to spinning a bicycle wheel with a robotic arm. C2 doesn't send messages, but it can receive messages from anyone. If C1 happens to know it takes the "ping" command, it could send that directly instead of sending a request via the server. C3 could do the same thing if it is instrumented with send capability. The server doesn't send any messages unless prompted, but any node in the network with send capabilities and knowledge of the public interface implemented by the server could send commands to C1, C2 or C3 in the same manner as C1.