libWhisperCore Documentation

by Frederic Trouche.

$Id: libWhisperCore.sgml,v 1.4 2001/04/18 20:32:16 xfred Exp $


This document is a programmer's guide to the libWhisperCore library, an application level library supporting various kind of data stream to be handled asynchronously and remotely.

1. Introduction

Basicaly, purpose of this library is to provide suffiscient mechanisms to handle independant data streams of different kind in asynchronous interactive processes (called data handlers) over a network.

This implies :

This library has been set up to use with the libWhisper library.

2. Multithreaded processes

2.1 Simple threads

The nrtThread class defines a process (method) that be threaded. This is an abstract class since the threaded method, execute(void *), is purely virtual.

When this class is derived, it is expected that either create(void *) or createDetached(void *) is called explicitly (e.g. in the constructor). create makes a joinable thread, and createDetached a detached one.

In both cases, the th protected variable holds the last created thread identifier.

nrtThread holds a internal synchronisation variable that can, directly or not, used through the kill(nrtThread *) (current thread activates de conditional variable of the given thread) and wait(pthread_cond_t *_cond = 0) (current thread is waiting for the activation of a synchronisation variable, its own by default) methods.

2.2 ``Cyclic'' threads

nrtCyclicThread (inherited from nrtThread) has a special behaviour; it calls the virtual handle(void) method periodicaly. Use setSecs(int) or Secs(void) to access period.

The internal EOT parameter has to be set to 1 whenever the thread has to be killed.

3. Synchronisation tools

3.1 Mutexes

Simple mutexes

Classical mutex is provided by the rtMutex class. It got essentialy two accesors : P(void) (pick the ``token'') and R(void) (release it).

Recursive mutexes

rtRecursiveMutex (that inherits from rtMutex class) allows a predefined number of ``token'' to be picked at a time. Number is an optional argument to class's constructor (default is 16).

3.2 Shared data

A shared data can be written by one writer, at a time, or readen by many readers. Basic operations are provided by begWrite(void)/endWrite(void) and begRead(void) /endRead(void) methods.

Readers(void) method give the reader's number, and DirectReaders(void) does the same thing without implicitly assuming any other concurent access (this can be useful precautions have been taken by programmer). Anyway, those methods are situated at a very low level, and you probably won't care.

Shared integer

rtSharedInt holds a single shared integer that can be read using Value(void) or DirectValue(void) methods, and sets by set(int _value) or prefixed ++ and -- operators.

3.3 Parameters

A paramater (rtParameter class) has following protected char* members:

Accessors have same name, with an upcased first character.

Integer parameter

rtIntegerParameter is derived from rtParameter and rtSharedInt and can be cloned using the rtIntegerParameter *clone(void) method.

It appears that a intermediate class could introduce a more flexible implementation.

Parameters

rtParameters defines a fixed number of pointers to some parameters. You'll probably need the AddInt(...), GetInt(int _index), and GetInt(char *_name) methods to handle parameters.

4. Networking

4.1 Interface to socket

rtSocket defines a standard socket and provides tree important methods : void send(char *buffer, int _length);, void recv(char **buffer, int _length); and void recv(char *buffer, int _length);.

It is used as the base of following classes; they all use the TCP network protocol.

4.2 Client

rtSocketClient is used to connect to an rtSocketServer IPC server. Connection is made using the void connect(char *_addr, int _port); method.

Remember that this class inherits rtSocket.

4.3 Server

rtSocketServer can be used as IPC minimal server. It adds to the basical rtSocket methods the protected and purely virtual void handleClient(rtSocket *_socket) method.

4.4 TCP DataHandler Server

rtStreamWriterSocket waits for clients, encodes incoming data stream, and sends it to all connected clients, via different sockets.

For now, four clients can be connected simultaneously.

void handleSound(rtDataStreamBlock *block) has probably to be adapted to particular uses.

4.5 TCP DataHandler Client

rtStreamReaderSocket constructor allows connecting to any instance of type rtStreamWriterSocket, then incoming data are handled in rtDataHandler's `handle' familly methods (for instance void handleSound(rtDataStreamBlock *block)).

4.6 Session management

5. Data and handlers

WHISPER has a specific way to handle data. That means that both computing processes and data are some pre-defined WHISPER's objects.

A data handler (that processes data) has incoming and outgoing data streams that consists of data blocks. Futhermore, each data handler is hold by a chain (whisperChain); introducing therefore another level of flexibility.

Whenever a incoming block arrives, handler (which is a thread) is signaled, and increments its waitingBlocks shared variable. Then, each block is readen through the incoming data stream's readNext(...) method and forwarded to one of the handle... methods.

5.1 Data blocks

A data block is a typed array of characters with arbitrary length. Since each data block can be read asynchronously by data handlers (inherited from a nrtThread), it has to be aware of the number of future reading that are left.

When a block isn't useable anymore by any of its reading handlers, it is automaticaly deleted from the stream its belong to.

5.2 Data streams

In WHISPER, a data stream consists of ordered independant data stream blocks. Few methods are available to handle streams : chain(int _type, char *_buffer, int _length) and *chain(rtDataStreamBlock *) allows programmer to chain a new block into the stream.

readNext(rtDataStreamBlock *) returns the block following the given block. But it hasn't to be called directly by programmer.

Some other facilities are providen to compute stream rate and such things.

5.3 Chains

A chain can hold many dependant data handlers. It has a name, and some convenience methods to report messages or errors.

Since whisperChain class inherits nrtCyclicThread, it executes a virtual handle(void) method periodicaly. By default, this method does nothing.

6. Application

In brief, a WHISPER application (whisperApplication) is a nrtCyclicThread that can manage some WHISPER chains.

Most important providen methods are probably addChain(char *_name), setCurrentToLast(void) and the message handling methods.

6.1 Basics

First of all, the application must instanciate a chain, using addChain(char *_name) and declare it as default chain (setCurrentToLast(void).

Thus, the addHandler(rtDataHandler *) can be called and any new handler'll go in the default chain.