Files
veejay/veejay-current/veejay-server/libOSC/OSC-receive.h
Niels Elburg d8e6f98d53 Initial checkin of veejay 1.4
git-svn-id: svn://code.dyne.org/veejay/trunk@1172 eb8d1916-c9e9-0310-b8de-cf0c9472ead5
2008-11-10 20:16:24 +00:00

243 lines
9.7 KiB
C

/*
Copyright © 1998. The Regents of the University of California (Regents).
All Rights Reserved.
Written by Matt Wright, The Center for New Music and Audio Technologies,
University of California, Berkeley.
Permission to use, copy, modify, distribute, and distribute modified versions
of this software and its documentation without fee and without a signed
licensing agreement, is hereby granted, provided that the above copyright
notice, this paragraph and the following two paragraphs appear in all copies,
modifications, and distributions.
IN NO EVENT SHALL REGENTS BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT,
SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING LOST PROFITS, ARISING
OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF REGENTS HAS
BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
REGENTS SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE. THE SOFTWARE AND ACCOMPANYING DOCUMENTATION, IF ANY, PROVIDED
HEREUNDER IS PROVIDED "AS IS". REGENTS HAS NO OBLIGATION TO PROVIDE
MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
The OpenSound Control WWW page is
http://www.cnmat.berkeley.edu/OpenSoundControl
*/
/*
OSC-receive.h
Matt Wright, 11/18/97
include OSC-timetag.h and NetworkReturnAddress.h before this file.
*/
/**************************************************
Initialization and memory pre-allocation
**************************************************/
/* The memory model used by this module is pre-allocation of fixed-size
objects for network buffers and other internal objects. This preallocated
memory is dynamically managed internally by a custom high-performance memory
allocator. When the preallocated memory runs out, this module calls an
optional realtime memory allocator that you provide. If your memory
allocator gives this module more memory, it will add it to the pool of
objects and never free the memory. If your system does not have a realtime
memory allocator, provide a procedure that always returns 0.
You will fill an OSCReceiveMemoryTuner struct with the parameters that
determine how memory will be allocated.
The MemoryAllocator fields are procedures you will provide that allocate
memory. Like malloc(), they take the number of bytes as arguments and return
either a pointer to the new memory or 0 for failure. This memory will never
be freed.
- The InitTimeMemoryAllocator will be called only at initialization time,
i.e., before OSCInitAddressSpace() returns. If it ever returns 0, that's
a fatal error.
- The RealTimeMemoryAllocator will be called if, while the application is
running, the address space grows larger than can fit in what was allocated
at initialization time. If the RealTimeMemoryAllocator() returns 0, the
operation attempting to grow the address space will fail. If your system
does not have real-time memory allocation, RealTimeMemoryAllocator should
be a procedure that always returns 0.
The remaining fields say how much memory to allocate at initialization time:
- receiveBufferSize is the maximum packet size that can be received. Is the
maximum UDP packet size 4096? OSC clients can send a query to this system
asking for this maximum packet size.
- numReceiveBuffers determines how many packets at a time can be sitting
on the scheduler with messages waiting to take effect. If all the
receive buffers are tied up like this, you won't be able to receive
new packets.
- numQueuedObjects is the number of messages and packets that can be sitting
on the scheduler waiting to take effect.
- Because a message pattern may be dispatched before the message takes effect,
we need memory to store the callback pointers corresponding to a message.
numCallbackListNodes is the number of callbacks that may be stored in this
fashion. It must be at least as large as the maximum number of methods that
any one message pattern may match, but if you want to take advantage of
pre-dispatching, this should be large enough to hold all the callbacks for
all the messages waiting in the scheduler.
*/
struct OSCReceiveMemoryTuner {
void *(*InitTimeMemoryAllocator)(int numBytes);
void *(*RealTimeMemoryAllocator)(int numBytes);
int receiveBufferSize;
int numReceiveBuffers;
int numQueuedObjects;
int numCallbackListNodes;
};
/* Given an OSCReceiveMemoryTuner, return the number of bytes of
memory that would be allocated if OSCInitReceive() were called
on it. */
int OSCReceiveMemoryThatWouldBeAllocated(struct OSCReceiveMemoryTuner *t);
/* Returns FALSE if it fails to initialize */
Boolean OSCInitReceive(struct OSCReceiveMemoryTuner *t);
/**************************************************
Managing packet data structures
**************************************************/
/* You don't get to know what's in an OSCPacketBuffer. */
typedef struct OSCPacketBuffer_struct *OSCPacketBuffer;
/* Get an unused packet. Returns 0 if none are free. If you get a packet
with this procedure, it is your responsibility either to call
OSCAcceptPacket() on it (in which case the internals of the OSC Kit free
the OSCPacketBuffer after the last message in it takes effect) or to call
OSCFreePacket() on it. */
OSCPacketBuffer OSCAllocPacketBuffer(void);
/* Free. This is called automatically after the last message that was
in the packet is invoked. You shouldn't need to call this unless
you get a packet with OSCAllocPacketBuffer() and then for some reason
decide not to call OSCAcceptPacket() on it. */
void OSCFreePacket(OSCPacketBuffer p);
void OSCFreeReceiver(void);
/* Whatever code actually gets packets from the network should use these
three selectors to access the fields in the packet structure that need
to be filled in with the data from the network. */
/* Selector to get the buffer from a packet. This buffer's size will be
equal to the receiveBufferSize you passed to OSCInitReceive(). */
char *OSCPacketBufferGetBuffer(OSCPacketBuffer p);
/* Selector to get a pointer to the int that's the size count for the
data currently in a packet. (Not the capacity of the packet's buffer,
but the size of the packet that's actually stored in the buffer.) */
int *OSCPacketBufferGetSize(OSCPacketBuffer);
/* Selector to get the client's network address from a packet. This buffer's
size will be equal to the clientAddrSize you passed to OSCInitReceive().
Note that the NetworkReturnAddressPtr type is full of "const"s, so your
code that fills in the return address will probably have to cast the return
value of this procedure to some non-const type to be able to write into it. */
NetworkReturnAddressPtr OSCPacketBufferGetClientAddr(OSCPacketBuffer p);
/* Returns the capacity of packet buffers (the receiveBufferSize you passed
to OSCInitReceive()). */
int OSCGetReceiveBufferSize(void);
/**************************************************
Dealing with OpenSoundControl packets and
making the messages take effect.
**************************************************/
/* Call this as soon as a packet comes in from the network.
It will take care of anything that has to happen immediately,
but put off as much as possible of the work of parsing the
packet. (This tries to be as fast as possible in case a
lot of packets come in.) */
void OSCAcceptPacket(OSCPacketBuffer packet);
/* Call this during an otherwise idle time. It goes through
everything that's sitting in the OSC scheduler waiting to
happen and does some of the work of parsing, pattern
matching, dispatching, etc., that will have to be done
at some point before the scheduled messages can take
effect.
The return value indicates whether there is more work of
this sort that could be done. (Each time you call this,
it does only a small unit of this kind of work. If it
returns TRUE and you still have time before the next thing
you have to do, call it again.) */
Boolean OSCBeProductiveWhileWaiting(void);
/* Call this whenever enough time has passed that you want to see which
messages are now ready and have them take effect. (For example, in a
synthesizer, you might call this once per synthesis frame, just before
synthesizing the audio for that frame.)
This procedure finds the earliest time tag of all the queued messages
and invokes *all* of the queued messages with that time tag. (OSC
guarantees that messages with the same tag take effect atomically.)
If there are more messages that are ready, but with a different time
tag, this procedure does not invoke them, but returns TRUE to indicate
that more messages are ready.
*/
Boolean OSCInvokeMessagesThatAreReady(OSCTimeTag now);
/* Same thing, but invokes all of the messages whose time has come. */
void OSCInvokeAllMessagesThatAreReady(OSCTimeTag now);
Boolean NetworkReceivePacket(OSCPacketBuffer packet);
Boolean NetworkStartUDPServer(OSCPacketBuffer packet, int port_id);
Boolean NetworkPacketWaiting(OSCPacketBuffer packet);
void GoMultiCast(const char *groupname);
int IsMultiCast( char *dst);
/**************************************************
How to use this stuff
**************************************************/
/* Here's a gross approximation of how your application will invoke the
procedures in this module:
while (1) {
OSCTimeTag now = CurrentTime();
do {
if (WeAreSoLateThatWeNeedToDelayOSCMessagesToAvoidACrisis()) break;
} while (OSCInvokeMessagesThatAreReady(now) == TRUE);
SynthesizeSomeSound();
if (NetworkPacketWaiting()) {
OSCPacketBuffer p = OSCAllocPacketBuffer();
if (!p) {
Bummer();
} else {
NetworkReceivePacket(p);
OSCAcceptPacket(p);
}
}
while (TimeLeftBeforeWeHaveDoSomething()) {
if (!OSCBeProductiveWhileWaiting()) break;
}
}
*/