/*
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.

*/
#ifndef IS_MINGW
#include <netinet/in.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <sys/ioctl.h>
#include <arpa/inet.h>
#endif

#include <sys/types.h>

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); 

/**************************************************
   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;
    }
}

*/

